linux应用编程12-串口终端

目录

1、终端

1.1、终端分类

1.1.1、本地终端和远程终端

1.1.2、物理终端和伪终端

1.2、查看连接终端

1.3、终端参数

1.4、终端的工作模式

1.4.1、规范模式

1.4.2、非规范模式

1.4.3、原始模式

2、termios API

2.1、struct termios结构体

2.1.1、c_iflag

2.1.2、c_oflag

2.1.3、c_cflag

2.1.4、c_lflag

2.1.5、c_cc

2.2、函数

2.2.1、cfmakeraw()函数

2.2.2、cfsetispeed()函数

2.2.3、cfsetospeed()函数

2.2.4、cfsetspeed()函数

2.2.5、tcdrain()函数

2.2.6、tcflush()函数

2.2.6、tcflow()函数

2.2.7、tcgetattr()函数

2.2.8、tcsetattr()函数

3、串口应用编程流程


1、终端

1.1、终端分类

1.1.1、本地终端和远程终端

本地终端 鼠标、键盘、显示器
远程终端 串口远程终端 通过串口登录
网络远程终端 通过 ssh、 Telnet 等协议登录到一个远程主机

注:/dev/ttyX是本地终端对应的设备节点, 包括/dev/tty1~/dev/tty63 一共63 个本地终端。 

1.1.2、物理终端和伪终端

物理终端 本地直接关联物理设备
伪终端 没有关联任何物理设备

注:/dev/pts/X是伪终端对应的设备节点。

1.2、查看连接终端

使用who 命令可以查看系统当前连接了哪些终端。

1.3、终端参数

输入模式 输入模式控制输入数据(如终端驱动程序从串口或键盘接收到的字符数据)在被传递给应用程序之前的处理方式。
输出模式 输出模式控制输出字符的处理方式,即由应用程序发送出去的字符数据在传递到串口或屏幕之前是如何处理的。
控制模式 控制模式控制终端设备的硬件特性,譬如对于串口来说,该字段比较重要,可设置串口波特率、数据位、校验位、停止位等硬件特性。
本地模式 本地模式用于控制终端的本地数据处理和工作模式。
特殊控制字符 特殊控制字符是一些字符组合如 Ctrl+C、 Ctrl+Z 等, 当用户键入这样的组合键,终端会采取特殊处理方式。
输入速率 终端的输入速率
输出速率 终端的输出速率

1.4、终端的工作模式

1.4.1、规范模式

在规范模式下,所有的输入是基于行进行处理的。在用户输入一个行结束符(回车符、 EOF 等)之前,系统调用 read()函数是读不到用户输入的任何字符的。除了 EOF 之外的行结束符(回车符等)与普通字符一样会被 read()函数读取到缓冲区中。在规范模式中,行编辑是可行的,而且一次 read()调用最多只能读取一行数据。如果在 read()函数中被请求读取的数据字节数小于当前行可读取的字节数,则 read()函数只会读取被请求的字节数,剩下的字节下次再被读取。

1.4.2、非规范模式

在非规范模式下,所有的输入是即时有效的,不需要用户另外输入行结束符,而且不可进行行编辑。

TIME 和 MIN 的值只能用于非规范模式,两者结合起来可以控制对输入数据的读取方式。
MIN = 0 和 TIME = 0 在这种情况下, read()调用总是会立即返回。若有可读数据,则读取数据并返回被读取的字节数; 否则读取不到任何数据并返回 0。
MIN > 0 和 TIME = 0 在这种情况下, read()函数会被阻塞, 直到有 MIN 个字符可以读取时才返回。返回值是读取的字符数量。到达文件尾时返回 0。
MIN = 0 和 TIME > 0 在这种情况下, 只要有数据可读或者经过 TIME 个十分之一秒的时间, read()函数则立即返回返回值为被读取的字节数。如果超时并且未读到数据,则 read()函数返回 0。
MIN > 0 和 TIME > 0
 
在这种情况下, 当有 MIN 个字节可读或者两个输入字符之间的时间间隔超过 TIME 个十分之一秒时, read()函数才返回。因为在输入第一个字符后系统才会启动定时器,所以,在这种情况下, read()函数至少读取一个字节后才返回。

1.4.3、原始模式

原始模式是一种特殊的非规范模式。在原始模式下,所有的输入数据以字节为单位被处理。在这个模式下,终端是不可回显的, 并且禁用终端输入和输出字符的所有特殊处理。

2、termios API

串口的应用编程可以通过 ioctl()对串口进行配置,调用 read()读取串口的数据、调用 write()向串口写入数据。但是通常不这么做!因为 Linux 为上层用户做了一层封装,将这些 ioctl()操作封装成了一套标准的 API。可以直接使用这套标准 API 进行串口应用编程。

注:这一套接口并不是针对串口开发的,而是针对所有的终端设备。

2.1、struct termios结构体

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 */
    speed_t c_ispeed; /* input speed */
    speed_t c_ospeed; /* output speed */
};

注:对于这些变量尽量不要直接对其初始化,而要将其通过“按位与”、“按位或” 等操作添加标志或清除某个标志。

注:不同的终端设备,本身硬件上就存在很大的区别,所以配置参数不是对所有终端设备都是有效的。

2.1.1、c_iflag

输入模式标志。

说明
IGNBRK 忽略输入终止条件
BRKINT 当检测到输入终止条件时发送 SIGINT 信号
IGNPAR 忽略帧错误和奇偶校验错误
PARMRK 对奇偶校验错误做出标记
INPCK 对接收到的数据执行奇偶校验
ISTRIP 将所有接收到的数据裁剪为 7 比特位、也就是去除第八位
INLCR 将接收到的 NL(换行符)转换为 CR(回车符)
IGNCR 忽略接收到的 CR(回车符)
ICRNL 将接收到的 CR(回车符)转换为 NL(换行符)
IUCLC 将接收到的大写字符映射为小写字符
IXON 启动输出软件流控
IXOFF 启动输入软件流控
IXANY 允许任意字节启动流控

2.1.2、c_oflag

输出模式标志。

说明
OPOST 启用输出处理功能,如果不设置该标志则下面其他标志都被忽略
OLCUC 将输出字符中的大写字符转换成小写字符
ONLCR 将输出中的换行符(NL '\n')转换成回车符(CR '\r')
OCRNL 将输出中的回车符(CR '\r')转换成换行符(NL '\n')
ONOCR 在第 0 列不输出回车符(CR)
ONLRET 不输出回车符
OFILL 发送填充字符以提供延时
OFDEL 如果设置该标志,则表示填充字符为 DEL 字符,否则为 NULL
字符

2.1.3、c_cflag

控制模式控制终端设备的硬件特性(串口波特率、数据位、校验位、停止位等)。

CBAUD 波特率的位掩码
B0 波特率为 0
B300 300 波特率
B1200 1200 波特率
B1800 1800 波特率
B2400 2400 波特率
B4800 4800 波特率
B9600 9600 波特率
B19200 19200 波特率
B38400 38400 波特率
B57600 57600 波特率
B115200 115200 波特率
B230400 230400 波特率
B460800 460800 波特率
B500000 500000 波特率
B576000 576000 波特率
B921600 921600 波特率
B1000000 1000000 波特率
B1152000 1152000 波特率
B1500000 1500000 波特率
B2000000 2000000 波特率
B2500000 2500000 波特率
B3000000 3000000 波特率

注:在 Linux 系统下, 使用 CBAUD 位掩码所选择的位来指定串口波特率;在其它一些系统中,可能使用c_ispeed 成员变量和 c_ospeed 成员变量来指定串口的波特率。

CSIZE 数据位的位掩码
CS5 5 个数据位
CS6 6 个数据位
CS7 7 个数据位
CS8 8 个数据位
CSTOPB 2 个停止位,如果不设置该标志则默认是一个停止位
CREAD 接收使能
PARENB 使能奇偶校验
PARODD 使用奇校验、而不是偶校验
HUPCL 关闭时挂断调制解调器
CLOCAL 忽略调制解调器控制线
CRTSCTS 使能硬件流控

2.1.4、c_lflag

本地模式用于控制终端的本地数据处理和工作模式。

ISIG 若收到信号字符(INTR、 QUIT 等),则会产生相应的信号
ICANON 启用规范模式
ECHO 启用输入字符的本地回显功能。
ECHOE 若设置 ICANON,则允许退格操作
ECHOK 若设置 ICANON,则 KILL 字符会删除当前行
ECHONL 若设置 ICANON,则允许回显换行符
ECHOCTL 若设置 ECHO,则控制字符(制表符、换行符等)会显示成“^X”,其中 X 的 ASCII 码等于给相应控制字符的 ASCII 码加上 0x40。例如,退格字符(0x08)会显示为“^H”('H'的 ASCII 码为 0x48)
ECHOPRT 若设置 ICANON 和 IECHO,则删除字符(退格符等)和被删除的字符都会被显示
ECHOKE 若设置 ICANON,则允许回显在 ECHOE 和 ECHOPRT 中设定的 KILL字符
NOFLSH 在通常情况下,当接收到 INTR、 QUIT 和 SUSP 控制字符时,会清空
输入和输出队列。如果设置该标志,则所有的队列不会被清空
TOSTOP 若一个后台进程试图向它的控制终端进行写操作,则系统向该后台进程的进程组发送 SIGTTOU 信号。该信号通常终止进程的执行
IEXTEN 启用输入处理功能

2.1.5、c_cc

特殊控制字符是一些字符组合,如 Ctrl+C、 Ctrl+Z 等, 当用户键入这样的组合键,终端会采取特殊处理方式。

VEOF 文件结尾符 EOF,对应键为 Ctrl+D; 该字符使终端驱动程序将输入行中的全部字符传递给正在读取输入的应用程序。如果文件结尾符是该行的第一个字符,则用户程序中的 read 返回 0,表示文件结束。
VEOL 附加行结尾符 EOL,对应键为 Carriage return(CR) ; 作用类似于行结束符。
VEOL2 第二行结尾符 EOL2,对应键为 Line feed(LF) ;
VERASE 删除操作符 ERASE,对应键为 Backspace(BS) ; 该字符使终端驱动程序删除输入行中的最后一个字符;
VINTR 中断控制字符 INTR,对应键为 Ctrl+C; 该字符使终端驱动程序向与终端相连的进程发送SIGINT 信号;
VKILL 删除行符 KILL,对应键为 Ctrl+U, 该字符使终端驱动程序删除整个输入行;
VMIN 在非规范模式下,指定最少读取的字符数 MIN;
VQUIT 退出操作符 QUIT,对应键为 Ctrl+Z; 该字符使终端驱动程序向与终端相连的进程发送
SIGQUIT 信号。
VSTART 开始字符 START,对应键为 Ctrl+Q; 重新启动被 STOP 暂停的输出。
VSTOP 停止字符 STOP,对应键为 Ctrl+S; 字符作用“截流”,即阻止向终端的进一步输出。用于支持 XON/XOFF 流控。
VSUSP 挂起字符 SUSP,对应键为 Ctrl+Z; 该字符使终端驱动程序向与终端相连的进程发送SIGSUSP 信号,用于挂起当前应用程序。
VTIME 非规范模式下, 指定读取的每个字符之间的超时时间(以分秒为单位) TIME。

2.2、函数

2.2.1、cfmakeraw()函数

将终端配置为原始模式。

#include 
#include 

void cfmakeraw(struct termios *termios_p);

2.2.2、cfsetispeed()函数

设置输入波特率。

注:设置波特率有专门的函数,用户不能直接通过位掩码来操作。

#include 
#include 

int cfsetispeed(struct termios *termios_p, speed_t speed);

2.2.3、cfsetospeed()函数

设置输出波特率。

注:设置波特率有专门的函数,用户不能直接通过位掩码来操作。

#include 
#include 

int cfsetospeed(struct termios *termios_p, speed_t speed);

2.2.4、cfsetspeed()函数

设置波特率。

注:设置波特率有专门的函数,用户不能直接通过位掩码来操作。

#include 
#include 

int cfsetspeed(struct termios *termios_p, speed_t speed);

2.2.5、tcdrain()函数

调用 tcdrain()函数后会使得应用程序阻塞, 直到串口输出缓冲区中的数据全部发送完毕为止!

#include 
#include 

int tcdrain(int fd);

参数 fd:文件描述符。

返回值:调用成功时返回 0;失败将返回-1,并设置 errno。 

2.2.6、tcflush()函数

调用该函数会清空输入/输出缓冲区中的数据。

#include 
#include 

int tcflush(int fd, int queue_selector);

参数 fd:文件描述符。

参数 queue_selector:

TCIFLUSH 对接收到而未被读取的数据进行清空处理
TCOFLUSH 对尚未传输成功的输出数据进行清空处理
TCIOFLUSH 对尚未处理的输入/输出数据进行清空处理

返回值:调用成功时返回 0;失败将返回-1,并设置 errno。

2.2.6、tcflow()函数

调用 tcflow()函数会暂停数据传输或接收工作。

#include 
#include 

int tcflow(int fd, int action);

 参数 fd:文件描述符

参数 action:

TCOOFF 暂停数据输出(输出传输)
TCOON 重新启动暂停的输出
TCIOFF 发送 STOP 字符,停止终端设备向系统发送数据
TCION 发送一个 START 字符,启动终端设备向系统发送数据;

返回值:调用成功时返回 0;失败将返回-1,并设置 errno。

2.2.7、tcgetattr()函数

获取到终端当前的配置参数。

#include 
#include 

int tcgetattr(int fd, struct termios *termios_p);

参数 fd:文件描述符

参数 termios_p:保存获取的配置参数。

返回值:调用成功时返回 0;失败将返回-1,并设置 errno。

2.2.8、tcsetattr()函数

将配置参数写入到终端设备,使其生效。

#include 
#include 

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

参数 fd:文件描述符

参数 optional_actions:指定更改何时生效

TCSANOW 配置立即生效
TCSADRAIN 配置在所有写入 fd 的输出都传输完毕之后生效
TCSAFLUSH 所有已接收但未读取的输入都将在配置生效之前被丢弃

参数 termios_p:将 struct termios 对象中的配置参数写入到终端设备中。
返回值:调用成功时返回 0;失败将返回-1,并设置 errno。

3、串口应用编程流程

1)调用open()打开串口设备文件

注:调用 open()函数时,使用 O_NOCTTY 标志,该标志用于告知系统它不会成为进程的控制终端。

2)调用cfmakeraw()将终端配置为原始模式
3)接收使能

4)调用tcflush()刷新缓冲区

5)设置输入输出波特率

6)设置数据位

7)设置停止位

8)设置奇偶校验位

9)设置 MIN 和 TIME 的值

10) 调用tcsetattr()更新配置

11)调用read()/write()读写数据

       

你可能感兴趣的:(linux,C编程,linux)