在編寫應(yīng)用程序的時候,需要將前面提到的串口參數(shù)如波特率、數(shù)據(jù)位、奇偶校驗位、停止位等設(shè)置好,通訊雙方才能在約定好的參數(shù)下進(jìn)行通訊。在哪里設(shè)置參數(shù),通過什么設(shè)置參數(shù),還有如何設(shè)置這些參數(shù)呢?下面分別進(jìn)行介紹。
在哪里設(shè)置串口參數(shù)--termios結(jié)構(gòu)體
POSIX規(guī)范中定義了標(biāo)準(zhǔn)接口-termios結(jié)構(gòu)體,在linux中用termios來設(shè)置串口參數(shù),如前面提到的波特率、停止位、校驗位、數(shù)據(jù)位等。它的詳細(xì)描述在<termios.h>中的<bits/termios.h>。
查看termios.h:
可以看到termios結(jié)構(gòu)體的定義:
在termios結(jié)構(gòu)體中的四個標(biāo)志控制了輸入輸出的四個不同部分。輸入模式標(biāo)志c_iflag決定如何解釋和處理接收的字符;輸出模式標(biāo)志c_oflag決定如何解釋和處理發(fā)送到tty設(shè)備的字符;控制模式c_cflag標(biāo)志決定設(shè)備的一系列協(xié)議特征,這一標(biāo)志只對物理設(shè)備有效;本地模式標(biāo)志c_lflag決定字符在輸出前如何收集和處理。
而c_cc[NCCS]數(shù)組包含了終端的所有特殊字符,可以修改特殊字符對應(yīng)的鍵值;c_ispeed和c_ospeed則記錄串口的輸入和輸出波特率(input speed和output speed)。
下面詳細(xì)介紹各個結(jié)構(gòu)體成員,列出的各個成員選項較多,大家不必每個都看,用到什么查詢即可。結(jié)構(gòu)體成員也只需重點關(guān)注輸入模式c_iflag、控制模式c_cflag和傳輸速度c_ispeed、c_ospeed。
通過什么設(shè)置參數(shù)--結(jié)構(gòu)體成員
c_iflag標(biāo)志常量:Input mode(輸入模式)
輸入模式可以在輸入值傳給程序之前控制其處理的方式。其中輸入值可能是由串口或鍵盤的終端驅(qū)動程序所接收到的字符。
c_iflag選項值表:
使用軟件流控制是啟用IXON、IXOFF和IXANY選項:
相反,要禁用軟件流控,則禁止上面的選項:
c_oflag標(biāo)志常量:Output mode(輸出模式)
輸出模式主要負(fù)責(zé)控制輸出字符的處理方式,即輸出字符在傳送到串口或顯示器之前是如何被程序來處理。
輸出模式是利用termios結(jié)構(gòu)的c_oflag的標(biāo)志來加以控制,其定義的方式皆以O(shè)R來加以組合。
c_oflag選項值表:
啟用輸出處理需要在c_oflag成員中啟用OPOST選項:
使用原始輸出,就是禁用輸出處理,使數(shù)據(jù)能不經(jīng)過處理、過濾的完整輸出到串口。當(dāng)OPOST被禁止,c_oflag其他選項也被忽略:
c_cflag標(biāo)志常量:Control mode(控制模式)
控制模式主要用于控制終端設(shè)備的硬件設(shè)置。利用termios結(jié)構(gòu)的c_cflag的標(biāo)志來加以控制。控制模式用在串口線連接到數(shù)據(jù)設(shè)備,也可以用在與終端設(shè)備的通訊。
c_cflag選項值表:
c_lflag標(biāo)志常量:Local mode(局部模式)
Local mode主要用來控制終端設(shè)備不同的特色。利用termios結(jié)構(gòu)里的c_lflag的標(biāo)志來設(shè)定局部模式。
在表中有兩個比較重要的標(biāo)志:
(1)ECHO:它可以讓你阻止鍵入字符的回應(yīng)。
(2)ICANON(正規(guī)模式)標(biāo)志,它可以對所接收的字符在兩種不同的終端設(shè)備模式之間來回切換。
c_lflag選項值表:
規(guī)范模式是行處理的。調(diào)用read讀串口數(shù)據(jù)時,每次返回一樣數(shù)據(jù)。如果選擇規(guī)范模式需要啟用ICANON、ECHO和ECHOE選項:
當(dāng)串口設(shè)備作為用戶終端時,通常要把串口設(shè)備配置成規(guī)范模式。
在原始模式下,串口輸入數(shù)據(jù)是不經(jīng)過處理的,在串口接收的數(shù)據(jù)被完整保留。要使串口設(shè)備工作在原始模式,需要關(guān)閉ICANON、ECHO、ECHOE和ISIG選項:
c_cc數(shù)組:特殊控制字符
可提供使用者設(shè)定一些特殊的功能,如Ctrl+C的字符組合。特殊控制字符主要是利用termios結(jié)構(gòu)里c_cc的數(shù)組成員來做設(shè)定。c_cc數(shù)組主要用于正規(guī)與非正規(guī)兩種環(huán)境,但要注意的是正規(guī)與非正規(guī)不可混為一談。其定義了特殊的控制字符。符號下標(biāo)(初始值)和意義為:
? c_cflag選項值表:
特別說明:
這些符號下標(biāo)值是互不相同的,除了 VTIME,VMIN 的值可能分別與 VEOL,VEOF 相同。 (在 非正規(guī)模式下,特殊字符的含義更改為延時含義。MIN 表示應(yīng)當(dāng)被讀入的最小字符數(shù)。TIME 是以十分之一秒為單位的計時器。如果同時設(shè)置了它們,read 將等待直到至少讀入一個字符,一旦讀入 MIN 個字符或者從上次讀入字符開始經(jīng)過了 TIME 時間就立即返回。如果只設(shè)置了 MIN,read 在讀入 MIN 個字符之前不會返回。如果只設(shè)置了 TIME,read 將在至少讀入一個字符,或者計時器超時的時候立即返回。如果都沒有設(shè)置,read 將立即返回,只給出當(dāng)前準(zhǔn)備好的字符。)MIN與TIME組合有以下四種:
(1)MIN = 0 , TIME =0;
有READ立即回傳;否則傳回 0 ,不讀取任何字符。
(2)MIN = 0 , TIME >0;
READ傳回讀到的字符,或在十分之一秒后傳回TIME;若來不及讀到任何字符,則傳回0。
(3)MIN > 0 , TIME =0;
READ 會等待,直到MIN字符可讀。
(4)MIN > 0 , TIME > 0;
每一格字符之間計時器即會被啟動,READ會在讀到MIN字符,傳回值或TIME的字符計時(1/10秒)超過時將值傳回。
c_ispeed和c_ospeed:記錄串口的輸入和輸出波特率(input speed 和 output speed)
通過如下命令查看可用波特率:
如何設(shè)置串口參數(shù)--相關(guān)函數(shù)
前面知道了需要設(shè)置哪些參數(shù),但如何獲取當(dāng)前配置的參數(shù),如何把想要的配置寫入使配置生效以及其他可能用到的串口操作具體怎么實現(xiàn),下面介紹實現(xiàn)這些操作的函數(shù)。
tcgetattr()
(1)原型
(2)功能
取得文件描述符(fd)初始值,并把其值賦給temios_p;函數(shù)可以從后臺進(jìn)程中調(diào)用;但是,終端屬性可能被后來的前臺進(jìn)程所改變。
tcsetattr()
(1)原型
(2)功能
設(shè)置與終端相關(guān)的參數(shù) (除非需要底層支持卻無法滿足),使用termios_p引用的termios結(jié)構(gòu)。optional_actions(tcsetattr函數(shù)的第二個參數(shù))指定了什么時候改變會起作用:
TCSANOW:改變立即發(fā)生;
TCSADRAIN:改變在所有寫入 fd 的輸出都被傳輸后生效。這個函數(shù)應(yīng)當(dāng)用于修改影響輸出的參數(shù)時使用。(當(dāng)前輸出完成時將值改變);
TCSAFLUSH :改變在所有寫入 fd 引用的對象的輸出都被傳輸后生效,所有已接受但未讀入的輸入都在改變發(fā)生前丟棄(同TCSADRAIN,但會舍棄當(dāng)前所有值);
tcsendbreak()
傳送連續(xù)的0值比特流,持續(xù)一段時間,如果終端使用異步串行數(shù)據(jù)傳輸的話。如果 duration是0,它至少傳輸0.25秒,不會超過0.5秒。如果duration非零,它發(fā)送的時間長度由實現(xiàn)定義。
如果終端并非使用異步串行數(shù)據(jù)傳輸,tcsendbreak()什么都不做,成功返回0,錯誤返回-1,并且為errno置值來指示錯誤;
tcdrain()
等待直到所有寫入fd引用的對象的輸出都被傳輸。成功返回0,錯誤返回-1,并且為errno置值來指示錯誤;
tcflush()
丟棄要寫入引用的對象,但是尚未傳輸?shù)臄?shù)據(jù),或者收到但是尚未讀取的數(shù)據(jù),成功返回0,錯誤返回-1,并且為errno置值來指示錯誤;取決于queue_selector的值:
TCIFLUSH :刷新收到的數(shù)據(jù)但是不讀;
TCOFLUSH :刷新寫入的數(shù)據(jù)但是不傳送;
TCIOFLUSH :同時刷新收到的數(shù)據(jù)但是不讀,并且刷新寫入的數(shù)據(jù)但是不傳送;
tcflow()
掛起 fd 引用的對象上的數(shù)據(jù)傳輸或接收成功返回0,錯誤返回-1,并且為errno置值來指示錯誤;,取決于 action 的值:
TCOOFF :掛起輸出;
TCOON :重新開始被掛起的輸出;
TCIOFF :發(fā)送一個 STOP 字符,停止終端設(shè)備向系統(tǒng)傳送數(shù)據(jù);
TCION :發(fā)送一個 START 字符,使終端設(shè)備向系統(tǒng)傳輸數(shù)據(jù);
打開一個終端設(shè)備時的默認(rèn)設(shè)置是輸入和輸出都沒有掛起。
波特率函數(shù)
被用來獲取和設(shè)置 termios 結(jié)構(gòu)中,輸入和輸出波特率的值。新值不會馬上生效,直到成功調(diào)用了 tcsetattr() 函數(shù)。
設(shè)置速度為 B0 使得 modem "掛機"。與 B38400 相應(yīng)的實際比特率可以用 setserial(8) 調(diào)整。
輸入和輸出波特率被保存于 termios 結(jié)構(gòu)中。
cfmakeraw 設(shè)置終端屬性如下:
(1)termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
(2)termios_p->c_oflag &= ~OPOST;
(3)termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
(4)termios_p->c_cflag &= ~(CSIZE|PARENB);
(5)termios_p->c_cflag |= CS8;
①cfgetospeed() 返回值為termios_p 指向的 termios 結(jié)構(gòu)中存儲的輸出波特率 ;
②cfsetospeed() 設(shè)置 termios_p 指向的 termios 結(jié)構(gòu)中存儲的輸出波特率為 speed。取值必須是以下常量之一:
③cfgetispeed() 返回值為termios 結(jié)構(gòu)中存儲的輸入波特率;
④cfsetispeed() 設(shè)置 termios 結(jié)構(gòu)中存儲的輸入波特率為 speed。如果輸入波特率被設(shè)為0,實際輸入波特率將等于輸出波特率;