串口初始化配置
2019-07-13 04:53发布
生成海报
在基于AT91的嵌入式linux中接收串口数据时,发现对于接收的数据经常出现接收不完整的现象。一帧的数据可能会被当做两帧接收,导致对于一帧数据接收出现问题。虽然这种情况在一般情况下,并不是经常出现,但是只要数据量稍微大一些,情况就会出现。
于是仔细看了程序中关于串口配置这一块的程序,
[cpp] view
plain copy
-
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
-
{
-
struct termios oldtio;
-
struct termios newtio;
-
-
if( tcgetattr(fd, &oldtio) != 0) {
-
perror("SetupSerial 1");
-
return -1;
-
}
-
-
bzero( &newtio, sizeof( newtio ));
-
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_iflag |= INPCK ;
-
newtio.c_cflag |= PARENB;
-
newtio.c_cflag &= ~PARODD;
-
break;
-
case 'N':
-
newtio.c_cflag &= ~PARENB;
-
break;
-
}
-
-
switch( nSpeed )
-
{
-
case 2400:
-
cfsetispeed(&newtio, B2400);
-
cfsetospeed(&newtio, B2400);
-
break;
-
case 4800:
-
cfsetispeed(&newtio, B4800);
-
cfsetospeed(&newtio, B4800);
-
break;
-
case 9600:
-
cfsetispeed(&newtio, B9600);
-
cfsetospeed(&newtio, B9600);
-
break;
-
case 115200:
-
cfsetispeed(&newtio, B115200);
-
cfsetospeed(&newtio, B115200);
-
break;
-
case 460800:
-
cfsetispeed(&newtio, B460800);
-
cfsetospeed(&newtio, B460800);
-
break;
-
default:
-
cfsetispeed(&newtio, B9600);
-
cfsetospeed(&newtio, B9600);
-
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] = 1;
-
-
tcflush(fd,TCIFLUSH);
-
if((tcsetattr(fd,TCSANOW,&newtio))!=0)
-
{
-
perror("com set error");
-
return -1;
-
}
-
-
tcflush(fd,TCIFLUSH);
-
return 0;
-
}
在分析完程序后发现可能导致出问题的地方:在使用oldtio读取串口配置后,却没有将其复制给newtio,并且将newtio清零,这造成下边的设置操作,修改了一些原来的设置。
根据程序修改VTIME,VMIN可推知这里要使用非规范方式,
根据APUE可知由VTIME,VMIN的设置共可以有四种选择
A:VTIME > 0, VMIN > 0
B: VTIME = 0, VMIN > 0
C: VTIME > 0, VMIN = 0
D: VTIME = 0, VMIN = 0
由程序修改的值
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 1;
可知这里要设置为第二种方式:只有接收到MIN个字节数据,read才返回;否则,read将阻塞。
因为这里没有将oldtio复制给newtio所以这里的ICANON标识一定没有设置,所以是处于非规范模式下。这里的VTIME, VMIN对这里的设置也是有效的。
但是这样难免修改一些我们没有注意的选项,根据这里的设置,结合APUE中的示例程序,发现APUE中将终端设置为原始模式(raw modle)与这里的设置较为相似,于是想采用APUE中的部分参数设置,来修改此处的程序。
==================APUE中 put terminal into a raw modle ===========================
[cpp] view
plain copy
-
int
-
tty_raw(int fd)
-
{
-
int err;
-
struct termios buf;
-
-
-
if (ttystate != RESET) {
-
errno = EINVAL;
-
return(-1);
-
}
-
if (tcgetattr(fd, &buf) < 0)
-
return(-1);
-
save_termios = buf;
-
-
-
-
-
-
buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
-
-
-
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮