串口初始化配置

2019-07-13 04:53发布

在基于AT91的嵌入式linux中接收串口数据时,发现对于接收的数据经常出现接收不完整的现象。一帧的数据可能会被当做两帧接收,导致对于一帧数据接收出现问题。虽然这种情况在一般情况下,并不是经常出现,但是只要数据量稍微大一些,情况就会出现。 于是仔细看了程序中关于串口配置这一块的程序, [cpp] view plain copy
  1. int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)  
  2. {  
  3. struct termios oldtio;  
  4.     struct termios newtio;  
  5.   
  6.     if( tcgetattr(fd, &oldtio)  !=  0) {  
  7.         perror("SetupSerial 1");  
  8.         return -1;  
  9.     }  
  10.       
  11.     bzero( &newtio, sizeof( newtio ));  
  12.     newtio.c_cflag  |=  CLOCAL | CREAD;  
  13.     newtio.c_cflag &= ~CSIZE;  
  14.   
  15.     switch( nBits )  
  16.     {  
  17.         case 7:  
  18.             newtio.c_cflag |= CS7;  
  19.         break;  
  20.         case 8:  
  21.             newtio.c_cflag |= CS8;  
  22.         break;  
  23.     }  
  24.   
  25.     switch( nEvent )  
  26.     {  
  27.         case 'O':  
  28.         newtio.c_cflag |= PARENB;  
  29.         newtio.c_cflag |= PARODD;  
  30.         newtio.c_iflag |= INPCK ;  
  31.         break;  
  32.         case 'E':  
  33.         newtio.c_iflag |= INPCK ;  
  34.         newtio.c_cflag |= PARENB;  
  35.         newtio.c_cflag &= ~PARODD;  
  36.         break;  
  37.         case 'N':   
  38.         newtio.c_cflag &= ~PARENB;  
  39.         break;  
  40.     }  
  41.   
  42.     switch( nSpeed )  
  43.     {  
  44.         case 2400:  
  45.             cfsetispeed(&newtio, B2400);  
  46.             cfsetospeed(&newtio, B2400);  
  47.         break;  
  48.         case 4800:  
  49.             cfsetispeed(&newtio, B4800);  
  50.             cfsetospeed(&newtio, B4800);  
  51.         break;  
  52.         case 9600:  
  53.             cfsetispeed(&newtio, B9600);  
  54.             cfsetospeed(&newtio, B9600);  
  55.         break;  
  56.         case 115200:  
  57.             cfsetispeed(&newtio, B115200);  
  58.             cfsetospeed(&newtio, B115200);  
  59.         break;  
  60.         case 460800:  
  61.             cfsetispeed(&newtio, B460800);  
  62.             cfsetospeed(&newtio, B460800);  
  63.         break;  
  64.         default:  
  65.             cfsetispeed(&newtio, B9600);  
  66.             cfsetospeed(&newtio, B9600);  
  67.         break;  
  68.     }  
  69.     if( nStop == 1 )  
  70.         newtio.c_cflag &=  ~CSTOPB;  
  71.     else if ( nStop == 2 )  
  72.         newtio.c_cflag |=  CSTOPB;  
  73.   
  74.     newtio.c_cc[VTIME]  = 0;  
  75.     newtio.c_cc[VMIN] = 1;  
  76.       
  77.     tcflush(fd,TCIFLUSH);  
  78.     if((tcsetattr(fd,TCSANOW,&newtio))!=0)  
  79.     {  
  80.         perror("com set error");  
  81.         return -1;  
  82. }  
  83.       
  84.     tcflush(fd,TCIFLUSH);//The `tcflush' function is used to clear the input and/or output  
  85.     return 0;   
  86. }  


在分析完程序后发现可能导致出问题的地方:在使用oldtio读取串口配置后,却没有将其复制给newtio,并且将newtio清零,这造成下边的设置操作,修改了一些原来的设置。 根据程序修改VTIMEVMIN可推知这里要使用非规范方式, 根据APUE可知由VTIMEVMIN的设置共可以有四种选择 AVTIME > 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
  1. int  
  2. tty_raw(int fd) /* put terminal into a raw mode */  
  3. {  
  4.  int err;  
  5.  struct termios buf;  
  6.   
  7.   
  8.  if (ttystate != RESET) {  
  9.  errno = EINVAL;  
  10.  return(-1);  
  11.  }  
  12.  if (tcgetattr(fd, &buf) < 0)  
  13.  return(-1);  
  14.  save_termios = buf; /* structure copy */  
  15.   
  16.  /* 
  17.   * Echo off, canonical mode off, extended input 
  18.   * processing off, signal chars off. 
  19.   */  
  20.  buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);  
  21.   
  22.  /* 
  23.   * No SIGINT on BREAK, CR-to-NL off, input parity