1. 简述
Linux串口开发中内置了标准波特率的选项可以满足大部分需求,但是有些特殊的设备的波特率是非标准的(我接触到的有遥控接收机Sbus协议的波特率就为100k),因此需要特殊开发。已有很多方法来解决这个问题,本博客记录使用termios2结构体来配置非标波特率。
测试系统:树莓派4B+Raspberry系统。
注意:本方法包含的<asm-generic/termbits.h>和<termios.h>这两个头文件里都定义了struct termios,需将其中一个注释。
2.代码
Serial.h头文件。
#ifndef SERIAL_H
#define SERIAL_H
#include <string>
using std::string;
int serialOpen(string uart, int baud);
int setSerialOpt(int fd,int nSpeed,int nBits, char nEvent, int nStop);
#endif
Serial.cpp文件
#include "serial.h"
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <asm-generic/termbits.h>
#include <errno.h>
#include <termios.h>
int serialOpen(string uart, int baud)
{
int serialFd;
if((serialFd = open(uart.c_str(), O_RDWR|O_NOCTTY|O_NDELAY|O_NONBLOCK))<0)
{
perror("serialopen failded");
return -1;
}
else
{
if(0 == setSerialOpt(serialFd, baud, 8, 'N', 1))
return serialFd;
else
return -1;
}
}
int setSerialOpt(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios2 newtio,oldtio;
//读出原来的配置信息,按理说之所以读出来,是有部分数据不需要改,但感觉这里是这里对新的结构体配置,也没用到读出来的值
if (0 != ioctl(fd, TCGETS2, &oldtio)) {
close(fd);
fd = -1;
perror("ioctl failded");
return -1;
}
memset(&newtio,0,sizeof(newtio));
//bzero( &newtio, sizeof( newtio ) ); //新结构体清0
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
switch( nBits )
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
/*** 奇偶校验 ***/
switch( nEvent )
{
case 'O':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= INPCK;
break;
case 'E':
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
newtio.c_iflag |= INPCK;
break;
case 'N':
newtio.c_cflag &= ~PARENB;
break;
}
/*** 设置波特率 ***/
switch( nSpeed )
{
case 2400:
case 4800:
case 9600:
case 38400:
case 57600:
case 115200: //标准波特率
newtio.c_cflag |= CBAUDEX;
newtio.c_ispeed = nSpeed;
newtio.c_ospeed = nSpeed;
break;
default: //非标准波特率
newtio.c_cflag |= BOTHER;
newtio.c_ispeed = nSpeed;
newtio.c_ospeed = nSpeed;
break;
}
/*** 设置停止位 ***/
if( nStop == 1 )
newtio.c_cflag &= ~CSTOPB;
else if ( nStop == 2 )
newtio.c_cflag |= CSTOPB;
/*设置等待时间和最小接收字符*/
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 30;
/*处理未接收字符*/
tcflush(fd,TCIFLUSH);
if (0 != ioctl(fd, TCSETS2, &newtio)) {
close(fd);
fd = -1;
perror("ioctl failded");
return -1;
}
return 0;
}