串口自环测试失败原因定位

INT32 serial_test()
{
    INT32 fd;
    INT32 i;
    char rbuf[1];
    char wrbuf[1];
    INT32 count = 0;
    INT32 cnt = 0;
    rbuf[0] = 0;
    int ret;
 //VCS_Ctrl_LedConf(SC1_LED,RED,FAST_BLINK);  //SC4红灯灭
// printf("serial_test::11111\n");
 
    printflag = 1;
    fd = open( "/dev/ttyS0", O_RDWR| O_NOCTTY  | O_NONBLOCK);
    if (fd < 0)
    {
        DPRINTF(PRINT_FLAG_ERR,"can't open ttyS0\n");
        close(fd);
    }
    else
     {
        DPRINTF(PRINT_FLAG_ERR,"open OK...\n");
    }
// printf("serial_test::22222\n");  
 tcflush(fd,TCIOFLUSH);
 for(i=0;i<10000;i++)
 {
    rbuf[0] = 0;
    read(fd,rbuf,1);
 }
//printf("serial_test::3333\n");
// VCS_Ctrl_LedConf(SC3_LED,RED,FAST_BLINK);  //SC4红灯灭
 if(0 == tty_raw(fd))
 DPRINTF(PRINT_FLAG_ERR,"tty raw set OK \n");
// VCS_Ctrl_LedConf(SC3_LED,GREEN,FAST_BLINK);  //SC4红灯灭
 
 #if 0   
 {
       
   INT32 timeOut = 0;
        /* hope to read 10 byte from serial com0*/
        while(1)
        {
            ret = read(fd, rbuf, 1000);
            if(ret <= 0)
            {
                timeOut ++;
                if (timeOut > 10)
                    break;
            }
        }
    }
 #endif
    while(1)
    {
        tcflush(fd,TCIOFLUSH);
       
        wrbuf[0] = 'u';
        rbuf[0] = 0;

ret=write(fd,wrbuf,1);
        if(ret== -1)
        {
            printf("write error!\n");
            perror("wirte failed");
        }
        if(ret==1)
            printf("write success!");
        usleep(1000);  //lixia add 2010-06-13
        
        ret = 0;
    cnt = 0;
        while(ret != 1)

{
            cnt++;
            ret=read(fd,rbuf,1);
            if(ret== -1)
            {
                 printf("read error! 0x%x\n",errno); 这里发现经常读错误,而且返回的errno为0xb,
                 perror("read failed");
            }
            if(ret==1)
                printf("read success! cnt=%d\n",cnt);
             usleep(1000);
            if(cnt>2000)
                break;
  }


        printf("w:%c %d r:%c %d \n",wrbuf[0],wrbuf[0],rbuf[0],rbuf[0]);
        if(wrbuf[0] == rbuf[0])
        {
            Beep_Warning_On();
            sleep(1);
            Beep_Warning_Off();
            sleep(1);
           if (0 == tty_reset(fd))
                DPRINTF(PRINT_FLAG_ERR,"tty set RESET ok\n");
          // sleep(2);
            close(fd);
            printflag = 0;
          //   VCS_Ctrl_LedConf(SC1_LED,GREEN,FAST_BLINK);  //SC4红灯灭
            return 0;
        }
        else
        {
           count ++;
           if(count > 1000)
           {
              if (0 == tty_reset(fd))
              {
                  DPRINTF(PRINT_FLAG_ERR,"tty set RESET ok\n");
              }
                close(fd);
                printflag = 0;
                 VCS_Ctrl_LedConf(SC1_LED,GREEN,FAST_BLINK);  //SC4红灯灭
                return -1;
           }
        }
    }    
}

发现“标红的read函数”经常会读错误,而且返回的errno为0xb,

0xb对应EAGAIN。

因为open函数使用的是O_NONBLOCK,非阻塞,所以定位到原因,因为是非阻塞模式,所以如果没有数据时read会直接返回失败,导致写入不等于读取的数据,如果超过1000次,就判断串口自环测试失败。优化后的代码见上图compare。

知识点:一定要判断函数的返回值!!!

--------------------------------------------------------------------------------------------------------------------------------------

非阻塞(O_NONBLOCK)

非阻塞I/O使我们的操作要么成功,要么立即返回错误,不被阻塞。
对于一个给定的描述符两种方法对其指定非阻塞I/O:
(1)调用open获得描述符,并指定O_NONBLOCK标志
(2)对已经打开的文件描述符,调用fcntl,打开O_NONBLOCK文件状态标志。

flags = fcntl( s, F_GETFL, 0 ) )
fcntl( s, F_SETFL, flags | O_NONBLOCK )

--------------------------------------------------------------------------------------------------------------------------------------

Linux:非阻塞O_NONBLOCK与O_NDELAY的区别

O_NONBLOCK和O_NDELAY所产生的结果都是使I/O变成非阻塞模式(non-blocking),在读取不到数据或是写入缓冲区已满会马上return,而不会阻塞等待。

它们的差别在于:在读操作时,如果读不到数据,O_NDELAY会使I/O函数马上返回0,但这又衍生出一个问题,因为读取到文件末尾(EOF)时返回的也是0,这样无法区分是哪种情况。因此,O_NONBLOCK就产生出来,它在读取不到数据时会回传-1,并且设置errno为EAGAIN

O_NDELAY是在System V的早期版本中引入的,在编码时,还是推荐POSIX规定的O_NONBLOCK,O_NONBLOCK可以在openfcntl时设置。

--------------------------------------------------------------------------------------------------------------------------------------

Linux 设备驱动--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志

阻塞:

在设计简单字符驱动程序时,要注意一个重要问题.

 当一个设备无法立刻满足用户的读写请求时应当如何处理?

例如:调用 read 时没有数据可读,但以后可能会有;

或者一个进程试图向设备写入数据,但是设备暂时没有准备好接收数据.

应用程序通常不关心这种问题,应用程序只是调用 read 或 write 并得到返回值.

驱动程序应当 ( 缺省地 ) 阻塞进程使它进入睡眠直到请求可以得到满足.

阻塞操作:

是指在执行设备操作时,若不能获得资源挂起进程,直到满足可操作的条件后进行操作,

被挂起的进程进入睡眠状态,被从调度器的运行队列移走,直到等待的条件被满足.

非阻塞操作:

进程不能进行设备操作时并不挂起,他或者放弃,或者不停的查询,直到可以进行操作为止.

阻塞方式-read- 实现:

在阻塞型驱动程序中,read 实现方式如下:

如果进程调用 read ,但设备 没有数据 或 数据不足,进程阻塞.

新数据到达后唤醒被阻塞进程.

阻塞方式-write- 实现:

在阻塞型驱动程序中,write 实现方式如下:

如果进程调用了 write ,但设备 没有足够的空间供其写入数据, 进程阻塞.

当设备中的数据被读走后,缓冲区中 空出部分空间,则 唤醒进程.

非阻塞方式的读写操作:

阻塞方式是文件读写操作的 默认方式,但是应用程序员可通过使用 O_NONBLOCK 标志来人为

设置读写操作为 非阻塞方式 .( 该标志定义在 < linux/fcntl.h > 中,在打开文件时指定 ) .

如果 设置了 O_NONBLOCK 标志,read 和 write 的行为是不同的 ,如果进程没有数据就绪时调用了 read ,

或者在缓冲区没有空间时调用了 write ,系统只是 简单的返回 -EAGAIN,而 不会阻塞进程.

实例 --- 读阻塞的实现:

用 while 是因为可能别的信号唤醒了睡眠,我们要通过while 重新检测是否真有数据了....

实例 --- 按键驱动阻塞实现:

1,在 open 函数 查看看是 阻塞方式 还是 非阻塞方式:

file 结构体中含有 f_flags 标志位,看是 阻塞方式 还是 非阻塞方式:

O_NONBLOCK 为 非阻塞方式

 if (file->f_flags & O_NONBLOCK)  /* 非 阻塞操作 */{if (down_trylock(&button_lock))   /* 无法获取信号量,down_trylock 立马返回 一个 非零值 */return -EBUSY;}else                             /* 阻塞操作 */{/* 获取信号量 */down(&button_lock);   /* 获取不到  睡眠 */}

2,在 read 函数中同样查看:

 if (file->f_flags & O_NONBLOCK)       /* 非 阻塞操作 */{if (!ev_press)                 /* ev_press 为 1 表示有按键按下,为 0 if 成立 ,没有按键按下, */return -EAGAIN;        /* 返回 -EAGAIN 让再次来执行 */}else                                   /* 阻塞操作 */{/* 如果没有按键动作, 休眠 */wait_event_interruptible(button_waitq, ev_press);}
<table><tr><td bgcolor=#7FFFD4>这里的背景色是:Aquamarine,  十六进制颜色值:#7FFFD4, rgb(127, 255, 212)</td></tr></table>

3,应用程序中:

1,以阻塞方式运行:

后台执行应用程序,进程处于睡眠状态,按下按键,立马打印按键号;

int main(int argc, char **argv)
{unsigned char key_val;int Oflags;fd = open("/dev/buttons", O_RDWR );if (fd < 0){printf("can't open!\n");return -1;}while (1){read(fd, &key_val, 1);printf("key_val: 0x%x\n", key_val);}return 0;
}

2,以非阻塞方式运行:

open 驱动程序的时候,传入标志 O_NONBLOCK 非阻塞;

后台执行应用程序:

int main(int argc, char **argv)
{unsigned char key_val;int ret;int Oflags;fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);if (fd < 0){printf("can't open!\n");return -1;}while (1){ret = read(fd, &key_val, 1);printf("key_val: 0x%x, ret = %d\n", key_val, ret);sleep(5);}return 0;
}

非阻塞方式,没有按键值按下,程序立马返回;
read 返回值 为 -1;

https://blog.csdn.net/yikai2009/article/details/8653697#t7

阻塞和非阻塞(串口自环测试失败原因定位)相关推荐

  1. Linux 使用fcntl c_cc[VMIN] c_cc[CTIME]设置串口阻塞与非阻塞读取数据

    一.概述 Linux串口非常灵活,可以根据需要配置成标准串口和自定义串口模式,就Linux 串口读取数据来说,有有两种主要方式:阻塞与非阻塞. 阻塞:一直等待数据,直到退出条件成立: 非阻塞:及时返回 ...

  2. ESP3 + ESP-IDF | 串口1 - 简单的串口回环测试

    文章目录 一.前言 二.VSCODE + ESP-IDF 2.1.快速创建项目 2.2.选择串口通道,ESP芯片型号 三.代码 3.1.头文件 3.2.全局变量 3.3.app_main( )函数 3 ...

  3. 阻塞、非阻塞、多路复用、同步、异步、BIO、NIO、AIO 一锅端

    承接上文的操作系统,关于IO会涉及到阻塞.非阻塞.多路复用.同步.异步.BIO.NIO.AIO等几个知识点.知识点虽然不难但平常经常容易搞混,特此Mark下,与君共勉. 1 阻塞跟非阻塞 1.1 阻塞 ...

  4. IO:同步,异步,阻塞,非阻塞

    IO - 同步,异步,阻塞,非阻塞 都是老生常谈的东西,多通读几遍,理解透彻! 实际上同步与异步是针对应用程序与内核的交互而言的.同步过程中进程触发IO操作并等待(也就是我们说的阻塞)或者轮询的去查看 ...

  5. 同步通信与异步通信以及阻塞和非阻塞之我见 [原]

    一.硬件层次上的同步与异步 1.异步通信    在异步通信中,CPU与外设之间有两项约定:    (1)字符格式---字符的编码形式及规定,每个串行字符由以下四个部分组成:       ⑴ 1个起始位 ...

  6. 设备的阻塞与非阻塞操作

    阻塞操作是指,在执行设备操作时,若不能获得资源,则进程挂起直到满足可操作的条件再进行操作.非阻塞操作的进程在不能进行设备操作时,并不挂起.被挂起的进程进入sleep状态,被从调度器的运行队列移走,直到 ...

  7. Socket阻塞与非阻塞,同步与异步、I/O模型

    [原文链接] 1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步:       所谓同步,就是在发出一 ...

  8. recv send 阻塞和非阻塞

    int send( SOCKET s, const char FAR *buf, int len, int flags ); 不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据 ...

  9. Linux 阻塞和非阻塞IO 实验

    目录 阻塞和非阻塞IO 阻塞和非阻塞简介 等待队列 轮询 Linux 驱动下的poll 操作函数 阻塞IO 实验 硬件原理图分析 实验程序编写 运行测试 非阻塞IO 实验 硬件原理图分析 实验程序编写 ...

  10. 通俗系列之同步、异步、阻塞和非阻塞

    前言 在日常的开发中,经常出现同步.异步.阻塞和非阻塞等概念.有些人搞不清楚什么代码是同步,什么代码是异步.有些人说我用异步了啊,为什么效率还是没提高呢?也许你是用异步了,但是可能是异步阻塞了.有些人 ...

最新文章

  1. linux /etc/profile和/etc/bashrc
  2. VTK:图片之ImageMathematics
  3. Java黑皮书课后题第2章:*2.23(驾驶费用)编写一个程序,提示用户输入驾驶的距离、每加仑多少英里的汽车燃油性能值,以及每加仑的价格,然后显示旅程的费用
  4. php对外发包引发服务器崩溃的终极解决方法分享
  5. 美国劳工部揭露中国女人大数据,看完彻底傻眼了……
  6. Kotlin入门(4)声明与操作数组
  7. python_统计数组中指定范围的数据占的比例
  8. 读Thinking in Java(1~4)
  9. windows sesrver2003下搭建DHCP服务器
  10. 最简单的pdf加水印方法,五个步骤很详细
  11. ps文件太大无法保存?
  12. Thinkpad X201i笔记本电脑开机Fan Error
  13. 「雕爷学编程」Arduino动手做(13)——触摸开关模块
  14. 互联网创业公司是否需要技术外包?
  15. USB连接默认更改为传输文件
  16. Javascript 判断一个数是否为素数的三种解法
  17. 抗去除花指令(一)——花指令基础
  18. 英文论文画图常用软件
  19. glTF学习笔记(0)——概述
  20. 丁香园开放医疗数据平台,覆盖药、病、诊、科研等7大应用场景

热门文章

  1. 科研不是比赛,而是一种对未知和完美的自我追求——跟邢波(Eric Xing)面对面聊科研...
  2. 运用.net工厂编写数据库类
  3. matlab 纵坐标 科学计数法,echarts纵坐标使用科学计数法表示
  4. Java随机生成_0--2π_使用随机数计算PI
  5. ios 通知接收两次_苹果健康体系又进一步,iOS 14.3支持有氧适能通知
  6. spark使用KryoRegistrator java代码示例
  7. 数商云:B2C商城网站建设功能框架大解析
  8. TOMCAT报错解决
  9. WebSocket+HTML5实现在线聊天室
  10. DigitalOcean发布弹性块存储服务