近来在一个项目开发中,在一个新的硬件平台下的linux系统,使用uart串口进行通讯,结果通讯不畅。代码是以前在其他硬件平台下验证完全没问题的代码,为什么会出问题呢?经过各方面查资料,最终定位为uart串口初始化的问题。在linux系统下,串口的初始化比较复杂,需要设置的东西比较多,如果有一些默认的配置与硬件和应用程序不匹配,而又没有重新配置,就会导致通讯失败的情况。经过对linux系统下串口初始化的进行了整理梳理,最终解决了问题。记录这批位置可以为其他小伙伴提供参考。
一、termios结构体
termios是在POSIX规范中定义的标准接口,表示终端设备,包括虚拟终端、串口等。串口通过termios进行配置。本文的内容,基本是基于这个这个结构体进行介绍,它是决定串口是否设置成功的关键。
这个结构体的定义如下:
struct termios
{unsigned short c_iflag; // 输入模式标志unsigned short c_oflag; // 输出模式标志unsigned short c_cflag; // 控制模式标志unsigned short c_lflag; // 本地模式标志unsigned char c_line; // 线路规程unsigned char c_cc[NCC]; // 控制特性speed_t c_ispeed; // 输入速度speed_t c_ospeed; // 输出速度
}
在这个结构体中包含了串口设置的绝大部分标志位,下面我们对这个结构体中的元素一一进行分析。
1、输入模式标志c_iflag
c_iflag成员负责控制串口输入数据的处理,下表是c_iflag的部分可用标志
标志 |
说明 |
INPCK |
打开输入奇偶校验 |
IGNPAR |
忽略奇偶错字符 |
PARMRK |
标记奇偶错 |
ISTRIP |
剥除字符第8位 |
IXON |
启用/停止输出控制流起作用 |
IXOFF |
启用/停止输入控制流起作用 |
IGNBRK |
忽略BREAK条件 |
INLCR |
将输入的NL转换为CR |
IGNCR |
忽略CR |
ICRNL |
将输入的CR转换为NL |
设置输入校验
当c_cflag成员的PARENB(奇偶校验)选项启用时,c_iflag的也应启用奇偶校验选项。操作方法是启用INPCK和ISTRIP选项:
options.c_iflag |= (INPCK | ISTRIP);
如果关闭奇偶校验,则使用如下方法:
options.c_iflag &= ~(INPCK | ISTRIP);
设置软件流控制
使用软件流控制是启用IXON、IXOFF和IXANY选项:
options.c_iflag |= (IXON | IXOFF | IXANY);
相反,要禁用软件流控制是禁止上面的选项:
options.c_iflag &= ~(IXON | IXOFF | IXANY);
输入字符转换
linux系统可以将输入字符转换为其他字符,这个功能如果不注意可能会导致程序,比如,ICRNL这个标志位的作用是将输入的CR转换为NL ,如果要启用这个功能,则使用下面的方法:
options.c_iflag |= ICRNL;
如果要禁用这个功能,则使用下面的方法:
options.c_iflag &= ~ICRNL;
2、输入模式标志c_oflag
c_oflag成员管理输出模式,下表所示是c_oflag成员的部分选项标志。
标志 |
说明 |
BSDLY |
退格延迟屏蔽 |
CMSPAR |
标志或空奇偶性 |
CRDLY |
CR延迟屏蔽 |
FFDLY |
换页延迟屏蔽 |
OCRNL |
将输出的CR转换为NL |
OFDEL |
填充符为DEL,否则为NULL |
OFILL |
对于延迟使用填充符 |
OLCUC |
将输出的小写字符转换为大写字符 |
ONLCR |
将NL转换为CR-NL |
ONLRET |
NL执行CR功能 |
ONOCR |
在0列不输出CR |
OPOST |
执行输出处理 |
OXTABS |
将制表符扩充为空格 |