目录
概述
1 了解串口应用编程
1.1 认识 struct termios 结构体
1.1.1 认识c_iflag
1.1.2 认识c_oflag
1.1.3 认识 c_cflag 的配置参数
1.1.4 认识c_lflag
1.2 终端相关的函数库
2 编写串口应用接口
2.1 设置baud函数
2.2 设置停止位函数
2.3 设置奇偶校验函数
2.4 设置停止位函数
3 使用usr API接口
3.1 配置参数函数
3.2 初始化串口函数
3.3 关闭串口函数
4 参考资料
源代码下载地址: Linux环境下终端接口应用函数(serialport)资源-CSDN文库
概述
本文介绍linux环境下终端接口的相关知识,并介绍与其相关的数据结构的意义,重要参数的解释。还使用接口编写用户函数,以实现基于serial port的终端功能。
1 了解串口应用编程
在linux环境下,串口是终端的一种形式。对其操作,linux中已经定义了关于termios 的API 。在使用这些API之前,必须对其要有基本的认识。
1.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 */
};
参数定义如下:
参数名称 | 描述 | 注释 |
---|---|---|
c_iflag | 输入模式参数标志位 | |
c_oflag | 输出模式参数标志位 | |
c_cflag | 控制模式参数标志位 | |
c_lflag | 本地模式参数标志位 | |
c_line | 终端的行规程 | |
c_cc[NCCS] | 终端的特殊字符 | |
c_ispeed | 配置输入波特率参数 | |
c_ospeed | 配置输出波特率参数 |
1.1.1 认识c_iflag
参数定义 | 描述 |
---|---|
IGNBRK | 忽略输入终止条件 |
BRKINT | 当检测到输入终止条件时发送 SIGINT 信号 |
IGNPAR | 忽略帧错误和奇偶校验错误 |
PARMRK | 对奇偶校验错误做出标记 |
INPCK | 对接收到的数据执行奇偶校验 |
ISTRIP | 将所有接收到的数据裁剪为 7 比特位、也就是去除第八位 |
INLCR | 将接收到的 NL(换行符)转换为 CR(回车符) |
IGNCR | 忽略接收到的 CR(回车符) |
ICRNL | 将接收到的 CR(回车符)转换为 NL(换行符) |
IUCLC | 将接收到的大写字符映射为小写字符 |
IXON | 启动输出软件流控 |
IXOFF | 启动输入软件流控 |
1.1.2 认识c_oflag
参数定义 | 描述 |
---|---|
IGNBRK | 忽略输入终止条件 |
OPOST | 启用输出处理功能,如果不设置该标志则其他标志都被忽略 |
OLCUC | 将输出字符中的大写字符转换成小写字符 |
ONLCR | 将输出中的换行符(NL '\n')转换成回车符(CR '\r') |
OCRNL | 将输出中的回车符(CR '\r')转换成换行符(NL '\n') |
ONOCR | 在第 0 列不输出回车符(CR) |
ONLRET | 不输出回车符 |
OFILL | 发送填充字符以提供延时 |
OFDEL | 如果设置该标志,则表示填充字符为 DEL 字符,否则为 NULL 字符 |
1.1.3 认识 c_cflag
含义: 控制模式标志,指定终端硬件控制信息
参数定义 | 描述 |
---|---|
CBAUD | 波特率(4+1位)(非POSIX) |
CBAUDEX | 附加波特率(1位)(非POSIX) |
CSIZE | 字符长度,取值范围为CS5、CS6、CS7或CS8 |
CSTOPB | 2 个停止位,如果不设置该标志则默认是一个停止位 |
CREAD | 使用接收器 |
PARENB | 使用奇偶校验 |
PARODD | 对输入使用奇偶校验,对输出使用偶校验 |
HUPCL | 关闭设备时挂起 |
CLOCAL | 忽略调制解调器线路状态 |
CRTSCTS | 使用RTS/CTS流控制 |
CBAUD 参数定义如下
参数定义 | 描述 |
---|---|
CBAUD | 波特率的位掩码 |
B2400 | 2400 波特率 |
B9600 | 9600 波特率 |
B19200 | 19200 波特率 |
B38400 | 38400波特率 |
B57600 | 57600波特率 |
B115200 | 115200波特率 |
.... | 其他波特率定义参看:termios.h |
CSIZE参数定义如下
参数定义 | 描述 |
---|---|
CS5 | 5 个数据位 |
CS6 | 6 个数据位 |
CS7 | 7 个数据位 |
CS8 | 8个数据位 |
1.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 | 启用输入处理功能 |
1.2 终端相关的函数库
使用串口终端,必须包含下面两个图文件
#include <termios.h>#include <unistd.h>
其提供的函数接口如下:
函数名 | 功能介绍 | |
---|---|---|
tcgetattr | 获取与终端相关的参数 | 取得终端介质(fd)初始值,并把其值 赋给temios_p;函数可以从后台进程中调用;但是,终端属性可能被后来的前台进程所改变。 |
tcsetattr | 配置与终端相关的参数 | 设置与终端相关的参数 (除非需要底层支持却无法满足),使用 termios_p 引用的 termios 结构。 optional_actions (tcsetattr函数的第二个参数)指定了什么时候改变会起作用: TCSANOW:改变立即发生 TCSADRAIN:改变在所有写入 fd 的输出都被传输后生效。这个函数应当用于修改影响输出的参数时使用。(当前输出完成时将值改变) TCSAFLUSH :改变在所有写入 fd 引用的对象的输出都被传输后生效,所有已接受但未读入的输入都在改变发生前丢弃(同TCSADRAIN,但会舍弃当前所有值)。 |
tcsendbreak | 在一个指定的时间区内发送连续的0位流 | 传送连续的 0 值比特流,持续一段时间,如果终端使用异步串行数据传输的话。如果 duration 是 0,它至少传输 0.25 秒,不会超过 0.5 秒。如果 duration 非零,它发送的时间长度由实现定义 |
tcdrain | 等待所有输出都被发送 | 等待直到所有写入 fd 引用的对象的输出都被传输 |
tcflush | 清除输入缓冲区或输出缓冲区 | ueue_selector 的值: TCIFLUSH :刷新收到的数据但是不读 TCOFLUSH :刷新写入的数据但是不传送 TCIOFLUSH :同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送 |
tcflow | 对输入和输出流控制进行控制 | 挂起 fd 引用的对象上的数据传输或接收,取决于 action 的值: |
cfmakeraw | 设置终端设置为原始模式(raw data ) | TCOOFF :挂起输出 TCOON :重新开始被挂起的输出 TCIOFF :发送一个 STOP 字符,停止终端设备向系统传送数据 TCION :发送一个 START 字符,使终端设备向系统传输数据 打开一个终端设备时的默认设置是输入和输出都没有挂起。 |
cfgetispeed | 返回存储在 TermiosPointer 参数指向的 termios 结构中的输入波特率 | |
cfgetospeed | 返回存储在 TermiosPointer 参数所指向的 termios 结构中的输出波特率 | |
cfsetispeed | 将存储在 TermiosPointer 参数指向的 termios 结构中的输入波特率设置为 Speed 参数指定的值 | 设置 termios 结构中,输入和输出波特率的值。新值不会马上生效,直到成功调用了 tcsetattr() 函数。 |
cfsetospeed | 存储在 TermiosPointer 参数指向的 termios 结构中的输出波特率设置为 Speed 参数指定的值 | 设置 termios 结构中,输入和输出波特率的值。新值不会马上生效,直到成功调用了 tcsetattr() 函数。 |
函数原型声明如下:
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions,const struct termios *termios_p);
int tcsendbreak(int fd, int duration);
int tcdrain(int fd);
int tcflush(int fd, int queue_selector);
int tcflow(int fd, int action);
void cfmakeraw(struct termios *termios_p);
speed_t cfgetispeed(const struct termios *termios_p);
speed_t cfgetospeed(const struct termios *termios_p);
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
2 编写串口应用接口
2.1 设置baud函数
static void set_baudrate (unsigned int baudrate)
{speed_t speed;speed = baudrate_to_Bxx (baudrate); /* set baudrate */cfsetispeed(&termios_new, speed); // set input speedcfsetospeed(&termios_new, speed); // set output speed
}
使用cfsetispeed()设置波特率时,必须要要把其转换为 termios.h定义的类型,本例中使用baudrate_to_Bxx()函数实现这个功能。在 termios.h中定义的baud类型:
static speed_t baudrate_to_Bxx (unsigned int baudrate)
{switch (baudrate) {case 1200:return (B1200);case 2400:return (B2400);case 9600:return (B9600);case 19200:return (B19200);case 38400:return (B38400);case 57600:return (B57600);case 115200:return (B115200);default:return (B9600);}
}
2.2 设置停止位函数
static void set_stopbit (const char *stopbit)
{if (0 == strcmp (stopbit, "1")) {termios_new.c_cflag &= ~CSTOPB; /* 1 stop bit */}else if (0 == strcmp (stopbit, "1.5")) {termios_new.c_cflag &= ~CSTOPB; /* 1.5 stop bits */}else if (0 == strcmp (stopbit, "2")) {termios_new.c_cflag |= CSTOPB; /* 2 stop bits */}else {termios_new.c_cflag &= ~CSTOPB; /* 1 stop bit */}
}
2.3 设置奇偶校验函数
static void set_parity (char parity)
{switch (parity) {case 'N': /* no parity check */termios_new.c_cflag &= ~PARENB;break;case 'E': /* even */termios_new.c_cflag |= PARENB;termios_new.c_cflag &= ~PARODD;break;case 'O': /* odd */termios_new.c_cflag |= PARENB;termios_new.c_cflag |= ~PARODD;break;default: /* no parity check */termios_new.c_cflag &= ~PARENB;break;}
}
2.4 设置停止位函数
static void set_data_bit (unsigned int databit)
{termios_new.c_cflag &= ~CSIZE;switch (databit) {default:case 8:termios_new.c_cflag |= CS8;break;case 7:termios_new.c_cflag |= CS7;break;case 6:termios_new.c_cflag |= CS6;break;case 5:termios_new.c_cflag |= CS5;break;}
}
3 使用usr API接口
3.1 配置参数函数
编写一个函数,初始化串口参数,详细代码如下,其操作步骤:
step-1: 清空termios_new
step-2: 初始化termios_new数据结构
step-3: 填充用户参数
step-4: 调用tcsetattr使参数生效
static unsigned int set_portattr ( unsigned int baudrate, // 2400 4800 9600 .. 115200unsigned int databit, // 5, 6, 7, 8const char *stopbit, // "1", "1.5", "2"char parity) // N(o), O(dd), E(ven)
{bzero(&termios_new, sizeof (termios_new));cfmakeraw (&termios_new);set_baudrate (baudrate);termios_new.c_cflag |= CLOCAL | CREAD; /* | CRTSCTS */set_data_bit (databit);set_parity (parity);set_stopbit (stopbit);termios_new.c_cc[VTIME] = 1; /* unit: 1/10 second. */termios_new.c_cc[VMIN] = 255; /* minimal characters for reading */return (tcsetattr (fd, TCSANOW, &termios_new));
}
3.2 初始化串口函数
在初始化函数中,其操作步骤如下:
step-1: 打开串口设备
step-2: 获取旧的终端参数,并将其保存在termios_old中
step-3: 调用set_portattr配置参数
int usr_serial_open( char *port, unsigned int baudrate, unsigned int databit, const char *stopbit, char parity)
{int err;fd = open (port, O_RDWR | O_NOCTTY | O_NDELAY);if (-1 == fd) {fprintf(stderr, "cannot open port %s\n", port);return (-1);}tcgetattr (fd, &termios_old); /* save the form termios value */err = set_portattr (baudrate, databit, stopbit, parity);if ( err ) {fprintf ( stderr, "\nport %s cannot set baudrate at %d\n",port, baudrate);}return fd;
}
3.3 关闭串口函数
关闭串口函数,主要做如下事情:
step-1: 恢复termios_old参数
step-2: 关闭fd对应的端口
void usr_serial_close( void )
{/* flush output data before close and restore old attribute */tcsetattr(fd, TCSADRAIN, &termios_old);close(fd);
}
4 参考资料
《Linux/Unix系统编程手册(下册)》