前言
这一系列串口编程重点在应用层编程,但是在讲解原理与相关概念时需要对驱动框架有个基础的认识。如果只是浅尝辄止,以后在遇到串口驱动与应用层程序调试难免遇到瓶颈。关于 tty驱动架构参见我的其他博客:Linux tty驱动程序架构。有时了解下底层以及实现方式对于应用层编程的帮助也是大有裨益的。之前博客讲了终端,tty,控制台等概念以及区别,因此在串口编程相关章节中提及串口,有时也会用终端,tty等来替代,注意它们实际上所指是相同的。
在 Linux 中可以通过一组函数调用(通用终端接口,简称GTI)来控制终端,这组函数调用与用于读写数据的函数是分离的,这就使得读写数据的接口非常简洁,同时又允许可以对终端或串口的行为进行更精细地控制。但由于需要支持大量不同类型的硬件,GTI 中实现的 IO 接口却不简洁。
详解 termios
termios 是在 POSIX 规范中定义的标准接口,它类似与 System V 中的 termio 接口。通过设置 termios 类型的数据结构中的值和使用一小组函数调用,就可以对终端接口进行控制。termios 的结构体定义以及相关函数调用参见 termios.h 头文件。termios 结构的定义如下:
如定义所示,影响终端的参数按照不同模式分成如下几类:
- 输入模式
- 输出模式
- 控制模式
- 本地模式
- 线路规程
- 特殊控制字符
- 输入速率
- 输出速率
输入模式
输入模式控制输入数据(终端驱动程序从串行口或键盘接收到的字符)在被传递给程序之前的处理方式。通过设置 termios 结构中 c_iflag 成员的标志对它们进行控制。所有的标志都被定义为宏,这也是所有终端模式都采用的方法。可用于 c_iflag 成员的宏如下所示:
- BRKINT:当在输入行中检测到一个终止状态(连接丢失)时,产生一个中断。
- IGNBRK:忽略输入行中的终止状态。
- ICRNL:将接收到的回车符转换为新行符。
- IGNCR:忽略接收到的回车符。
- INLCR:将接收到的新行符转换为回车符。
- IGNPAR:忽略奇偶校验错误的字符。
- INPCK:对接收到的字符执行奇偶校验。
- PARMRK:对奇偶校验错误做出标记。
- ISTRIP:将所有接收到的字符裁剪为 7 比特位。
- IXOFF:对输入启动软件流控。
- IXON:对输出启动软件流控。
输出模式
输出模式控制输出字符的处理方式,即由程序发送出去的字符在传递到串行口或屏幕之前是如何处理的。可用于 c_oflag 成员的宏如下所示:
- OPOST:打开输出处理功能。
- ONLCR:将输出中的换行符转换为回车/换行符。
- OCRNL:将输出中的回车符转换为新行符。
- ONOCR:在第0列不输出回车符。
- ONLRET:不输出回车符。
- OFILL:发送填充字符以提供延时。
- OFDEL:用DEL而不是NULL字符作为填充字符。
- NLDLY:新行符延时选择。
- CRDLY:回车符延时选择。
- TABDLY:制表符延时选择。
- BSDLY:退格符延时选择。
- VTDLY:垂直制表符延时选择。
- FFDLY:换页符延时选择。
控制模式
- CLOCAL:忽略所有调制解调器的状态行。
- CREAD:启动字符接收器。
- CS5:发收采用5位数据位。
- CS6:发收采用6位数据位。
- CS7:发收采用7位数据位。
- CS8:发收采用8位数据位。
- CSTOPB:字符采用两位停止位。
- HUPCL:关闭时挂断调制解调器。
- PARENB:使能奇偶校验。
- PARODD:使用奇校验。
本地模式
- ECHO:启用输入字符的本地回显功能。
- ECHOE:接收到 ERASE 时执行退格、空格、退格的动作组合。
- ECHOK:接收到 KILL 字符时执行行删除操作。
- ECHONL:回显新行符。
- ICANON:启用标准输入处理。
- IEXTEN:启用基于特定实现的函数。
- ISIG:启用新号。
- NOFLSH:禁止清空队列。
- TOSTOP:在试图进行写操作之前给后台进程发送一个信号。
特殊控制字符
特殊控制字符是一些字符组合,如 Ctrl+C,当用户键入这样的组合键,终端会采取特殊处理方式。termios 中 c_cc 数组将各种特殊字符映射到对应的支持函数。每个字符位置(数组下标)由对应的宏定义的。根据终端是否被设置为标准模式(即上节提到的 ICANON 标志),数组使用也分为标准与非标准两种情形。
标准模式可以使用的数组下标:
- VEOF:EOF 字符。
- VEOL:EOL 字符。
- VERASE:ERASE 字符。
- VINTR:INTR 字符。
- VKILL:KILL 字符。
- VQUIT:QUIT 字符。
- VSUSP:SUSP 字符。
- VSTART:START 字符。
- VSTOP:STOP 字符。
- VINTR:INTR 字符。
- VMIN:MIN 值。
- VQUIT:QUIT 字符。
- VSUSP:SUSP 字符。
- VTIME:TIME 值。
- VSTART:START 字符。
- VSTOP:STOP 字符。
字符 | 说明 |
---|---|
INTR | 该字符使终端驱动程序向与终端相连的进程发送 SIGINT 信号 |
QUIT | 该字符使终端驱动程序向与终端相连的进程发送 SIGQUIT 信号 |
ERASE | 该字符使终端驱动程序删除输入行中的最后一个字符 |
KILL | 该字符使终端驱动程序删除整个输入行 |
EOF | 该字符使终端驱动程序将输入行中的全部字符传递给正在读取输入的应用程序。若输入行为空,read为0 |
EOL | 作用类似于行结束符,效果和常用的新行符相同 |
SUSP | 该字符使终端驱动程序向与终端相连的进程发送SIGSUSP信号,用于挂起当前应用程序 |
STOP | 字符作用“截流”,即阻止向终端的进一步输出。用于支持 XON/XOFF 流控,通常被设置为 ASCII 的XOFF |
START | 重新启动被 STOP 暂停的输出,通过被设置为 ASCII 的 XON 字符。 |
VTIME 和 VMIN
TIME值和MIN值只能用于非标准模式,关于二者的使用详见博客:Linux termios 串口编程之 VTIME与VMIN。
SHELL下使用 stty 访问终端模式
在 shell 下可以使用 stty 可以访问终端 termios。如:
#打印串口设备 ttyUSB0 设置情况。
root@ubuntu:/# stty -F /dev/ttyUSB0 -a
#设置 ttyUSB0 为 115200 波特率,8位数据位。
root@ubuntu:/# stty -F /dev/ttyUSB0 ispeed 115200 ospeed 115200 cs8
在设置成功之后就可以通过 cat、echo 等 shell 命令对设备进行读写了。
本篇重点在于介绍 termios 概念以及详细模式标志位等,大部分是不需要记忆的,使用频率也很低。
关于 Linux 串口编程的其他文章,可以移步至以下链接:
- 《Linux 串口编程<一> 一些背景》
- 《Linux 串口编程<二> 深入了解 termios》
- 《Linux 串口编程<三> 使用termios与API 进行串口程序开发》
- 《Linux 串口编程<四> 串口设备程序开发》
如果有其他想法或者疑问可以给我邮件或者评论~:-D