linux串口特殊字符不能接收

最近在linux系统中写了个串口收发程序,通过协议与下位机通讯,期间发现某些字符老接收不到,某些字符被更改,分析及其解决方法如下:

一、只接收到数据

0D 变成了0A  13收不到

 

解决此问题之前我们先看终端I/O的两种输入处理模式:

(1) 规范方式输入处理。在这种方式中,终端输入以行为单位进行处理。对于每个读要求,
终端驱动程序最多返回一行。
(2) 非规范方式输入处理。输入字符不以行为单位进行装配。
如果不作特殊处理,则默认方式是规范方式。例如:若s h e l l的标准输入、输出是终端,在
用r e a d和w r i t e将标准输入复制到标准输出时,终端以规范方式进行工作,每次r e a d最多返回一行。处理整个屏幕的程序,例如v i编辑程序使用非规范方式,其原因是其命令是由不以新行符终止的一个或几个字符组成的。另外,该编辑程序使用了若干特殊字符作为编辑命令,所以它也不希望系统对特殊字符进行处理。例如, C t r l - D字符通常是终端的文件结束符,但在v i中它是向下滚动半个屏幕的命令。

 

0x0a即'/n',以NL来表示,也就是说类似按了enter键,本行数据才输出,所以必须修改,将终端设置在 非规范方式输入处理。

在<termios.h>中,有如下定义

struct termios {
 tcflag_t c_iflag;  /* input mode flags */
 tcflag_t c_oflag;  /* output mode flags */
 tcflag_t c_cflag;  /* control mode flags */
 tcflag_t c_lflag;  /* local mode flags */
 cc_t c_line;   /* line discipline */
 cc_t c_cc[NCCS];  /* control characters */
};

 

c_iflag由终端设备驱动程序用来控制输入特性(剥除输入字节的第8位,允许输
入奇偶校验等等)

c_oflag则控制输出特性(执行输出处理,将新行映照为C R / L F等)

c_cflag影响到UART串行线(忽略调制解调器的状态线,每个字符的一个或两个停止位等等),
c_lflag影响驱动程序和用户之间的界面(回送的开或关,可视的擦除符,允许终端产生的信
号,对后台作业输出的控制停止信号等)。


修改非规范方式输入处理,如下:struct termios options;
tcgetattr( fd,&options)  

options.c_lflag &= ~(ICANON );

通过修改c_lflag本地模式,将ICANON属性去掉,ICANON就是规范化方式。

 

二、接收到数据:

04 05 06 07 08 09 0a 0b 0c 0a 0e 0f 
10 11 12 1d 1e 1f ……

其余数据全正确

03以前的数据全部没有,而0x03相当于 ^c, 即CTRL+C, ^c, ^?由ISIG来控制,那么去除该控制,应该就可以显示03了,再次修改为:

options.c_lflag &= ~(ICANON |ISIG);

 

三、接收到数据:

00 01 02 03 04 05 06 07 08 09 0a 0b 
0c 0a 0e 0f 10 12 14

其余数据全部正确

看,0d变成了0a

c_iflag模式中,有ICRNL项,IGNCR项,将两者去掉:

options.c_iflag &= ~(ICRNL|IGNCR)

至此0D数据正常了。


但是13依然接收不到

c_iflag模式中,有IXON项,IXOFF项,将两者去掉:

options.c_iflag &= ~(ICRNL|IGNCR|IXON|IXOFF)

至此13接收正常。



四、下面我们对termios成员进行解释

tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_cc[NCCS];
其具体意义如下。
c_iflag:输入模式标志,控制终端输入方式,具体参数如表1所示。
表1 c_iflag参数表
键 值
说 明
IGNBRK
忽略BREAK键输入
BRKINT
如果设置了IGNBRK,BREAK键输入将被忽略
IGNPAR
忽略奇偶校验错误
PARMRK
标识奇偶校验错误
INPCK
允许输入奇偶校验
ISTRIP
去除字符的第8个比特
INLCR
将输入的NL(换行)转换成CR(回车)
IGNCR
忽略输入的回车
ICRNL
将输入的回车转化成换行(如果IGNCR未设置的情况下)
IUCLC
将输入的大写字符转换成小写字符(非POSIX)
IXON
允许输出时对XON/XOFF流进行控制
IXANY
输入任何字符将重启停止的输出
IXOFF
允许输入时对XON/XOFF流进行控制
IMAXBEL
当输入队列满的时候开始响铃
c_oflag:输出模式标志,控制终端输出方式,具体参数如表2所示。
表2 c_oflag参数
键 值
说 明
OPOST
处理后输出
OLCUC
将输入的小写字符转换成大写字符(非POSIX)
ONLCR
将输入的NL(换行)转换成CR(回车)及NL(换行)
OCRNL
将输入的CR(回车)转换成NL(换行)
ONOCR
第一行不输出回车符
ONLRET
不输出回车符
OFILL
发送填充字符以延迟终端输出
OFDEL
以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符为NUL
NLDLY
换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)
CRDLY
回车延迟,取值范围为:CR0、CR1、CR2和 CR3
TABDLY
水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3
BSDLY
空格输出延迟,可以取BS0或BS1
VTDLY
垂直制表符输出延迟,可以取VT0或VT1
FFDLY
换页延迟,可以取FF0或FF1
c_cflag:控制模式标志,指定终端硬件控制信息,具体参数如表3所示。
表3 c_cflag参数
键 值
说 明
CBAUD
波特率(4+1位)(非POSIX)
CBAUDEX
附加波特率(1位)(非POSIX)
CSIZE
字符长度,取值范围为CS5、CS6、CS7或CS8
CSTOPB
设置两个停止位
CREAD
使用接收器
PARENB
使用奇偶校验
PARODD
对输入使用奇偶校验,对输出使用偶校验
HUPCL
关闭设备时挂起
CLOCAL
忽略调制解调器线路状态
CRTSCTS
使用RTS/CTS流控制
c_lflag:本地模式标志,控制终端编辑功能,具体参数如表4所示。
表4 c_lflag参数
键 值
说 明
ISIG
当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
ICANON
使用标准输入模式
XCASE
在ICANON和XCASE同时设置的情况下,终端只使用大写。
ECHO
显示输入字符
ECHOE
如果ICANON同时设置,ERASE将删除输入的字符
ECHOK
如果ICANON同时设置,KILL将删除当前行
ECHONL
如果ICANON同时设置,即使ECHO没有设置依然显示换行符
ECHOPRT
如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
TOSTOP
向后台输出发送SIGTTOU信号
c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等。c_cc中定义了如表5所示的控制字符。
表5 c_cc支持的控制字符
说 明
说 明
VINTR
Interrupt字符
VEOL
附加的End-of-file字符
VQUIT
Quit字符
VTIME
非规范模式读取时的超时时间
VERASE
Erase字符
VSTOP
Stop字符
VKILL
Kill字符
VSTART
Start字符
VEOF
End-of-file字符
VSUSP
Suspend字符
VMIN
非规范模式读取时的最小字符数
   
tcsetattr函数用于设置终端的相关参数。参数fd为打开的终端文件描述符,参数optional_actions用于控制修改起作用的时间,而结构体termios_p中保存了要修改的参数。
optional_actions可以取如下的值:
TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:清空输入输出缓冲区才改变属性。
错误信息:
EBADF:非法的文件描述符。
EINTR:tcsetattr函数调用被信号中断。
EINVAL:参数optional_actions使用了非法值,或参数termios中使用了非法值。
ENCTTY:非终端的文件描述符。

属性设置

函数:int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);

tcsetattr函数用于设置终端参数。函数在成功的时候返回0,失败的时候返回-1,并设置errno的值。

参数说明:

参数fd为打开的终端文件描述符,参数optional_actions用于控制修改起作用的时间,而结构体termios_p中保存了要修改的参数。optional_actions可以取如下的值。

 

TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:清空输入输出缓冲区才改变属性。
EBADF:非法的 文件描述符
EINTR:tcsetattr 函数调用被信号中断。
EINVAL:参数optional_actions使用了非法值,或参数termios中使用了非法值。
ENCTTY:非 终端文件描述符



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值