導讀
在串口通信開發中,數據錯亂是常見問題。本文將快速介紹串口標志位的作用及配置方法,幫助解決數據傳輸錯誤。
這是一個真實案例,用戶反饋“串口向另外的設備發送數據,發現運行一段時間后,發送的消息會阻塞很久才會發出來,一下子出來很多數據”。經過幫客戶檢查應用程序源碼,發現應用程序在串口阻塞方面沒有做正確的處理,修改后解決。
?非阻塞打開串口
open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NONBLOCK);
- O_NOCTTY:如果打開的是一個終端設備,這個程序不會成為對應這個端口的控制終端,如果沒有該標志,任何一個輸入,例如鍵盤中止信號等,都將影響進程。
- O_NONBLOCK:該標志與早期使用的O_NDELAY標志作用差不多。程序不關心DCD信號線的狀態,也就是不關心端口另一端是否已經連接。如果不指定該標志,進程將一直在休眠狀態,直到DCD信號線為0。簡單點就是以非阻塞方式打開串口。
?設置串口成阻塞方式可用fcntl設置串口的阻塞/非阻塞。1. 阻塞:fcntl(fd, F_SETFL, 0)fcntl中的F_SETFL只可以更改標志O_APPEND,O_NONBLOCK,O_SYNC 和 O_ASYNC;而0則表示清空這幾個標志,其中O_NONBLOCK也沒了,所以就變成了阻塞。2. 非阻塞:fcntl(fd, F_SETFL, O_NONBLOCK)檢測打開的文件描述符是否連接到一個終端設備,進一步確認串口是否正確打開。
?獲取和設置termios1. 獲取termios結構體(串口屬性)
- inttcgetattr(intfd,structtermios*termptr);
- termptr:接收返回的termios,成功:0,失敗:-1。
2. 保存先前的串口配置inttcsetattr(intfd,intopt,conststructtermios*termptr); 3. 設置串口屬性3.1 opt:在串口驅動程序里有輸入緩沖區和輸出緩沖區。在改變串口屬性時,緩沖區可能有數據存在,如何處理緩沖區中的數據,可通過opt 參數實現。
- TCSANOW:更改立即發生;
- TCSADRAIN:發送了所有輸出后更改才發生,若更改輸出參數則應用此選項;
- TCSAFLUSH:發送了所有輸出后更改才發生,在更改發生時未讀的所有輸入數據被刪除(Flush)。
3.2 成功:0。3.2 失敗:-1。
?設置波特率1. 設置輸入波特率
int cfsetispeed(struct termios *termptr, speed_t speed);
2.設置輸出波特率
int cfsetospeed(struct termios *termptr, speed_t speed);
?設置數據位(也稱設置字符大小)通過 c_cflag 設置。
CSIZE //數據位屏蔽CS5//5個數據位CS6 //6個數據位CS7 //7個數據位CS8 //8個數據位
例如,設置串口的數據位為 8 位:
c_cflag &= ~CSIZE; //清除CSIZEc_cflag |= CS8; //設置CS8
?設置奇偶校驗位設置串口的奇偶校驗是在 c_cflag 設置。
- PARENB 進行奇偶校驗。
- PARODD 奇校驗,否則為偶校驗。
1. 無校驗
c_cflag &= ~PARENB;
2.偶校驗
c_cflag |= PARENB;c_cflag &= ~PARODD;
3. 奇校驗
c_cflag |= PARENB;c_cflag |= ~PARODD;
?設置停止位設置串口停止位是在 c_cflag 設置。1. 設置 1 位停止位
c_cflag &= ~CSTOPB; //清除CSTOPB標志位
2.設置 2 位停止位
c_cflag |= CSTOPB; //設置CSTOPB標志位
?設置最少字符和等待時間c_cc[VTIME]和c_cc[VMIN]設置最少字符和等待時間,針對 read 而言。如果設置為0的話,則在任何情況下read()函數立即返回:
c_cc[VTIME] = 0;c_cc[VMIN] = 0;
?清除串口緩沖由于串口在重新設置之后,需要對當前的串口設備進行適當的處理,通常使用tcflush實現。
int tcdrain(int fd); //使程序阻塞,直到輸出緩沖區的數據全部發送完畢。int tcflow(int fd, int action); // 用于暫停或重新開始輸出。int tcflush(int fd, int queue_selector); //用于清空輸入/輸出緩沖區。
使用tcflush()函數,對于在緩沖區中的尚未傳輸的數據,或者收到的,但是尚未讀取的數據進行處理。queue_selector設置:
- TCIFLUSH:對接收到而未被讀取的數據進行清空處理。
- TCOFLUSH:對尚未傳送成功的輸出數據進行清空處理。
TCIOFLUSH:即對尚未處理的輸入輸出數據進行清空處理。
?激活選項CLOCAL 和 CREAD 分別用于本地連接和接收使能。激活這兩個選項:
c_cflag |= CLOCAL | CREAD;
?激活串口配置(屬性)
在完成全部串口配置之后,要激活剛才的配置并使配置生效。使用屬性設置函數 tcsetattr(),前面已有其說明。
?向串口寫數據
直接調用wtrite()即可。
?從串口讀數據調用read()讀取串口數據,但在非規范模式/原始模式下需要設置VMIN和VTIME。
- VMIN:非規范模式下讀取的最小字符數。
- VTIME:非規范模式下讀數據時的延時,VTIME個1/10秒。
VMIN和VTIME組合有四種情況:
- VMIN=0,VTIME=0:讀取的最少字符數為0,延時時間為0,read立即返回。
- VMIN>0,VTIME=0: read阻塞到讀取VMIN個字符才返回。
- VMIN=0,VTIME>0:有數據就返回,無數據等待VTIME個1/10秒返回。
VMIN>0,VTIME>0:讀取VMIN個字符或前后兩個字符的輸入間隔超過VTIME個1/10秒后返回,因為在輸入第一個字符之后系統才會啟動定時器,所以在這種情況下,read至少讀取一個字符。
?串口操作順序
- 保存原有串口屬性(可選);
- 設置波特率;
- 設置激活選項,如c_cflag |= CLOCAL | CREAD;
- 設置數據位大小;
- 設置奇偶校驗位;
- 設置停止位;
- 設置輸出(可選),如c_oflag=0;0是清空標志;c_oflag&=~OPOST;
- 設置輸入(可選);
- 設置c_lflag,如原始模式cfmakeraw(&termios);
- 設置讀取特性,c_cc[VTIME]和c_cc[VMIN];
- 刷新緩沖區,tcflush();
- 設置串口屬性,tcsetattr()。
-
嵌入式
+關注
關注
5141文章
19524瀏覽量
314803 -
串口
+關注
關注
14文章
1582瀏覽量
78592 -
zlg
+關注
關注
1文章
68瀏覽量
38525
發布評論請先 登錄
Verilog語言中阻塞和非阻塞賦值的不同
關于串口讀寫阻塞,沒有設置非阻塞標志,為什么還能繼續打印
UART阻塞方式收發
解決串口傳輸“阻塞”問題的方案資料下載

總結:這些Keil 軟件仿真的串口調試技巧,你都記熟了沒有?資料下載

評論