近日在寫一個linux的串口程序,發現大多數情況下數據接收沒問題,但是有時卻有問題。主要是接收的字符串中包含有0x03這個字符,會造成與它相鄰的字符同時也接收不到,搞了好久才發現這個錯誤。查找資料后發現許多ARM板也存着這個問題,存在問題的字符串還包括0x13、0x0D等特殊含義的字符。
解決方法
方法比較簡單,在接收數據前,對串口的文件描述符fd進行如下設置,
- <pre name="code" class="cpp">struct termios options;
- if ( tcgetattr( fd,&options) != 0)
- {
- perror("SetupSerial 1");
- return(FALSE);
- }
- options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
- options.c_oflag &= ~OPOST;
- options.c_cflag |= CLOCAL | CREAD;
- options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
- tcsetattr(fd,TCSAFLUSH,&options);
現在問題應該可以解決了。如果你還想了解的更深入的話,可以接着往下看看。
屬性獲取
- 函數:int tcgetattr(int fd, struct termios *termios_p);
參數說明:
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_cc[NCCS];
其具體意義如下。
c_iflag:輸入模式標志,控制終端輸入方式,具體參數如表1所示。
表1 c_iflag參數表
|
鍵 值
|
說 明
|
|
IGNBRK
|
忽略BREAK鍵輸入
|
|
BRKINT
|
如果設置了IGNBRK,BREAK鍵輸入將被忽略
|
|
IGNPAR
|
忽略奇偶校驗錯誤
|
|
PARMRK
|
標識奇偶校驗錯誤
|
|
INPCK
|
允許輸入奇偶校驗
|
|
ISTRIP
|
去除字符的第8個比特
|
|
INLCR
|
將輸入的NL(換行)轉換成CR(回車)
|
|
IGNCR
|
忽略輸入的回車
|
|
ICRNL
|
將輸入的回車轉化成換行(如果IGNCR未設置的情況下)
|
|
IUCLC
|
將輸入的大寫字符轉換成小寫字符(非POSIX)
|
|
IXON
|
允許輸出時對XON/XOFF流進行控制
|
|
IXANY
|
輸入任何字符將重啟停止的輸出
|
|
IXOFF
|
允許輸入時對XON/XOFF流進行控制
|
|
IMAXBEL
|
當輸入隊列滿的時候開始響鈴
|
c_oflag:輸出模式標志,控制終端輸出方式,具體參數如表2所示。
表2 c_oflag參數
|
鍵 值
|
說 明
|
|
OPOST
|
處理后輸出
|
|
OLCUC
|
將輸入的小寫字符轉換成大寫字符(非POSIX)
|
|
ONLCR
|
將輸入的NL(換行)轉換成CR(回車)及NL(換行)
|
|
OCRNL
|
將輸入的CR(回車)轉換成NL(換行)
|
|
ONOCR
|
第一行不輸出回車符
|
|
ONLRET
|
不輸出回車符
|
|
OFILL
|
發送填充字符以延遲終端輸出
|
|
OFDEL
|
以ASCII碼的DEL作為填充字符,如果未設置該參數,填充字符為NUL
|
|
NLDLY
|
換行輸出延時,可以取NL0(不延遲)或NL1(延遲0.1s)
|
|
CRDLY
|
回車延遲,取值范圍為:CR0、CR1、CR2和 CR3
|
|
TABDLY
|
水平制表符輸出延遲,取值范圍為:TAB0、TAB1、TAB2和TAB3
|
|
BSDLY
|
空格輸出延遲,可以取BS0或BS1
|
|
VTDLY
|
垂直制表符輸出延遲,可以取VT0或VT1
|
|
FFDLY
|
換頁延遲,可以取FF0或FF1
|
c_cflag:控制模式標志,指定終端硬件控制信息,具體參數如表3所示。
表3 c_cflag參數
|
鍵 值
|
說 明
|
|
CBAUD
|
波特率(4+1位)(非POSIX)
|
|
CBAUDEX
|
附加波特率(1位)(非POSIX)
|
|
CSIZE
|
字符長度,取值范圍為CS5、CS6、CS7或CS8
|
|
CSTOPB
|
設置兩個停止位
|
|
CREAD
|
使用接收器
|
|
PARENB
|
使用奇偶校驗
|
|
PARODD
|
對輸入使用奇偶校驗,對輸出使用偶校驗
|
|
HUPCL
|
關閉設備時掛起
|
|
CLOCAL
|
忽略調制解調器線路狀態
|
|
CRTSCTS
|
使用RTS/CTS流控制
|
c_lflag:本地模式標志,控制終端編輯功能,具體參數如表4所示。
表4 c_lflag參數
|
鍵 值
|
說 明
|
|
ISIG
|
當輸入INTR、QUIT、SUSP或DSUSP時,產生相應的信號
|
|
ICANON
|
使用標准輸入模式
|
|
XCASE
|
在ICANON和XCASE同時設置的情況下,終端只使用大寫。
|
|
ECHO
|
顯示輸入字符
|
|
ECHOE
|
如果ICANON同時設置,ERASE將刪除輸入的字符
|
|
ECHOK
|
如果ICANON同時設置,KILL將刪除當前行
|
|
ECHONL
|
如果ICANON同時設置,即使ECHO沒有設置依然顯示換行符
|
|
ECHOPRT
|
如果ECHO和ICANON同時設置,將刪除打印出的字符(非POSIX)
|
|
TOSTOP
|
向后台輸出發送SIGTTOU信號
|
c_cc[NCCS]:控制字符,用於保存終端驅動程序中的特殊字符,如輸入結束符等。c_cc中定義了如表5所示的控制字符。
表5 c_cc支持的控制字符
|
宏
|
說 明
|
宏
|
說 明
|
|
VINTR
|
Interrupt字符
|
VEOL
|
附加的End-of-file字符
|
|
VQUIT
|
Quit字符
|
VTIME
|
非規范模式讀取時的超時時間
|
|
VERASE
|
Erase字符
|
VSTOP
|
Stop字符
|
|
VKILL
|
Kill字符
|
VSTART
|
Start字符
|
|
VEOF
|
End-of-file字符
|
VSUSP
|
Suspend字符
|
|
VMIN
|
非規范模式讀取時的最小字符數
|
tcsetattr函數用於設置終端的相關參數。參數fd為打開的終端文件描述符,參數optional_actions用於控制修改起作用的時間,而結構體termios_p中保存了要修改的參數。
optional_actions可以取如下的值:
TCSANOW:不等數據傳輸完畢就立即改變屬性。
TCSADRAIN:等待所有數據傳輸結束才改變屬性。
TCSAFLUSH:清空輸入輸出緩沖區才改變屬性。
錯誤信息:
EBADF:非法的文件描述符。
EINTR:tcsetattr函數調用被信號中斷。
EINVAL:參數optional_actions使用了非法值,或參數termios中使用了非法值。
ENCTTY:非終端的文件描述符。
屬性設置
函數:int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
tcsetattr函數用於設置終端參數。函數在成功的時候返回0,失敗的時候返回-1,並設置errno的值。
參數fd為打開的終端文件描述符,參數optional_actions用於控制修改起作用的時間,而結構體termios_p中保存了要修改的參數。optional_actions可以取如下的值。
TCSANOW:不等數據傳輸完畢就立即改變屬性。
TCSADRAIN:等待所有數據傳輸結束才改變屬性。
TCSAFLUSH:清空輸入輸出緩沖區才改變屬性。
錯誤信息:
EBADF:非法的
文件描述符。
EINTR:tcsetattr
函數調用被信號中斷。
EINVAL:參數optional_actions使用了非法值,或參數termios中使用了非法值。
示例
- #include <stdio.h>
- #include <termios.h>
- #include <unistd.h>
- #include <errno.h>
- int main(void){
- //term用於存儲獲得的終端參數信息
- struct termios term;
- int err;
- //獲得標准輸入的終端參數,將獲得的信息保存在term變量中
- if(tcgetattr(STDIN_FILENO,&term)==-1){
- perror("Cannot get standard input description");
- return 1;
- }
- //修改獲得的終端信息的結束控制字符
- term.c_cc[VEOF]=(cc_t)0x07;
- //使用tcsetattr函數將修改后的終端參數設置到標准輸入中
- //err用於保存函數調用后的結果
- err=tcsetattr(STDIN_FILENO,TCSAFLUSH,&term);
- //如果err為-1或是出現EINTR錯誤(函數執行被信號中斷),
- //給出相關出錯信息
- if(err==-1 && err==EINTR){
- perror("Failed to change EOF character");
- return 1;
- }
- return 0;
- }
