Linux串口接收丟失0x11,0x13和0x0D字符的問題

0. 遇到問題
做嵌入式開發(fā)少不了要用到串口, Linux下的嵌入式應(yīng)用層開發(fā)也一樣, 也要經(jīng)常用到串口設(shè)備.
這不, 前一段我就在linux下折騰程序, 調(diào)試發(fā)現(xiàn)串口接收原始二進(jìn)制數(shù)據(jù)總是莫名的數(shù)據(jù)丟失或數(shù)據(jù)錯(cuò)誤, (第1版用的都是ASCII碼傳輸, 倒沒有發(fā)現(xiàn)這樣的現(xiàn)象). 經(jīng)過仔細(xì)分析, 感覺這現(xiàn)象發(fā)生 好像只和被丟失的數(shù)據(jù)字節(jié)本身有關(guān), 和其周圍的數(shù)據(jù)模式無(wú)關(guān). 于是一狠心把0x00~0xFF所有數(shù)據(jù)都試了一遍(改個(gè)測(cè)試程序也不是很花時(shí)間), 一定要把它搞透透. 結(jié)果發(fā)現(xiàn)也只有3個(gè)數(shù)會(huì)有問題:
接收的?0x11?和?0x13?會(huì)被丟失
接收的?0x0D?會(huì)被篡改成?0x0A
再定睛一看, 感覺這3個(gè)數(shù) 不像是隨隨便便 冒出來(lái)的.
0x0D大家都知道就是大名鼎鼎的回車?\r, 它被篡改成的0x0A就是經(jīng)常和它一起的兄弟換行?\n.
0x11?和?0x13雖然不知道是個(gè)什么玩意, 但在ASCII表里也是靠前的, 控制字符之類的東西. 后來(lái)查到一個(gè)是?^Q VSTART字符?一個(gè)是?^S VSTOP字符, 好像是什么?起動(dòng)/停止輸出控制?用的, 估計(jì)是上古時(shí)代撥號(hào)上網(wǎng)modem控制之類的產(chǎn)物.
它們仨都是有名堂的, 說(shuō)不定某個(gè)技術(shù)細(xì)節(jié)調(diào)整一下就能解決, 果不其然, 用它們仨作關(guān)鍵字去搜索, 一下就搜到了答案.
1. 找到答案
只要在串口設(shè)備初始化時(shí),?c_iflag屬性的設(shè)置修改一下即可.
c_iflag是關(guān)于接收的屬性設(shè)置, 至于屬性值設(shè)置成什么號(hào), 我找到了一個(gè)權(quán)威答案,
在APUE這本書里的18章11節(jié)中, 第666頁(yè)有個(gè)名為?tty_raw()?的示例函數(shù),
其作用是將串口從終端模式改為原始模式(linux下串口設(shè)備默認(rèn)是終端模式).
此函數(shù)中對(duì)c_iflag屬性的設(shè)置, 我們照抄它就行:
buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
至于這樣設(shè)置的意義, 見下圖, 我就不贅述了.

2. 回到最初的問題
再回到我們的最初, 這些選項(xiàng)里, 那些是解決我們的問題的呢?
應(yīng)該是下面2個(gè):
ICRNL, reset它可?CR-to-NL off, 0x0D不會(huì)被篡改成0x0A了
IXON, reset它可?output flow control off, 0x11和0x13不會(huì)被丟掉了
(另外, 看到也有人說(shuō)可以干脆把c_iflag和c_oflag屬性都設(shè)置成0的, 我沒有試過, 不知是否可行.)