最近在linux系统中写了个串口通信的程序,主要是PC机和ARM-mini2440开发板的串口进行通信(当然在开发板上也是跑的Linux操作系统),PC和开发板都要进行接收和发送。发送端要发送从0x00~0xFF中的任意字符,(包括不可见字符)但接收端某些字符老接收不到,而接收端是使用的是软中断的方式,也就是使用的信号SIGIO,进行数据的接收,但是在收到SIGIO信号后,总是接收不到数据,分析及其解决方法如下:
一、接收数据时
写数据时,直接调用write函数就可以了,但是在用read读数据时,就会有一定的规则了。解决这些问题之前我们先看终端I/O的两种输入处理模式:
(1) 规范方式输入处理。
在这种方式中,终端输入以行为单位进行处理。对于每个读要求,终端驱动程序最多返回一行。只有遇到NL,EOL,EOL2,和EOF。此类表示一行结束的特殊字符时,才会read到真正的数据,否则即使收到SIGIO信号,当调用read函数进行读串口时,一样读不到数据。就是在这里,自己调试了好长时间,只到设置了 newio.c_lflag
& =~ICANON .这上面的5个行定界符中,其中只有一个EOF字符在终端驱动程序对其处理后即被删除。其他4个字符则作为该行的最后一个字符返回给调用者。
0x0a即'\n',以NL来表示,也就是说类似按了enter键,本行数据才输出,所以必须修改,将终端设置在非规范方式输入处理。
(2) 非规范方式输入处理。输入字符不以行为单位进行装配。
如果不作特殊处理,则默认方式是规范方式。例如:若shell的标准输入、输出是终端,在用read和write将标准输入复制到标准输出时,终端以规范方式进行工作,每次read最多返回一行。处理整个屏幕的程序,例如vi编辑程序使用非规范方式,其原因是其命令是由不以新行符终止的一个或几个字符组成的。另外,该编辑程序使用了若干特殊字符作为编辑命令,所以它也不希望系统对特殊字符进行处理。例如,Ctrl+D字符通常是终端的文件结束符,但在vi中它是向下滚动半个屏幕的命令。
POSIX.1定义了11个特殊输入字符,其中9个可以改变。
关闭termios结构中中c_lflag字段的ICANO标志就使终端处于非规范模式。在非规范模式中,输入数据并不组成行,不处理下列特殊字符:ERASE,KILL、EOF、NL、EOL、EOL2、CR、REPRINT、STATUS和WERASE。不处理的意思就是,不会对这些特殊的字符,进行特殊的处理。
在规范模式下,系统每次返回一行,但在非规范模式下,系统怎样才能知道在什么时候将数据返回给我们呢?如果它一次返回一个字节,那么系统开销就会很大。在启动读数据时,往往不知道要读多少数据,所以系统不能总是一次返回多个字节。
解决方法: 当已读了指定量的数据后,或者已经过了给定的时间后,即通知系统返回,这种技术使用了termios结构中的c_cc数组的两个变量:MIN和TIME。c_cc数组中的这两个元素下标名为VMIN和VTIME。MIN说明一个read返回前的最小字节数据,TIME说明等待数据到达的分秒数(秒的十分之一是分秒)。 |