串口是计算机上的串行通信的物理接口。首先先介绍一下串行通信,串行通信的分类:
1、按照数据传送方向,分为:
单工:数据传输只支持数据在一个方向上传输;就像路上的单行线。
半双工:允许数据在两个方向上传输。但是,在某一时刻,只允许数据在一个方向上传输;半双工就像分时段的单行线,上午时段通行这边,下午时段通行另一边,而单工就是全天单行线。
全双工:允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端;全双工就是双向车道。
2、按照通信方式,分为:
同步通信:带时钟同步信号传输。比如:SPI,IIC通信接口。
异步通信:不带时钟同步信号。比如:UART(通用异步收发器),单总线。
在同步通讯中,收发设备上方会使用一根信号线传输信号,在时钟信号的驱动下双方进行协调,在异步通讯中不使用时钟信号进行数据同步,通讯中需要双方规约好数据的传输速率(也就是波特率)等,以便更好地同步。常用的波特率有4800bps、9600bps、115200bps等。
串口通信中通常使用的是异步串行通信
串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。通信使用3根线完成,分别是地线(GND)、发送(TXD)、接收(RXD)。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。
常用的串口接头有两种,一种是9针串口(简称DB-9),一种是25针串口(简称DB-25)。每种接头都有公头和母头之分,其中带针状的接头是公头,而带孔状的接头是母头。
以DB9为例,如图:
母头:泛指所有带孔状的接头(5针朝下,从左到右依次是1~9)
公头:泛指所有带针状的接头(5针朝下,从右到左依次是1~9)
各引脚的定义:
最简单的三线通行就需要到2,3,5接口而已。需要测试串口是否正常时,连接TXD接RXD,RXD接TXD,GND接GND。自己的TXD口接RXD口,自发自收,测试串口是否正常。
DB9和DB25的常用信号脚说明:
pin function name pin function name
DB9 |
DB25 |
1 数据载波检测 DCD |
8 数据载波检测 DCD |
2 接收数据 RXD |
3 接收数据 RXD |
3 发送数据 TXD |
2 发送数据 TXD |
4 数据终端准备 DTR |
20 数据终端准备 DTR |
5 信号地 GND |
7 信号地 GND |
6数据设备准备好DSR |
6 数据设备准备好 DSR |
7 请求发送 RTS |
4 请求发送 RTS |
8 清除发送 CTS |
5 清除发送 CTS |
9 振铃指示 RI |
22 振铃指示 RI |
GND - Logic Ground
从技术角度讲,GND不能算是信号。但是没有它其他信号都不能用了。基本上,logic ground有点像一个参考电压,通过它来判断哪个电压表示正哪个电压表示负。
TXD - Transmitted Data
TXD信号负载着从你的电脑或者设备到另一端的数据。Mark范围的电压被解析成1,而space范围电压被解析成0。
RXD - Received Data
RXD于TXD正好相反。它负载着从另一端的电脑或者设备上传到你的工作站的数据。Mark和space的解析方法于TXD一致。
DCD - Data Carrier Detect
DCD信号通常来自串口连结线的另一端。这条信号线上的space电压表示另一端的电脑或者设备现在已经连接。但是,DCD信号线却不是总可以得到的,有些设备上有这条信号线,而有的则没有。
DTR - Data Terminal Ready
DTR信号是你的工作站产生的,用以告诉另一端的电脑或者设备你已经是否已经准备好了。Space电压表示准备好了,而mark电压表示没有准备好。当你在工作站上打开串行接口时,DTR通常自动被设置位有效。
CTS - Clear To Send
CTS则通常来自连结线的另一端。Space电压表示你可以从工作站送出更多的数据。CTS通常用来协调你的工作站和另一端之间的串行数据流。
RTS - Request To Send
如果RTS信号被设置成space电压,这表示你准备好了一些数据需要传送。和CTS一样,RTS也被用来协调工作站和另一端的电脑或者设备之间的数据流。有些工作站上会一直将这个信号设置位space。
TTL电平:TTL是Transistor-Transistor Logic,即晶体管-晶体管逻辑的简称,它是计算机处理器控制的设备内部各部分之间通信的标准技术。TTL电平信号应用广泛,是因为其数据表示采用二进制规定,+5V等价于逻辑”1”,0V等价于逻辑”0”。
数字电路中,由TTL电子元器件组成电路的电平是个电压范围,规定:
输出高电平>=2.4V,输出低电平<=0.4V;
输入高电平>=2.0V,输入低电平<=0.8V。
RS232电平:RS232电平是串口的一个标准。
在TXD和RXD数据线上:
(1)逻辑1为-3~-15V的电压
(2)逻辑0为3~15V的电压
在RTS、CTS、DSR、DTR和DCD等控制线上:
(1)信号有效(ON状态)为3~15V的电压
(2)信号无效(OFF状态)为-3~-15V的电压
这是由通信协议RS-232规定的。
RS-232:标准串口,最常用的一种串行通讯接口。有三种类型(A,B和C),它们分别采用不同的电压来表示on和off。最被广泛使用的是RS-232C,它将mark(on)比特的电压定义为-3V到-12V之间,而将space(off)的电压定义到+3V到+12V之间。传送距离最大为约15米,最高速率为20kb/s。RS-232是为点对点(即只用一对收、发设备)通讯而设计的,其驱动器负载为3~7kΩ。所以RS-232适合本地设备之间的通信。
如果用的电平不一致也会导致通信双方通信不上,例如cpu出来的电平有可能就需要转换才能进行串口通信。
起始位:接收方探测, 默认总线空闲时是高电平,一旦来一个位的低电平,说明一帧数据开始了。紧接着就是数据位,一帧数据有多少个数据位,由通信双方定义。
数据位: 5, 6,7, 8, 一般是8个位。
校验位:数据位发完了,一般会跟奇偶校验位(奇校验、偶校验、无校验),验证收发双方的数据是否正常。
奇校验: 数据位加上校验位保证1的个数为奇数;
偶校验: 数据位加上校验位保证1的个数为偶数;
停止位:数据发完之后,会发一个停止位,停止位的宽度一般是: 1, 1.5, 2
空闲位:空闲位是指从一个字符的停止位结束到下一个字符的起始位开始,表示线路处于空闲状态,必须由高电平来填充。
主要流程 :1、open打开串口设备,获取串口设备文件描述符(Linux一切都是文件~)-->2、设置波特率、数据位、停止位、校验位等-->3、read()、write()操作文件描述符进行串口通信-->4、close()关闭设备
串口驱动的默认属性值(9600,8n1,无流控),最重要的同时也是最复杂的就是第二步串口的设置,所以先说open()、read()、write()、close()对串口的操作。
串口操作需要用到的头文件:
#include /*标准输入输出定义*/
#include /*标准函数库定义*/
#include /*Unix 标准函数定义*/
#include
#include
#include /*文件控制定义*/
#include /*POSIX 终端控制定义*/
#include /*错误号定义*/
#include /*字符串功能函数*/
跟打开其他文件一样,只不过可能会加上O_NOCTTY这两个选项O_NDELAY。
fd = open("/dev/ttyUSB0",O_RDWR|O_NOCTTY|O_NDELAY);
可采用下面的文件打开模式:
O_RDONLY:以只读方式打开文件
O_WRONLY:以只写方式打开文件
O_RDWR:以读写方式打开文件
(O_RDONLY和O_WRONLY和O_RDWR三个中必选一个)
O_APPEND:写入数据时添加到文件末尾
O_CREATE:如果文件不存在则产生该文件,使用该标志需要设置访问权限位mode_t
O_EXCL:指定该标志,并且指定了O_CREATE标志,如果打开的文件存在则会产生一个错误
O_TRUNC:如果文件存在并且成功以写或者只写方式打开,则清除文件所有内容,使得文件长度变为0
O_NOCTTY:如果打开的是一个终端设备,这个程序不会成为对应这个端口的控制终端,如果没有该标志,任何一个输入,例如键盘中止信号等,都将影响进程。
O_NONBLOCK:该标志与早期使用的O_NDELAY标志作用差不多。程序不关心DCD信号线的状态,如果指定该标志,进程将一直在休眠状态,直到DCD信号线为0。
写入数据也很简单,使用write就可以发送数据了:
write(fd, W_BUF, strlen(W_BUF));
和写入其他设备文件的方式相同,write函数也会返回发送数据的字节数或者在发生错误的时候返回-1。通常,发送数据最常见的错误就是EIO,当调制解调器或者数据链路将Data Carrier Detect(DCD)信号线弄掉了,就会发生这个错误。而且,直至关闭端口这个情况会一直持续。
read(fd,r_buf,sizeof(r_buf));
和读其他文件操作方式也一样,但是需要注意的是!从串口上读取数据的时候就得耍花招了。因为,如果你在原数据模式(raw data mode)操作端口的话,每个read(2)系统调用都会返回从串口输入缓冲区中实际得到的字符的个数。在不能得到数据的情况下,read(2)系统调用就会一直等着,只到有端口上新的字符可以读取或者发生超时或者错误的情况发生。如果需要read(2)函数迅速返回的话,你可以使用下面这个方式:
fcntl(fd, F_SETFL, FNDELAY);
标志FNDELAY可以保证read(2)函数在端口上读不到字符的时候返回0。需要回到正常(阻塞)模式的时候,需要再次在不带FNDELAY标志的情况下调用fcntl(2)函数:
fcntl(fd, F_SETFL, 0);
当然,如果你最初就是以O_NDELAY标志打开串口的,你也可在之后使用这个方法改变读取的行为方式。最好还是设置好串口属性之后再进行读写操作
很多系统都支持POSIX终端(串口)接口.程序可以利用这个接口来改变终端的参数,比如,波特率,字符大小等等.要使用这个端口的话,你必须将
设置串口属性先要tcgetattr()用来取得设备终端属性,然后中间设置波特率,设置停止位,校验位,数据位等,最后用tcsetattr()设置终端的属性。调用这两个函数的时候,需要提供一个包含着所有串口选项的termios结构体:
struct termios
{
tcflag_t c_iflag; //输入选项
tcflag_t c_oflag; //输出选项
tcflag_t c_cflag; //控制选项
tcflag_t c_lflag; //行选项
cc_t c_cc[NCCS]; //控制字符
};
通过termios结构体的c_cflag成员可以控制波特率,数据的比特数,parity,停止位和硬件流控制。下面这张表列出了所有可以使用的常数。
c_cflag常数
常量 |
描述 |
CBAUD |
Bit mask for baud rate |
B0 |
0 baud (drop DTR) |
B50 |
50 baud |
B75 |
75 baud |
B110 |
110 baud |
B134 |
134.5 baud |
B150 |
150 baud |
B200 |
200 baud |
B300 |
300 baud |
B600 |
600 baud |
B1200 |
1200 baud |
B1800 |
1800 baud |
B2400 |
2400 baud |
B4800 |
4800 baud |
B9600 |
9600 baud |
B19200 |
19200 baud |
B38400 |
38400 baud |
B57600 |
57,600 baud |
B76800 |
76,800 baud |
B115200 |
115,200 baud |
EXTA |
External rate clock |
EXTB |
External rate clock |
CSIZE |
Bit mask for data bits |
CS5 |
5 data bits |
CS6 |
6 data bits |
CS7 |
7 data bits |
CS8 |
8 data bits |
CSTOPB |
2 stop bits (1 otherwise) |
CREAD |
Enable receiver |
PARENB |
Enable parity bit |
PARODD |
Use odd parity instead of even |
HUPCL |
Hangup (drop DTR) on last close |
CLOCAL |
Local line - do not change "owner" of port |
LOBLK |
Block job control output |
CNEW_RTSCTS/CRTSCTS |
Enable hardware flow control (not supported on all platforms) |
使用函数cfsetispeed设置输入波特率和cfsetospeed设置输出波特率
struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);
options.c_cflag | = CLOCAL | CREAD;
数据位指的是每字节中实际数据所占的比特数。要修改数据位可以通过修改termios结构体中c_cflag成员来实现。CS5、CS6、CS7和CS8分别表示数据位为5、6、7和8。值得注意的是,在设置数据位时,必须先使用CSIZE做位屏蔽。
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
奇偶校验可以选择偶校验、奇校验等方式,也可以不使用校验。如果要设置为偶校验的话,首先要将termios结构体中c_cflag设置PARENB标志,并清除PARODD标志。如果要设置奇校验,要同时设置termios结构体中c_cflag设置PARENB标志和PARODD标志。激活c_iflag中的奇偶效验使能,如果不想使用任何校验的话,清除termios结构体中c_cflag的PARENB位。
设置奇校验:
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_iflag |= (INPCK | ISTRIP); //INPCK 打开输入奇偶校验,ISTRIP 去掉字符第8位
设置偶校验:
options.c_iflag |= (INPCK|ISTRIP);
options.c_cflag |= PARENB;
options.c_cflag |= ~PARODD;
无校验位:
options.c_cflag &= ~PARENB;
用CSTOPB只能设置1位或2位,通过设置c_cflag中的CSTOPB设置停止位。若停止位为1,则清除CSTOPB;若停止位为2,则激活CSTOPB。
一位停止位:
options.c_cflag &= ~CSTOPB;
两位停止位:
options.c_cflag |= CSTOPB;
在对接收字符和等待时间没有特别要求的情况下,可以将其设置为0。
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;
queue_selector可能的取值有以下几种。
TCIFLUSH:刷新收到的数据但是不读
TCOFLUSH:刷新写入的数据但是不传送
TCIOFLUSH:同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送。
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
第一个参数:fd为打开的终端文件描述符
第二个参数:optional_actions用于控制修改起作用的时间,
第三个参数:结构体termios_p中保存了要修改的参数。
optional_actions可以取如下的值:
TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:等待所有数据传输结束,清空输入输出缓冲区才改变属性。
错误信息:
EBADF:非法的文件描述符。
EINTR:tcsetattr函数调用被信号中断。
EINVAL:参数optional_actions使用了非法值,或参数termios中使用了非法值。
ENOTTY:非终端的文件描述符。
RETURN VALUE
cfgetispeed() returns the input baud rate stored in the termios structure.
cfgetospeed() returns the output baud rate stored in the termios structure.
All other functions return:
0 on success.
-1 on failure and set errno to indicate the error.
Note that tcsetattr() returns success if any of the requested changes could be successfully carried out. Therefore, when making multiple changes it may be necessary to follow this call with a further call to tcgetattr() to check that all changes have been performed successfully.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
int tty_fd = -1 ;
int rv = -1 ;
char r_buf[128] ;
struct termios options;
fd_set rset;
tty_fd = open("/dev/ttyUSB0",O_RDWR|O_NOCTTY|O_NDELAY) ; //打开串口设备
if(tty_fd < 0)
{
printf("open tty failed:%s\n", strerror(errno)) ;
goto cleanup ;
}
printf("open devices sucessful!\n") ;
memset(&options, 0, sizeof(options)) ;
rv = tcgetattr(tty_fd, &options); //获取原有的串口属性的配置
if(rv != 0)
{
printf("tcgetattr() failed:%s\n",strerror(errno)) ;
goto cleanup ;
}
options.c_cflag|=(CLOCAL|CREAD ); // CREAD 开启串行数据接收,CLOCAL并打开本地连接模式
options.c_cflag &=~CSIZE;// 先使用CSIZE做位屏蔽
options.c_cflag |= CS8; //设置8位数据位
options.c_cflag &= ~PARENB; //无校验位
/* 设置115200波特率 */
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag &= ~CSTOPB;/* 设置一位停止位; */
options.c_cc[VTIME] = 0;/* 非规范模式读取时的超时时间;*/
options.c_cc[VMIN] = 0; /* 非规范模式读取时的最小字符数*/
tcflush(tty_fd ,TCIFLUSH);/* tcflush清空终端未完成的输入/输出请求及数据;TCIFLUSH表示清空正收到的数据,且不读取出来 */
if((tcsetattr(tty_fd, TCSANOW,&options))!=0)
{
printf("tcsetattr failed:%s\n", strerror(errno));
goto cleanup ;
}
while(1)
{
FD_ZERO(&rset) ;
FD_SET(tty_fd, &rset) ;
rv = select(tty_fd+1, &rset, NULL, NULL, NULL) ;
if(rv < 0)
{
printf("select() failed: %s\n", strerror(errno)) ;
goto cleanup ;
}
if(rv == 0)
{
printf("select() time out!\n") ;
goto cleanup ;
}
memset(r_buf, 0, sizeof(r_buf)) ;
rv = read(tty_fd, r_buf, sizeof(r_buf)) ;
if(rv < 0)
{
printf("Read() error:%s\n",strerror(errno)) ;
goto cleanup ;
}
printf("Read from tty: %s\n",r_buf) ;
}
cleanup:
close(tty_fd) ;
return 0 ;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define W_BUF "WuYuJun<540726307@qq.com>"
int main(int argc, char **argv)
{
int tty_fd = -1 ;
int rv = -1 ;
struct termios options;
tty_fd = open("/dev/ttyUSB0",O_RDWR|O_NOCTTY|O_NDELAY) ; //打开串口设备
if(tty_fd < 0)
{
printf("open tty failed:%s\n", strerror(errno)) ;
goto cleanup ;
}
printf("open devices sucessful!\n") ;
memset(&options, 0, sizeof(options)) ;
rv = tcgetattr(tty_fd, &options); //获取原有的串口属性的配置
if(rv != 0)
{
printf("tcgetattr() failed:%s\n",strerror(errno)) ;
goto cleanup ;
}
options.c_cflag|=(CLOCAL|CREAD ); // CREAD 开启串行数据接收,CLOCAL并打开本地连接模式
options.c_cflag &=~CSIZE;// 先使用CSIZE做位屏蔽
options.c_cflag |= CS8; //设置8位数据位
options.c_cflag &= ~PARENB; //无校验位
/* 设置115200波特率 */
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag &= ~CSTOPB;/* 设置一位停止位; */
options.c_cc[VTIME] = 0;/* 非规范模式读取时的超时时间;*/
options.c_cc[VMIN] = 0; /* 非规范模式读取时的最小字符数*/
tcflush(tty_fd ,TCIFLUSH);/* tcflush清空终端未完成的输入/输出请求及数据;TCIFLUSH表示清空正收到的数据,且不读取出来 */
if((tcsetattr(tty_fd, TCSANOW,&options))!=0)
{
printf("tcsetattr failed:%s\n", strerror(errno));
goto cleanup ;
}
while(1)
{
rv = write(tty_fd, W_BUF,strlen(W_BUF)) ;
if(rv < 0)
{
printf("Write() error:%s\n",strerror(errno)) ;
goto cleanup ;
}
sleep(3) ;
}
cleanup:
close(tty_fd) ;
return 0 ;
}
写串口程序运行向串口写数据:
读串口程序运行从串口中读取数据:
上面只是简单的串口通信,串口属性还有很多可以设置的,下面转载别人博客上的Linux串口编程详解:https://www.cnblogs.com/jimmy1989/p/3545749.html
某些版本的UNIX系统支持通过CTS(Clear To Send)和RTS(Request To Send)信号线来设置硬件流控制。如果系统上定义了CNEW_RTSCTS和CRTSCTS常量,那么很可能它会支持硬件流控制。使用下面的方法将硬件流控制设置成有效:
options.c_cflag |= CNEW_RTSCTS; /* Also called CRTSCTS
将它设置成为无效的方法与此类似:
options.c_cflag &= ~CNEW_RTSCTS;
本地模式成员变量c_lflag可以控制串口驱动怎样控制输入字符。通常,你可能需要通过c_lflag成员来设置经典输入和原始输入模式。
成员变量c_lflag可以使用的常量
ISIG |
Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals |
ICANON |
Enable canonical input (else raw) |
XCASE |
Map uppercase \lowercase (obsolete) |
ECHO |
Enable echoing of input characters |
ECHOE |
Echo erase character as BS-SP-BS |
ECHOK |
Echo NL after kill character |
ECHONL |
Echo NL |
NOFLSH |
Disable flushing of input buffers after interrupt or quit characters |
IEXTEN |
Enable extended functions |
ECHOCTL |
Echo control characters as ^char and delete as ~? |
ECHOPRT |
Echo erased character as character erased |
ECHOKE |
BS-SP-BS entire line on line kill |
FLUSHO |
Output being flushed |
PENDIN |
Retype pending input at next read or input char |
TOSTOP |
Send SIGTTOU for background output |
可以通过输入模式成员c_iflag来控制从端口上收到的字符的输入过程。与c_cflag一样,c_iflag的最终值是想要使用的所有状态的位运算OR的组合。
c_iflag成员可以使用的常量
常量 |
描述 |
INPCK |
Enable parity check |
IGNPAR |
Ignore parity errors |
PARMRK |
Mark parity errors |
ISTRIP |
Strip parity bits |
IXON |
Enable software flow control (outgoing) |
IXOFF |
Enable software flow control (incoming) |
IXANY |
Allow any character to start flow again |
IGNBRK |
Ignore break condition |
BRKINT |
Send a SIGINT when a break condition is detected |
INLCR |
Map NL to CR |
IGNCR |
Ignore CR |
ICRNL |
Map CR to NL |
IUCLC |
Map uppercase to lowercase |
IMAXBEL |
Echo BEL on input line too long |
成员变量c_oflag之中包括了输出过滤选项。和输入模式相似,程序可以选择使用经过加工的或者原始的数据输出。
c_oflag成员的常量
常量 |
描述 |
OPOST |
Postprocess output (not set = raw output) |
OLCUC |
Map lowercase to uppercase |
ONLCR |
Map NL to CR-NL |
OCRNL |
Map CR to NL |
NOCR |
No CR output at column 0 |
ONLRET |
NL performs CR function |
OFILL |
Use fill characters for delay |
OFDEL |
Fill character is DEL |
NLDLY |
Mask for delay time needed between lines |
NL0 |
No delay for NLs |
NL1 |
Delay further output after newline for 100 milliseconds |
CRDLY |
Mask for delay time needed to return carriage to left column |
CR0 |
No delay for CRs |
CR1 |
Delay after CRs depending on current column position |
CR2 |
Delay 100 milliseconds after sending CRs |
CR3 |
Delay 150 milliseconds after sending CRs |
TABDLY |
Mask for delay time needed after TABs |
TAB0 |
No delay for TABs |
TAB1 |
Delay after TABs depending on current column position |
TAB2 |
Delay 100 milliseconds after sending TABs |
TAB3 |
Expand TAB characters to spaces |
BSDLY |
Mask for delay time needed after BSs |
BS0 |
No delay for BSs |
BS1 |
Delay 50 milliseconds after sending BSs |
VTDLY |
Mask for delay time needed after VTs |
VT0 |
No delay for VTs |
VT1 |
Delay 2 seconds after sending VTs |
FFDLY |
Mask for delay time needed after FFs |
FF0 |
No delay for FFs |
FF1 |
Delay 2 seconds after sending FFs |
字符数组c_cc里面包括了控制字符的定义和超时参数。这个数组的每个元素都是以常量定义的。
成员变量c_cc中的控制字符
常量 |
描述 |
键 |
VINTR |
Interrupt |
CTRL-C |
VQUIT |
Quit |
CTRL-Z |
VERASE |
Erase |
Backspace (BS) |
VKILL |
Kill-line |
CTRL-U |
VEOF |
End-of-file |
CTRL-D |
VEOL |
End-of-line |
Carriage return (CR) |
VEOL2 |
Second end-of-line |
Line feed (LF) |
VMIN |
Minimum number of characters to read |
- |
VSTART |
Start flow |
CTRL-Q (XON) |
VSTOP |
Stop flow |
CTRL-S (XOFF) |
VTIME |
Time to wait for data (tenths of seconds) |
- |
所谓高级串口编程其实说的就是使用更直接的底层的ioctl(2)和select(2)系统调用来操作串口。
前文中曾经提到使用tcgetattr和tcsetattr函数来配置串口。UNIX环境下,这些函数都是使用ioctl(2)系统调用来实现的。
系统调用ioctl可以带三个参数:
int ioctl(int fd, int request, ...);
显然,fd参数对于串口编程来说就是串口设备文件的文件描述符咯。而request参数是在
串口的IOCTL请求
REQUEST |
描述 |
POSIX函数 |
TCGETS |
Gets the current serial port settings. |
tcgetattr |
TCSETS |
Sets the serial port settings immediately. |
tcsetattr(fd, TCSANOW, &options) |
TCSETSF |
Sets the serial port settings after flushing the input and output buffers. |
tcsetattr(fd, TCSAFLUSH, &options) |
TCSETSW |
Sets the serial port settings after allowing the input and output buffers to drain/empty. |
tcsetattr(fd, TCSADRAIN, &options) |
TCSBRK |
Sends a break for the given time. |
tcsendbreak, tcdrain |
TCXONC |
Controls software flow control. |
tcflow |
TCFLSH |
Flushes the input and/or output queue. |
tcflush |
TIOCMGET |
Returns the state of the "MODEM" bits. |
None |
TIOCMSET |
Sets the state of the "MODEM" bits. |
None |
FIONREAD |
Returns the number of bytes in the input buffer. |
None |
TIOCMGET ioctl可以取得当前调制解调器的状态位。这个状态位囊括了除去RXD和TXD信号线的所有RS-232信号,这些都在下表中列出。
控制信号常量
常量 |
描述 |
TIOCM_LE |
DSR (data set ready/line enable) |
TIOCM_DTR |
DTR (data terminal ready) |
TIOCM_RTS |
RTS (request to send) |
TIOCM_ST |
Secondary TXD (transmit) |
TIOCM_SR |
Secondary RXD (receive) |
TIOCM_CTS |
CTS (clear to send) |
TIOCM_CAR |
DCD (data carrier detect) |
TIOCM_CD |
Synonym for TIOCM_CAR |
TIOCM_RNG |
RNG (ring) |
TIOCM_RI |
Synonym for TIOCM_RNG |
TIOCM_DSR |
DSR (data set ready) |
例如下面这个程序片段,你可以通过给ioctl带一个用来保存状态位的整形变量的指针来取得状态位。
#include
#include
int fd;
int status;
ioctl(fd, TIOCMGET, &status);
设置控制信号
TIOCMSET ioctl可以设置上面定义的调制解调器状态位。下面的例子展示如何使用它来将DTR信号线设成掉线状态。
#include
#include
int fd;
int status;
ioctl(fd, TIOCMGET, &status);
status &= ~TIOCM_DTR;
ioctl(fd, TIOCMSET, &status);
可能被设置的状态位取决于操作系统,驱动和正在使用的模式。关于更详细的信息应该去看以下你所使用的操作系统的文档。
Linux串口编程详解转载至:https://www.cnblogs.com/jimmy1989/p/3545749.html
参考:https://blog.csdn.net/baweiyaoji/article/details/72885633
https://blog.csdn.net/Shallwen_Deng/article/details/89482502