Linux下串口配置初步探寻

2021-02-20 16:35发布

一、在struct termios结构体中,对串口进行基本配置(如波特率设置,校验位和停止位设置 等)。

):

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 控制字符数组
      }; 

1c_cflag代表控制模式

CLOCAL含义为忽略所有调制解调器的状态行,这个目的是为了保证程序不会占用串口。CREAD代表启用字符接收器,目的是是的能够从串口中读取输入的数据。

CS5/6/7/8表示发送或接收字符时使用5/6/7/8比特。

CSTOPB表示每个字符使用两位停止位。

HUPCL表示关闭时挂断调制解调器。

PARENB:启用奇偶校验码的生成和检测功能。

PARODD只使用奇校验而不使用偶校验。

2c_iflag代表输入模式。

BRKINT:当在输入行中检测到一个到一个终止状态时,产生一个中断。

TGNBRK:忽略输入行中的终止状态。

TCRNL:将接受到的回车符转换为新行符。

TGNCR:忽略接受到的新行符。

INLCR:将接受到的新行符转换为回车符。

IGNPAR:忽略奇偶校检错误的字符。

INPCK:对接收到的字符执行奇偶校检。

PARMRK:对奇偶校检错误作出标记。

ISTRIP:将所有接收的字符裁减为7比特。

IXOFF:对输入启用软件流控。

IXON:对输出启用软件流控。

3c_cc特殊的控制字符。

标准模式和非标准模式下,c_cc数组的下标有不同的值:

1)标准模式:

VEOF:EOF字符

VEOL:EOF字符

VERASE:ERASE字符

VINTR:INTR字符

VKILL:KILL字符

VQUIT:QUIT字符

VSTART:START字符

VSTOP:STOP字符

(2)非标准模式:

VINTR:INTR字符

VMIN:MIN

VQUIT:QUIT字符

VSUSP:SUSP字符

VTIME:TIME

VSTART:START字符

 VSTOP:STOP字符

):其中,通过对c_cflag赋值,可以设置波特率、字符大小、数据位、停止位、奇偶校验位和硬件流控等。

程序例如:

struct termios options;  // 串口配置结构体
tcgetattr(fd,&options); //获取当前设置
bzero(&options,sizeof(options));
options.c_cflag  |= B115200 | CLOCAL | CREAD; // 设置波特率,本地连接,接收使能
options.c_cflag &= ~CSIZE; //屏蔽数据位
options.c_cflag  |= CS8; // 数据位为 8 ,CS7 for 7
options.c_cflag &= ~CSTOPB; // 一位停止位, 两位停止为 |= CSTOPB
options.c_cflag &= ~PARENB; // 无校验
 //options.c_cflag |= PARENB; //有校验
//options.c_cflag &= ~PARODD // 偶校验
//options.c_cflag |=  PARODD    // 奇校验

options.c_cc[VTIME] = 0; // 等待时间,单位百毫秒

//************************************************************************************

没满足条件或读缓冲区中剩下的数据会在0百毫秒后读出。另外特别注意的是当设置VTIME后,如果read第三个参数小于VMIN ,将会将VMIN 修改为read的第三个参数,即使用read(fd,&buf,m);,以设置变为:options.c_cc[VMIN] = m;

************************************************************************************//
options.c_cc[VMIN] = 0; // 最小字节数

//************************************************************************************

1VMIN = 0,当缓冲区字节数 >= 0 时进行读操作,实际上这时读串口操作并未被阻塞,因为条件始终被满足。

2VMIN = 1,当缓冲区字节数 >= 1 时进行读操作,当没有数据时读串口操作被阻塞。

3VMIN = 4,当缓冲区字节数 >= 4 时进行读操作,否则读串口操作被阻塞。每次读出的最大字节数由read函数中第三个参数决定。直到缓冲区剩下的数据< read 第三个参数 并且< 4 (如果这时read第三参数为 1 则进行4次读操作直至读完缓冲区,如read第三参数为2,连续进行读操作,直至缓冲区空或还剩一个字符)。

4没有设置VTIME,剩下的字符没有确定的期限,直到下次满足读条件的时候才被读出。

***********************************************************************************//
tcflush(fd, TCIOFLUSH);

// TCIFLUSH刷清输入队列。
                                       //TCOFLUSH刷清输出队列。 
                                       //TCIOFLUSH刷清输入、输出队列。
tcsetattr(fd, TCSANOW, &options);

// TCSANOW立即生效;
                                    //TCSADRAIN:Wait until everything has been transmitted;
                                  //TCSAFLUSH:Flush input and output buffers and make the change

上述中,在设置波特率时需要在数字前加上'B'。程序例:

cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);

二、对串口进行操作。串口是一个终端设备

(一)操作命令如下:

打开串口:fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);

O_RDWR 读写方式打开;
O_NOCTTY 不允许进程管理串口;通知linix系统,这个程序不会成为这个端口的控 制终端。
 O_NDELAY 非阻塞(默认为阻塞,打开后也可以使用fcntl()重新设置)通知Linux 系统不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。

写入串口n = write(fd, "linux", 5);
                 n实际写入字节数;

读取串口res = read(fd,buf,len);
                 res 读取的字节数;

设置串口fcntl(fd, F_SETFL, FNDELAY); //非阻塞
                 fcntl(fd, F_SETFL, 0); // 阻塞

关闭串口close(fd);

(二)总体上:

1、在创建的函数open_port()中要实现的函数:

程序例如:

(1)open("/dev/ttys0",O_RDWR | O_NOCTTY | O_NDELAY);/*打开串口0*/
(2)fcntl(fd,F_SETFL,0)/*恢复串口为阻塞状态*/
(3)isatty(STDIN_FILENO) /*测试是否为中断设备 非0即是中断设备*/

2配置串口参数函数set_opt()中要实现的函数:
(1)保存原先有串口配置
tcgetattr(fd,&oldtio);

(2)先将新串口配置清0
bzore(&newtio,sizeof(newito));

(3)激活选项CLOCAL和CREAD 用于本地连接和接收使用

newtio.c_cflag |=CLOCAL | CREAD;

(4)并设置数据位大小 需使用掩码设置
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |=CS8;

(5)设置奇偶校验
奇校验:
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
偶校验:
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PAREND;
newtio.c_cflag &= ~PARODD;
无奇偶校验:
newtio.c_cflag &= ~PARENB;

(6) 设置停止位通过激活c_cflag中的CSTOPB实现。若停止位为1,则清除CSTOPB,若停止位为2,则激活CSTOPB。
newtio.c_cflag &= ~CSTOPB; /*停止位为1*/
newtio.c_cflag |= CSTOPB;/*停止位为0*/

(7)设置波特率:
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);

(8)设置等待时间和最小接受字符对于接收字符和等待时间没有特别的要求时,可设为0:
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;

(9)处理为接收字符处理要写入的引用对象)。tcflush函数刷清(抛弃)输入缓存(终端驱动程序已接收到,但用户程序尚未读)或输出缓存(用户程序已经写,但尚未发送).
tcflush(fd,TCIFLUSH);

//  TCIFLUSH  刷清输入队列刷新收到的数据但是不读

   //  TCOFLUSH  刷清输出队列刷新写入的数据但是不传送

   //  TCIOFLUSH 刷清输入、输出队列同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送。

(10)激活新配置:
tcsetattr(fd,TCSANOW,&newtio);
3读写串口
write(fd,buff,8);
read(fd,buff,8);

(三)另外:

1、获取文件的flags,即open函数的第二个参数:

       flags = fcntl(fd,F_GETFL,0);

2、设置文件的flags:

      fcntl(fd,F_SETFL,flags);

3、增加文件的某个flags,比如文件是阻塞的,想设置成非阻塞:

       flags = fcntl(fd,F_GETFL,0);

       flags |= O_NONBLOCK;

      fcntl(fd,F_SETFL,flags);

4、取消文件的某个flags,比如文件是非阻塞的,想设置成为阻塞:

      flags = fcntl(fd,F_GETFL,0);

      flags &= ~O_NONBLOCK;

      fcntl(fd,F_SETFL,flags);

 

标签: