嵌入式Linux 串口编程系列1——基本知识、termios结构体

2019-07-13 04:28发布

    对于嵌入式系统开发而言,串口应用编程几乎是使用最 广泛的,应用案例如下: (1)串口与 外围设备通信,比如串口作为主设备,访问各种仪表从设备,协议一般有自有协议、Modbus通信协议。  (2)开发的设备作为从设备,外部设备通过串口进行相关通信,也比如Modbus通信协议及各种其他 私有协议。  (3)通过串口实现 交互,本质上也是通信,我们使用的shell,最 常见的通信渠道 就是串口。    可以说, 串口几乎是所有嵌入式设备的必备功能。关于串口的硬件层面的相关规定,可以参考之前的文章   《串口的一些基本概念--RS485 RS422 RS232 流控制》   无论在任何的系统环境下开发,串口的配置是必不可少的,包括串口通信参数:波特率、数据位、奇偶校验等,这些都是比较简单的,理解起来也是很容易的,串口配置的难点在于“接收中断”,之所以有这个难点的 原因是在于应用场景,因为所有的应用程序通过串口进行通信,都必然涉及到协议,所谓 协议就是 两个设备之间 对话的 规则,而成功通信的基础就是彼此都遵守通信协议,比如 工业上常用的 Modbus通信协议,主设备A只有发送 符合Modbus通信框架的数据,从设备B才会相应设备A,而从设备B 也需要符合Modbus协议标准,设备A才会认可,进而A、B之间才能成功通信。所以这就带来了一些难点,比如最常见的串口接收数据长度不定,怎么去处理?这个一般是通过固定结束字符、定时器空闲中断、DMA接收中断 等等。     在非linux下进行 串口配置,大多通过配置相应的 控制寄存器来实现,而接收层面,则是通过上面说的,对各种中断的处理,具体场景 具体分析。    在Linux下进行串口的配置,主要是通过 对结构体 termios 进行配置,这个就类似于 上面说的 寄存器,只不过Linxu的开发是采用多级分层的,应用 程序员是不用考虑底层CPU的寄存器的,只需要关注 专用 结构体 termios即可。因为应用层下面还有驱动层,只有驱动工程师才需要解除实际的硬件。 termios结构体     我们通过官方 手册里可以看到, 这个结构体内容如下: The header shall define the termios structure, which shall include at least the following members: tcflag_t c_iflag Input modes. tcflag_t c_oflag Output modes. tcflag_t c_cflag Control modes. tcflag_t c_lflag Local modes. cc_t c_cc[NCCS] Control characters.    其中 tcflag_t 是 unsigned short类型,cc_t 是 unsigned char类型,翻译过来如下: struct termios { unsigned short c_iflag; //输入模式 unsigned short c_oflag; //输出模式 unsigned short c_cflag; //控制模式 unsigned short c_lflag; //本地模式 unsigned char c_cc[NCC]; //控制 字符 数据 }  1、 c_iflag 输入模式控制      该参数如要是 实现 串口接收到的数据  传给应用程序 之前,进行先一步的处理,比如将输入中的 NL 翻译为CR,去掉第8位、忽略帧错误和奇偶校验错误,启用输入 奇偶校验检测等。具体宏定义如下: INPCK 奇偶校验使能 IGNPAR 忽略奇偶校验错误 PARMRK 奇偶校验错误掩码 ISTRIP 裁剪掉第8比特 IXON 启动输出软件控制流 IXOF 启动输入软件控制流 IXANY 输入任意字符可以重新启动输入(默:起始字符) IGNBRK 忽略输入终止条件 BRKINT 当检测到输入终止条件时发送SIGINT信号 INLCR 当收到NL(换行符)转换CR(回车符) IGNCR 忽略收到的CR ICRNL 当收到CR转换为NL IUCLC 讲接收到的大写字符映射为小写字符 IMAXBEL 当输入队列满时响铃    2、 c_oflag 输出模式控制       与输入模式控制相对应,负责控制输出单元的处理方式,具体参数宏定义如下: OPOST 启动输出处理功能,如果不设置,其他位忽略 OLCUC 将输出中的大写字符转换成小写字符 ONLCR 将输出中的换行符(‘ ’)转换成回车符(‘ ’) ONOCR 如果当前列号为0,则不输出回车字符 OCRNL 将输出中的回车符转换成换行 ONLRET 不输出回车符 OFILL 发送填充字符以提供延时 OFDEL 如果设置该标志,则表示填充字符为DEL字符,否则为NUL NLDLY 换行延时掩码 CRDLY 回车延时掩码 TABDLY 制表符延时掩码 BSDLY 水平退格符延时掩码 VTDLY 垂直退格符延时掩码 FFLDY 换页符延时掩码    3、 c_cflag 控制模式标志      该元素主要是 用于控制终端设备的硬件设备,波特率、数据位等,这也是最需要配置的元素,宏定义如下: CBAUD 波特率的位掩码 B0 0波特率(放弃DTR) … … B1800 1800的波特率 B2400 2400的波特率 B4800 4800的波特率 B9600 9600的波特率 B19200 19200的波特率 B38400 38400的波特率 B57600 57600的波特率 B115200 115200的波特率 EXTA 外部时钟率 EXTB 外部时钟率 CSIZE 数据位的位掩码 CS5 5个数据位 CS6 6个数据位 CS7 7个数据位 CS8 8个数据位 CSTOPB 2个停止位(不设置则是一个) GREAD 接收使能 PARENB 校验使能位 PARODD 使用奇校验而不是偶校验 HUPCL 最后关闭时挂线(放弃DTR) CLOCAL 本地连接(不改变端口所有者) CRTSCTS 硬件流控   4、 c_lflag 本地控制模式 ISIG 若收到信号字符(INTR,QUIT等)则会产生相应的信号 ICANON 启动规范模式 ECHO 启动本地回显功能 ECHOE 若设置ICANON则允许退格操作 ECHOK 若设置ICANON,则KILL字符会删除当前行 ECHONL 若设置ICANON,则允许回显换行符 ECHOCTL 若设置ECHO,则控制字符会显示成^x,其中x的ASCII码等于给相应的控制字符的ASCII码 加上0x40. ECHOPRT 若设置ICANON和IECHO,则删除字符和被删除的字符都会被显示 ECHOKE 若设置ICANON,则允许回显在ECHOE和ECHOPRT中设定的KILL字符 NOFLASH 在通常情况下,当接收到INTR,QUIT,SUSP控制字符时,会清空输入和输出队列。如果 设置改标志,则所有的队列不会被清空 TOSTOP 若一个后台进程师徒向他的控制终端进行写操作,则系统向改后台进程的进程组发送SIGTTOU 该信号通常终止进程的执行 IEXTEN 启动输入处理功能 5、c_cc 数组:特殊控制字元可提供使用者设定一些特殊的功能,定义如下: VINTR 中断控制字符,对应的键位ctrl+c VQUIT 退出操作符,对应的键为ctrl+z VERASE 删除操作符,对应Backspace VKILL 删除行符,对应的键为ctrl+u VEOF 文件结尾符,对应的键为ctrl+d VEOL 附加行结尾符,对应的键为carriage return VEOL2 第二行结尾符,对应的键为line feed VMIN 指定最少读取的字符数 VTIME 指定读取的每个字符之间的超时时间     这里面,最常用的是VMIN和VTIME,    VMIN  指定了 串口至少要读取VMIN个字符,才会不阻塞,也就是 串口接收超过VMIN个字符,read函数才会有返回,              使用该功能,可以实现 定长 数据的接收。    VTIME 指定了字符超时,也就是需要等待几百毫秒的值,read才会返回,单位是100ms,    VMIN和VTIME的组合,可以实现特定接收 处理,关系如下: VMIN = 0 和 VTIME = 0 :在这种情况下,read 调用总是立刻返回。如果有等待处理的字符,read 就会立 刻返回;如果没有字符等待处理,read 调用返回0,并且不读取任何字符; VMIN = 0 和 VTIME > 0 :在这种情况下,只要有字符可以处理或者是经过 VTIME 个十分之一秒的时间间 隔,read 调用就返回。如果因为超时而未读到任何字符, read 返回0,否则 read 返回读取的字符数目。 VMIN > 0 和 VTIME = 0 :在这种情况下,read 调用将一直等待,直到有 MIN 个字符可以读取时才返回, 返回值是读取的字符数量。到达文件尾时返回0。 VMIN > 0 和 VTIME > 0 :在这种情况下,当 read 被调用时,它会等待接收一个字符。在接收到第一个字 符及后续的每个字符后,一个字符间隔定时器被启动(如果定时器已经运行,则 重启它)。当有 MIN 个字符可读或两个字符之间的时间间隔超过 TIME 个十分 之一秒时,read 调用返回。这个功能可用于区分是单独按下了 Escape 键还是 按下一个 Escape 键开始的功能组合键。但要注意的是,网络通信或处理器的高 负载将使得类似这样的定时器失去作用。