• 正文
    • ? 非阻塞打開(kāi)串口
    • ? 設(shè)置串口成阻塞方式
    • ? 獲取和設(shè)置termios
    • ? 設(shè)置波特率
    • ? 設(shè)置奇偶校驗(yàn)位
    • ? 設(shè)置最少字符和等待時(shí)間
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

ZLG嵌入式筆記(連載24) | “串口阻塞”你真的會(huì)用嗎?

02/13 15:21
1210
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

串口通信開(kāi)發(fā)中,數(shù)據(jù)錯(cuò)亂是常見(jiàn)問(wèn)題。本文將快速介紹串口標(biāo)志位的作用及配置方法,幫助解決數(shù)據(jù)傳輸錯(cuò)誤。

這是一個(gè)真實(shí)案例,用戶反饋“串口向另外的設(shè)備發(fā)送數(shù)據(jù),發(fā)現(xiàn)運(yùn)行一段時(shí)間后,發(fā)送的消息會(huì)阻塞很久才會(huì)發(fā)出來(lái),一下子出來(lái)很多數(shù)據(jù)”。經(jīng)過(guò)幫客戶檢查應(yīng)用程序源碼,發(fā)現(xiàn)應(yīng)用程序在串口阻塞方面沒(méi)有做正確的處理,修改后解決。

? 非阻塞打開(kāi)串口

open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NONBLOCK);
    O_NOCTTY:如果打開(kāi)的是一個(gè)終端設(shè)備,這個(gè)程序不會(huì)成為對(duì)應(yīng)這個(gè)端口的控制終端,如果沒(méi)有該標(biāo)志,任何一個(gè)輸入,例如鍵盤中止信號(hào)等,都將影響進(jìn)程。
    O_NONBLOCK:該標(biāo)志與早期使用的O_NDELAY標(biāo)志作用差不多。程序不關(guān)心DCD信號(hào)線的狀態(tài),也就是不關(guān)心端口另一端是否已經(jīng)連接。如果不指定該標(biāo)志,進(jìn)程將一直在休眠狀態(tài),直到DCD信號(hào)線為0。簡(jiǎn)單點(diǎn)就是以非阻塞方式打開(kāi)串口。

? 設(shè)置串口成阻塞方式

可用fcntl設(shè)置串口的阻塞/非阻塞。

1. 阻塞:fcntl(fd, F_SETFL, 0)

fcntl中的F_SETFL只可以更改標(biāo)志O_APPEND,O_NONBLOCK,O_SYNC 和 O_ASYNC;而?0?則表示清空這幾個(gè)標(biāo)志,其中O_NONBLOCK也沒(méi)了,所以就變成了阻塞。

2. 非阻塞:fcntl(fd, F_SETFL, O_NONBLOCK)

檢測(cè)打開(kāi)的文件描述符是否連接到一個(gè)終端設(shè)備,進(jìn)一步確認(rèn)串口是否正確打開(kāi)。

? 獲取和設(shè)置termios

1. 獲取termios結(jié)構(gòu)體(串口屬性)

    int?tcgetattr(int?fd,?struct?termios?*termptr);termptr:接收返回的termios,成功:0,失敗:-1。

2. 保存先前的串口配置

int?tcsetattr(int?fd,?int?opt,?const?struct?termios?*termptr);

3. 設(shè)置串口屬性

3.1 opt:在串口驅(qū)動(dòng)程序里有輸入緩沖區(qū)和輸出緩沖區(qū)。在改變串口屬性時(shí),緩沖區(qū)可能有數(shù)據(jù)存在,如何處理緩沖區(qū)中的數(shù)據(jù),可通過(guò)opt 參數(shù)實(shí)現(xiàn)。

    TCSANOW:更改立即發(fā)生;TCSADRAIN:發(fā)送了所有輸出后更改才發(fā)生,若更改輸出參數(shù)則應(yīng)用此選項(xiàng);TCSAFLUSH:發(fā)送了所有輸出后更改才發(fā)生,在更改發(fā)生時(shí)未讀的所有輸入數(shù)據(jù)被刪除(Flush)。

3.2 成功:0。3.2 失?。?1。

? 設(shè)置波特率

1. 設(shè)置輸入波特率

int cfsetispeed(struct termios *termptr, speed_t speed);

2.?設(shè)置輸出波特率

int cfsetospeed(struct termios *termptr, speed_t speed);

設(shè)置數(shù)據(jù)位(也稱設(shè)置字符大小)

通過(guò) c_cflag 設(shè)置。

CSIZE ? ? ? //數(shù)據(jù)位屏蔽CS5??????????//5個(gè)數(shù)據(jù)位CS6 ? ? ? ? ?//6個(gè)數(shù)據(jù)位CS7 ? ? ? ? ?//7個(gè)數(shù)據(jù)位CS8 ? ? ? ? ?//8個(gè)數(shù)據(jù)位

例如,設(shè)置串口的數(shù)據(jù)位為 8 位:

c_cflag &= ~CSIZE; ? ? ? //清除CSIZEc_cflag |= CS8; ? ? ? ? //設(shè)置CS8

? 設(shè)置奇偶校驗(yàn)位

設(shè)置串口的奇偶校驗(yàn)是在 c_cflag 設(shè)置。

    PARENB ????進(jìn)行奇偶校驗(yàn)。PARODD ???奇校驗(yàn),否則為偶校驗(yàn)。

1. 無(wú)校驗(yàn)

c_cflag &= ~PARENB;

2.?偶校驗(yàn)

c_cflag |= PARENB;c_cflag &= ~PARODD;

3. 奇校驗(yàn)

c_cflag |= PARENB;c_cflag |= ~PARODD;

設(shè)置停止位

設(shè)置串口停止位是在 c_cflag 設(shè)置。1. 設(shè)置 1 位停止位

c_cflag &= ~CSTOPB; ? ? ? //清除CSTOPB標(biāo)志位

2.?設(shè)置 2 位停止位

c_cflag |= CSTOPB; ? ? ? ? ?//設(shè)置CSTOPB標(biāo)志位

? 設(shè)置最少字符和等待時(shí)間

c_cc[VTIME]?和c_cc[VMIN]?設(shè)置最少字符和等待時(shí)間,針對(duì) read 而言。如果設(shè)置為0的話,則在任何情況下read()函數(shù)立即返回:

c_cc[VTIME] = 0;c_cc[VMIN] = 0;

清除串口緩沖

由于串口在重新設(shè)置之后,需要對(duì)當(dāng)前的串口設(shè)備進(jìn)行適當(dāng)?shù)奶幚恚ǔJ褂胻cflush實(shí)現(xiàn)。

int tcdrain(int fd); ? ? ? ? ?//使程序阻塞,直到輸出緩沖區(qū)的數(shù)據(jù)全部發(fā)送完畢。int tcflow(int fd, int action); ? ? ? ? ? // 用于暫?;蛑匦麻_(kāi)始輸出。int tcflush(int fd, int queue_selector); ?//用于清空輸入/輸出緩沖區(qū)。

使用tcflush()函數(shù),對(duì)于在緩沖區(qū)中的尚未傳輸?shù)臄?shù)據(jù),或者收到的,但是尚未讀取的數(shù)據(jù)進(jìn)行處理。queue_selector設(shè)置:

    • TCIFLUSH:?對(duì)接收到而未被讀取的數(shù)據(jù)進(jìn)行清空處理。TCOFLUSH:?對(duì)尚未傳送成功的輸出數(shù)據(jù)進(jìn)行清空處理。

TCIOFLUSH:即對(duì)尚未處理的輸入輸出數(shù)據(jù)進(jìn)行清空處理。

激活選項(xiàng)

CLOCAL 和 CREAD 分別用于本地連接和接收使能。激活這兩個(gè)選項(xiàng):

c_cflag |= CLOCAL | CREAD;

激活串口配置(屬性)

在完成全部串口配置之后,?要激活剛才的配置并使配置生效。使用屬性設(shè)置函數(shù) tcsetattr()?,前面已有其說(shuō)明。

向串口寫(xiě)數(shù)據(jù)

直接調(diào)用wtrite()即可。

從串口讀數(shù)據(jù)

調(diào)用read()讀取串口數(shù)據(jù),但在非規(guī)范模式/原始模式下需要設(shè)置VMIN和VTIME。

    VMIN:非規(guī)范模式下讀取的最小字符數(shù)。VTIME:非規(guī)范模式下讀數(shù)據(jù)時(shí)的延時(shí),VTIME個(gè)1/10秒。

VMIN和VTIME組合有四種情況:

    • VMIN=0,VTIME=0:??讀取的最少字符數(shù)為0,延時(shí)時(shí)間為0,read立即返回。VMIN>0,VTIME=0:? read阻塞到讀取VMIN個(gè)字符才返回。VMIN=0,VTIME>0:??有數(shù)據(jù)就返回,無(wú)數(shù)據(jù)等待VTIME個(gè)1/10秒返回。

VMIN>0,VTIME>0:??讀取VMIN個(gè)字符或前后兩個(gè)字符的輸入間隔超過(guò)VTIME個(gè)1/10秒后返回,因?yàn)樵谳斎氲谝粋€(gè)字符之后系統(tǒng)才會(huì)啟動(dòng)定時(shí)器,所以在這種情況下,read至少讀取一個(gè)字符。

串口操作順序

    保存原有串口屬性(可選);設(shè)置波特率;設(shè)置激活選項(xiàng),如c_cflag |= CLOCAL | CREAD;設(shè)置數(shù)據(jù)位大??;設(shè)置奇偶校驗(yàn)位;設(shè)置停止位;設(shè)置輸出(可選),如c_oflag=0;0是清空標(biāo)志;c_oflag&=~OPOST;設(shè)置輸入(可選);設(shè)置c_lflag,如原始模式cfmakeraw(&termios);設(shè)置讀取特性,c_cc[VTIME]和c_cc[VMIN];刷新緩沖區(qū),tcflush();設(shè)置串口屬性,tcsetattr()。

M3562 Cortex?-A53核心板

四核Cortex-A53

1.8GHz主頻

低成本3568方案

參考價(jià)格:288元起

致遠(yuǎn)電子

致遠(yuǎn)電子

廣州致遠(yuǎn)電子股份有限公司成立于2001年,注冊(cè)資金5000萬(wàn)元,國(guó)家級(jí)高新技術(shù)認(rèn)證企業(yè),廣州市高端工控測(cè)量?jī)x器工程技術(shù)研究開(kāi)發(fā)中心,Intel ECA全球合作伙伴和微軟嵌入式系統(tǒng)金牌合作伙伴。

廣州致遠(yuǎn)電子股份有限公司成立于2001年,注冊(cè)資金5000萬(wàn)元,國(guó)家級(jí)高新技術(shù)認(rèn)證企業(yè),廣州市高端工控測(cè)量?jī)x器工程技術(shù)研究開(kāi)發(fā)中心,Intel ECA全球合作伙伴和微軟嵌入式系統(tǒng)金牌合作伙伴。收起

查看更多

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計(jì)資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫(xiě)文章/發(fā)需求
立即登錄