串口初始化配置(备忘)
来源:互联网 发布:安神助眠的药 知乎 编辑:程序博客网 时间:2024/06/06 03:25
在基于AT91的嵌入式linux中接收串口数据时,发现对于接收的数据经常出现接收不完整的现象。一帧的数据可能会被当做两帧接收,导致对于一帧数据接收出现问题。虽然这种情况在一般情况下,并不是经常出现,但是只要数据量稍微大一些,情况就会出现。
于是仔细看了程序中关于串口配置这一块的程序,
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);//The `tcflush' function is used to clear the input and/or output 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 ===========================
inttty_raw(int fd) /* put terminal into a raw mode */{ int err; struct termios buf; if (ttystate != RESET) { errno = EINVAL; return(-1); } if (tcgetattr(fd, &buf) < 0) return(-1); save_termios = buf; /* structure copy */ /* * Echo off, canonical mode off, extended input * processing off, signal chars off. */ buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); /* * No SIGINT on BREAK, CR-to-NL off, input parity * check off, don't strip 8th bit on input, output * flow control off. */ buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); /* * Clear size bits, parity checking off. */ buf.c_cflag &= ~(CSIZE | PARENB); /* * Set 8 bits/char. */ buf.c_cflag |= CS8; /* * Output processing off. */ buf.c_oflag &= ~(OPOST); /* * Case B: 1 byte at a time, no timer. */ buf.c_cc[VMIN] = 1; buf.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSAFLUSH, &buf) < 0) return(-1); /* * Verify that the changes stuck. tcsetattr can return 0 on * partial success. */ if (tcgetattr(fd, &buf) < 0) { err = errno; tcsetattr(fd, TCSAFLUSH, &save_termios); errno = err; return(-1); } if ((buf.c_lflag & (ECHO | ICANON | IEXTEN | ISIG)) || (buf.c_iflag & (BRKINT | ICRNL | INPCK | ISTRIP | IXON)) || (buf.c_cflag & (CSIZE | PARENB | CS8)) != CS8 || (buf.c_oflag & OPOST) || buf.c_cc[VMIN] != 1 || buf.c_cc[VTIME] != 0) { /* * Only some of the changes were made. Restore the * original settings. */ tcsetattr(fd, TCSAFLUSH, &save_termios); errno = EINVAL; return(-1); } ttystate = RAW; ttysavefd = fd; return(0);}
从英文注释,可以了解到,各个参数的具体意义,
同时参考博客http://blog.csdn.net/awei_xu/article/details/3725329 中的红色标记部分设置来补充,
if((fd = open(dev,O_RDWR | O_NOCTTY | O_NDELAY)) == -1) /*---------------------- 重要----------------------*/ //保证本程序不会成为端口的所有者,从而妨碍控制工作和挂起信号. opt.c_cflag |= (CLOCAL | CREAD);//选择原始输入方式: 原始输入方式是不经处理的.opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //输出不经处理opt.c_oflag &= ~OPOST; //取消软件流控制(不设置可能存在丢码) opt.c_iflag &= ~(IXON | IXOFF | IXANY); /*----------------------------------------------------*/
修改后的程序:
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; } newtio = oldtio;/*************Debug*******************/ newtio.c_cflag |= CLOCAL | CREAD; newtio.c_cflag &= ~(CSIZE | PARENB); newtio.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOE | IEXTEN); newtio.c_oflag &= ~OPOST; newtio.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | BRKINT | INPCK | ISTRIP);/***************************************/ switch( nBits ) { case 7: newtio.c_cflag |= CS7; break; case 8: newtio.c_cflag |= CS8; break; } switch( nEvent ) { case 'O': /*odd parity*/ newtio.c_iflag |= INPCK ; newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; break; case 'E': /*even parity*/ newtio.c_iflag |= INPCK ; newtio.c_cflag |= PARENB; newtio.c_cflag &= ~PARODD; break; case 'N': /*no parity*/ 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;}
修改完的初步测试中发现有些地方还有问题,
待下一步测试,找到原因所在。
- 串口初始化配置(备忘)
- 串口初始化配置
- ---串口的配置初始化函数------------------
- Tomcat配置(备忘)
- 串口初始化
- 串口初始化
- 串口初始化
- 串口初始化
- 串口驱动程序设计详解---串口初始化(上)
- 串口驱动程序设计详解---串口初始化(上)
- 串口驱动程序设计详解---串口初始化(上)
- avr单片机USART串口通讯初始化配置说明
- 串口驱动之初始化 (一)
- GDAL安装配置(备忘)
- Spring MVC配置(备忘)
- Mysql 5.6 配置(备忘)
- 【备忘】LATEX BEAMER初始化
- 类初始化顺序备忘
- oracle数据库连接设置
- 利用Apache的commons-net实现FTP的文件读取、上传、下载、删除和移动功能
- AjaxPro使用方法
- 大数相关
- as2判断鼠标在指定时间内是否有动作
- 串口初始化配置(备忘)
- MySQL索引的查看创建和删除
- (Android) Eclipse "launching delegate" 停在 27%的解决方法
- android常用广播集锦
- Altium Designer中如何输出元器件坐标
- 淺析PowerBuilder下動態SQL語句
- SharePoint学习笔记002:未能加载文件或程序集'Microsoft.SharePoint.Sandbox.dll
- 在Linux的文本模式下发送带附件的电子邮件
- 一次删除数据库中所有表和存储过程