Linux串口编程

一、串口通信介绍

串口是计算机上的串行通的物理接口。首先先介绍一下串行通信,串行通信的分类:

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

空闲位:空闲位是指从一个字符的停止位结束到下一个字符的起始位开始,表示线路处于空闲状态,必须由高电平来填充。

四、Linux串口编程

主要流程 :1、open打开串口设备,获取串口设备文件描述符(Linux一切都是文件~)-->2、设置波特率、数据位、停止位、校验位等-->3、read()、write()操作文件描述符进行串口通信-->4、close()关闭设备

串口驱动的默认属性值(9600,8n1,无流控),最重要的同时也是最复杂的就是第二步串口的设置,所以先说open()、read()、write()、close()对串口的操作。

串口操作需要用到的头文件

#include     <stdio.h>      /*标准输入输出定义*/

#include     <stdlib.h>     /*标准函数库定义*/

#include     <unistd.h>     /*Unix 标准函数定义*/

#include     <sys/types.h> 

#include     <sys/stat.h>  

#include     <fcntl.h>      /*文件控制定义*/

#include     <termios.h>    /*POSIX 终端控制定义*/

#include     <errno.h>      /*错误号定义*/

#include   <string.h>       /*字符串功能函数*/

打开串口设备:

跟打开其他文件一样,只不过可能会加上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终端(串口)接口.程序可以利用这个接口来改变终端的参数,比如,波特率,字符大小等等.要使用这个端口的话,你必须将<termios.h>头文件包含到你的程序中。这个头文件中定义了终端控制结构体和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);

通过位掩码的方式激活本地连接和接受使能选项:CLOCAL和CREAD

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;

调用函数”tcflush(fd,queue_selector)”来处理要写入引用的对象

queue_selector可能的取值有以下几种。

TCIFLUSH:刷新收到的数据但是不读

TCOFLUSH:刷新写入的数据但是不传送

TCIOFLUSH:同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送。

最后tcsetattr()设置终端的属性

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:非终端的文件描述符。

五、Linux串口编程通信代码

设置串口属性所用到的函数的返回值:

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 <stdio.h>

#include <string.h>

#include <errno.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <termios.h>

#include <unistd.h>

#include <sys/select.h>


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 <stdio.h>

#include <string.h>

#include <errno.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <termios.h>

#include <unistd.h>


#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)系统调用来操作串口。

串口的ioctl 

前文中曾经提到使用tcgetattr和tcsetattr函数来配置串口。UNIX环境下,这些函数都是使用ioctl(2)系统调用来实现的。

系统调用ioctl可以带三个参数:

int ioctl(int fd, int request, ...);

显然,fd参数对于串口编程来说就是串口设备文件的文件描述符咯。而request参数是在<termios.h>头文件中定义的常量,而且一般不会超出下表所列的范围。

串口的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 <unistd.h>

#include <termios.h>

int fd;

int status;

ioctl(fd, TIOCMGET, &status);

设置控制信号 

TIOCMSET ioctl可以设置上面定义的调制解调器状态位。下面的例子展示如何使用它来将DTR信号线设成掉线状态。

#include <unistd.h>

#include <termios.h>



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

  • 64
    点赞
  • 413
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值