0
点赞
收藏
分享

微信扫一扫

Linux下串口编程​

1.1 串口的名称

1.1.2 PC机的串口节点名称

串口的节点在/dev下边。

Linux下串口编程​_数据


计算机本身的串口:ttySx

USB串口:ttyUSBx

虚拟机右下角可以将USB串口设备挂载到dev下。

1.1.2 串口测试命令: microcom

命令使用方法:

[root@wbyq ]# microcom --help

BusyBox v1.23.2 (2020-09-04 15:21:06 CST) multi-call binary.


Usage: microcom [-d DELAY] [-t TIMEOUT] [-s SPEED] [-X] TTY


Copy bytes for stdin to TTY and from TTY to stdout


-d Wait up to DELAY ms for TTY output before sending every

next byte to it

-t Exit if both stdin and TTY are silent for TIMEOUT ms

-s Set serial line to SPEED

-X Disable special meaning of NUL and Ctrl-X from stdin​

参数如下:

-d 表示延时时间。发送一个字节后等待一段时间发送下一个字节.

-t 表示超时时间,超多少时间就自动退出。单位为ms

-s 表示波特率。

-X 禁用stdin中NUL和Ctrl-X特殊含义。

TTY 指定串口设备节点。如SAC0。

测试命令如下:

[root@wbyq ]# microcom -t 5000 -s 115200 /dev/ttySAC2

1.2 串口基本操作

1.2.1 打开串口

打开串口连接的时候,程序在open函数中除了Read+Write模式以外还需要指定O_NOCTTY选项:

fd=open("/dev/ttyUSB0",O_RDWR|O_NOCTTY);

标志O_NOCTTY告诉系统这个程序不会成为这个端口上的“控制终端”。如果不这样做的话,所有的输入,比如键盘上过来的Ctrl+C中止信号等等,会影响到你的进程。但是通常情况下,用户程序不会使用这个选项。

1.2.2向串口写数据

Linux下一切皆文件,写数据直接使用write、fputs等函数即可直接向串口发送数据。

n = write(fd, "1234\r\n", 6);


1.2.3从串口读数据

读数据的时候需要找准时机,需要知道串口何时有数据,可以使用linux下的轮询机制进行监控串口的文件描述符。

比如: poll、select、epoll机制等。也可以使用异步通知机制:fasync。

cnt=read(fd,buff,1024);


1.2.4 关闭串口

可以使用close系统调用关闭串口:  close(fd);


1.3 配置串口​

1.3.1 刷新输入输出缓冲区

函数原型: int tcflush(int fd, int queue_selector);

函数功能: 丢弃写入或者收到但是没有读取的数据.

函数参数:

int文件描述符.

int queue_selector:

TCIFLUSH

刷新已接收但未读取的数据。

TCOFLUSH

刷新已写入但未传输的数据。

TCIOFLUSH 刷新已接收但未读取的数据,以及已写入但未传输的数据。


1.3.2 设置输入输出波特率

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);

函数功能: 设置输出波特率.


波特率可以设置以下的值:

B0

B50

B75

B110

B134

B150

B200

B300

B600

B1200

B1800

B2400

B4800

B9600

B19200

B38400

B57600

B115200

B230400


波特率设置示例:

struct termios uart_cfg;

memset(&uart_cfg,0,sizeof(struct termios));

cfsetispeed(&uart_cfg,B115200); //设置输入波特率

cfsetospeed(&uart_cfg,B115200); //设置输出波特率


1.3.3 设置串口属性参数

进行串口编程时,最重要的是tcgetattrtcsetattr这两个函数,这两个函数可以设置串口的参数和获取串口已经配置的参数。

比如: 波特率、停止位、数据位、奇偶校验位等.

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

函数功能: 获取终端属性参数.


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

函数功能: 设置终端属性参数.

参数介绍:

int文件描述符.

int设置更改的时机.

TCSANOW

更改立即发生。

TCSADRAIN

在传输完所有写入fd的输出之后,将发生更改。

TCSAFLUSH

将所有输出写入fd引用的对象之后,将发生更改发送,并且所有已接收但未读取的输入将被丢弃在进行更改之前。

const struct termios *termios_p : 保存配置属性的结构体


配置示例:

struct termios uart_cfg;

memset(&uart_cfg,0,sizeof(struct termios));

cfsetispeed(&uart_cfg,B115200); //设置输入波特率

cfsetospeed(&uart_cfg,B115200); //设置输出波特率

uart_cfg.c_cflag &= ~CSIZE; //清除串口的数据位

uart_cfg.c_cflag |= CS8; //配置串口的数据位为 8 位

uart_cfg.c_cflag &= ~CSTOPB; //配置的停止位:1 个

uart_cfg.c_cflag |= CREAD; //使能接收

uart_cfg.c_cflag &= ~PARENB; //不使用奇偶校验

tcsetattr(fd,TCSANOW,&uart_cfg);


1.4 struct termios 结构体介绍

Struct termios结构体包含了以下成员:

tcflag_t c_iflag; /* 输入模式设置 */

tcflag_t c_oflag; /* 输出模式设置 */

tcflag_t c_cflag; /* 控制模式设置 */

tcflag_t c_lflag; /* 本地模式 */

cc_t c_cc[NCCS]; /* 控制字符 */


1.4.1 c_iflag

输入模式标志,控制终端输入方式

c_iflag参数表

键 值

说 明

IGNBRK

忽略BREAK键输入

BRKINT

如果设置了IGNBRK,BREAK键输入将被忽略

IGNPAR

忽略​​奇偶校验​​错误

PARMRK

标识奇偶校验错误

INPCK

允许输入​​奇偶校验​​

ISTRIP

去除字符的第8个比特

INLCR

将输入的NL(换行)转换成CR(回车)

IGNCR

忽略输入的回车

ICRNL

将输入的回车转化成换行(如果IGNCR未设置的情况下)

IUCLC

将输入的大写字符转换成小写字符(非​​POSIX​​)

IXON

允许输出时对​​XON/XOFF​​流进行控制

IXANY

输入任何字符将重启停止的输出

IXOFF

允许输入时对​​XON/XOFF​​流进行控制

IMAXBEL

当输入队列满的时候开始响铃


1.4.2 c_oflag

输出模式标志,控制终端输出方式

c_oflag参数:

键 值

说 明

OPOST

处理后输出

OLCUC

将输出的小写字符转换成大写字符(非​​POSIX​​)

ONLCR

将输出的NL(换行)转换成CR(回车)及NL(换行)

OCRNL

将输出的CR(回车)转换成NL(换行)

ONOCR

第一行不输出回车符

ONLRET

不输出回车符

OFILL

发送填充字符以延迟终端输出

OFDEL

​​ASCII​​码的DEL作为填充字符,如果未设置该参数,填充字符为NUL

NLDLY

换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)

CRDLY

回车延迟,取值范围为:CR0、CR1、CR2和 CR3

TABDLY

水平​​制表符​​输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3

BSDLY

空格输出延迟,可以取BS0或BS1

VTDLY

垂直制表符输出延迟,可以取VT0或VT1

FFDLY

换页延迟,可以取FF0或FF1


1.4.3 c_cflag

控制模式标志,指定终端硬件控制信息.

c_cflag参数

键 值

说 明

CBAUD

​​波特率​​​(4+1位)(非​​POSIX​​)

CBAUDEX

附加波特率(1位)(非POSIX)

​​CSIZE​​

数据位长度,取值范围为CS5、CS6、CS7或CS8

例如:

newtio.c_cflag &= ~CSIZE;//清除串口的数据位

newtio.c_cflag |= CS8; //配置串口的数据位为8位

CSTOPB

设置两个停止位

例如:

newtio.c_cflag |= CSTOPB; //配置的停止位:2

newtio.c_cflag &= ~CSTOPB; //配置的停止位:1个

CREAD

使用接收功能

例如: newtio.c_cflag |= CREAD;

PARENB

使用​​奇偶校验​​

例如:

newtio.c_cflag &= ~PARENB 不使用奇偶校验

newtio.c_cflag |= PARENB 使用奇偶校验

PARODD

对输入使用奇偶校验,对输出使用​​偶校验​​

HUPCL

关闭设备时挂起

CLOCAL

忽略调制解调器线路状态

CRTSCTS

使用RTS/CTS​​流控制​​


1.4.4 c_lflag

本地模式标志,控制终端编辑功能

c_lflag参数

键 值

说 明

ISIG

当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号

ICANON

使用标准输入模式.

例如: options.c_lflag &= ~(ICANON ); //不使用规范模式(非标准模式)

options.c_lflag |= ICANON; //使用规范模式 (标准模式)

默认情况下,终端采用的是标准模式,终端收到数据时,是按照行读取的。终端需要收到\n才会返回。

XCASE

在ICANON和XCASE同时设置的情况下,终端只使用大写。

ECHO

显示输入字符

ECHOE

如果ICANON同时设置,​​ERASE​​将删除输入的字符

ECHOK

如果ICANON同时设置,KILL将删除当前行

ECHONL

如果ICANON同时设置,即使ECHO没有设置依然显示​​换行符​​

ECHOPRT

如果ECHO和ICANON同时设置,将删除打印出的字符(非​​POSIX​​)

TOSTOP

向后台输出发送SIGTTOU信号

IGNCR

忽略输入的回车。

例如:

options.c_iflag |= IGNCR; //忽略回车字符

options.c_iflag &= ~ IGNCR; //不忽略回车字符

ICRNL

在输入中将回车转换为换行符(除非设置了IGNCR)

例如:

options.c_iflag |= ICRNL; //在输入中将回车转换为换行符

options.c_iflag &= ICRNL;//不转换


1.4.5 c_cc[NCCS]

​​控制字符​​,用于保存终端驱动程序中的​​特殊字符​​,如输入结束符等。

c_cc支持的控制字符

说 明

说 明

VINTR

Interrupt字符

VEOL

附加的End-of-file字符

VQUIT

Quit字符

​​VTIME​​

非规范模式读取时的超时时间

(单位是百毫秒)

VERASE

Erase字符

VSTOP

Stop字符

VKILL

Kill字符

VSTART

Start字符

VEOF

End-of-file字符

VSUSP

Suspend字符

VMIN

非规范模式读取时的最字符数




在串口编程模式下,open未设置O_NONBLOCK或O_NDELAY的情况下。

c_cc[VTIME]和c_cc[VMIN]映像read函数的返回。

VTIME定义等待的时间,单位是百毫秒(通常是一个8位的unsigned char变量,取值不能大于cc_t)。

VMIN定义了要求等待的最小字节数,这个字节数可能是0。

如果VTIME取0,VMIN定义了要求等待读取的最小字节数。函数read()只有在读取了VMIN个字节的数据或者收到一个信号的时候才返回。

如果VMIN取0,VTIME定义了即使没有数据可以读取,read()函数返回前也要等待几百毫秒的时间量。这时,read()函数不需要像其通常情况那样要遇到一个文件结束标志才返回0。

如果VTIME和VMIN都不取0,VTIME定义的是当接收到第一个字节的数据后开始计算等待的时间量。如果当调用read函数时可以得到数据,计时器马上开始计时。如果当调用read函数时还没有任何数据可读,则等接收到第一个字节的数据后,计时器开始计时。函数read可能会在读取到VMIN个字节 的数据后返回,也可能在计时完毕后返回,这主要取决于哪个条件首先实现。不过函数至少会读取到一个字节的数据,因为计时器是在读取到第一个数据时开始计时的。

如果VTIME和VMIN都取0,即使读取不到任何数据,函数read也会立即返回。同时,返回值0表示read函数不需要等待文件结束标志就返回了。

例如:

newtio.c_cc[VTIME]=1; //表示间隔时间100毫秒. 100毫秒间隔外的数据就认为是新的一帧数据。

newtio.c_cc[VMIN]=10;//表示一次最大读取10个数据,如果接受了100个数据,read函数要读取10次才可以读取完毕,每次读取10个数据。


1.5 终端I/O的两种输入处理模式

Linux系统终端I/O有两种输入处理模式:

(1) 规范方式输入处理。在这种方式中,终端输入以行为单位进行处理。对于每个读要求,终端驱动程序最多返回一行。

(2) 非规范方式输入处理。输入字符不以行为单位进行装配,如果不作特殊处理,则默认方式是规范方式。

想要修改非规范方式输入处理,可以修改c_lflag本地模式选项,将ICANON属性去掉,ICANON就是规范化方式。 例如: options.c_lflag &= ~(ICANON );











举报

相关推荐

0 条评论