串口本身,標(biāo)準(zhǔn)和硬件 ?
串口是計(jì)算機(jī)上的串行通訊的物理接口。計(jì)算機(jī)歷史上,串口曾經(jīng)被廣泛用于連接計(jì)算機(jī)和終端設(shè)備和各種外部設(shè)備。雖然以太網(wǎng)接口和USB接口也是以一個(gè)串行流進(jìn)行數(shù)據(jù)傳送的,但是串口連接通常特指那些與RS-232標(biāo)準(zhǔn)兼容的硬件或者調(diào)制解調(diào)器的接口。雖然現(xiàn)在在很多個(gè)人計(jì)算機(jī)上,原來用以連接外部設(shè)備的串口已經(jīng)廣泛的被USB和Firewire替代;而原來用以連接網(wǎng)絡(luò)的串口則被以太網(wǎng)替代,還有用以連接終端的串口設(shè)備則已經(jīng)被MDA或者VGA取而代之。但是,一方面因?yàn)榇诒旧碓靸r(jià)便宜技術(shù)成熟,另一方面因?yàn)榇诘目刂婆_(tái)功能RS-232標(biāo)準(zhǔn)高度標(biāo)準(zhǔn)化并且非常普及,所以直到現(xiàn)在它仍然被廣泛應(yīng)用到各種設(shè)備上。某些計(jì)算機(jī)使用一個(gè)叫做UART的集成電路來作為串口設(shè)備。這個(gè)集成電路可以進(jìn)行字符和異步串行通訊序列之間的轉(zhuǎn)換,并且可以自動(dòng)地處理數(shù)據(jù)的時(shí)序。而某些低端設(shè)備則會(huì)讓CPU直接通過輸出針來傳送數(shù)據(jù),這種技術(shù)叫做bit-banging。因?yàn)椤按凇保琑S-232和UARTs基本上總是在同一個(gè)語境中出現(xiàn),所以這些名詞通常會(huì)被搞混。下面逐一解釋以下一些重要的名詞和術(shù)語。
什么是串行通信 ?
計(jì)算機(jī)可以每次傳送一個(gè)或者多個(gè)位(bit)的數(shù)據(jù)?!按小敝傅氖矫看沃粋鬏斠晃?1bit)數(shù)據(jù)。當(dāng)需要通過串行通訊傳輸一個(gè)字(word)的數(shù)據(jù)時(shí),只能以每次一位的方式接收或者發(fā)送。每個(gè)位可能是on(1)或者off(0)。很多技術(shù)術(shù)語中經(jīng)常用mark表示on,而space表示off。
串行數(shù)據(jù)的速度通常用每秒傳輸?shù)淖止?jié)數(shù)bits-per-second(bps)或者波特率(baud)表示。這個(gè)值表示的是每秒鐘被送出的0和1 的個(gè)數(shù)。很久很久以前,300bps就是很快的速度了,而現(xiàn)在的電腦可以處理高達(dá)430,800的RS-232速率。表示波特率的單位還有kpbs和 Mbps,1kps=1000bps而1Mbps=1000kbps。一般有人提到串行設(shè)備的時(shí)候,它通常說可能是某種數(shù)據(jù)通訊設(shè)備-DCE(Data Communications Equipment)或者數(shù)據(jù)終端設(shè)備-DTE(Data Terminal Equipment)。它們之間的區(qū)別非常簡(jiǎn)單,每個(gè)信號(hào)對(duì),比如傳送和接收,它們倆正好是相反的。如果需要將兩個(gè)DTE或者DCE設(shè)備連接起來的話,需要適配器或者交叉線纜將信號(hào)對(duì)交換。
什么是RS-232 ?
RS-232是EIA(Electronic Industries Association)定義的串行通信的電器接口。RS-232事實(shí)上有三種(A,B和C),它們分別采用不同的電壓來表示on和off。最被廣泛使用的是RS-232C,它將mark(on)比特的電壓定義為-3V到-12V之間,而將space(off)的電壓定義到+3V到+12V之間。雖然 RS-232C標(biāo)準(zhǔn)說信號(hào)最遠(yuǎn)被傳輸8m,但事實(shí)上你可以使用它傳輸更長(zhǎng)的距離,直到信號(hào)波特率已經(jīng)小到不行了為止。 RS-232的連結(jié)線中除去用來傳入傳出數(shù)據(jù)的電線,還有一些用來提供時(shí)序,狀態(tài)和握手的電線:
RS-232 針腳定義
DB-25
針腳 |
描述 |
針腳 |
描述 |
針腳 |
描述 |
針腳 |
描述 |
針腳 |
描述 |
1 |
Earth Ground |
6 |
DSR - Data Set Ready |
11 |
Unassigned |
16 |
Secondary RXD |
21 |
Signal Quality Detect |
2 |
TXD - Transmitted Data |
7 |
GND - Logic Ground |
12 |
Secondary DCD |
17 |
Receiver Clock |
22 |
Ring Detect |
3 |
RXD - Received Data |
8 |
DCD - Data Carrier Detecter |
13 |
Secondary CTS |
18 |
Unassigned |
23 |
Data Rate Select |
4 |
RTS - Request To Send |
9 |
Reserved |
14 |
Secondary TXD |
19 |
Secondary RTS |
24 |
Transmit Clock |
5 |
CTS - Clear To Send |
10 |
Reserved |
15 |
Transmit Clock |
20 |
DTR - Data Terminal Ready |
25 |
Unassigned |
DB-9
針腳 |
名稱 |
全名 |
方向(主機(jī) 外設(shè)) |
3 |
TD |
Transmit Data |
-> |
2 |
RD |
Receive Data |
<- |
7 |
RTS |
Request To Send |
-> |
8 |
CTS |
Clear To Send |
<- |
6 |
DSR |
Data Set Ready |
<- |
4 |
DTR |
Data Terminal Ready |
-> |
1 |
CD |
Data Carrier Detect |
<- |
9 |
RI |
Ring Indicator |
<- |
5 |
- |
Signal Ground |
|
另外兩個(gè)比較常見的串行接口的標(biāo)準(zhǔn)式RS-422和RS-574。RS-422使用更低的電壓和差分信號(hào),這樣可以將傳輸距離擴(kuò)張到300m。而RS-574定義了通??梢砸姷降挠迷陔娔X上的9針連接器和電壓。
信號(hào)定義 ?
RS-232標(biāo)準(zhǔn)定義了18個(gè)不同的串行通信的信號(hào)。而這些之中,僅僅有如下6個(gè)可以在UNIX環(huán)境中使用。
- GND - Logic Ground
從技術(shù)角度講,GND不能算是信號(hào)。但是沒有它其他信號(hào)都不能用了?;旧?,logic ground有點(diǎn)像一個(gè)參考電壓,通過它來判斷哪個(gè)電壓表示正哪個(gè)電壓表示負(fù)。
- TXD - Transmitted Data
TXD信號(hào)負(fù)載著從你的電腦或者設(shè)備到另一端(比如調(diào)制解調(diào)器)的數(shù)據(jù)。Mark范圍的電壓被解析成1,而space范圍電壓被解析成0。
- RXD - Received Data
RXD于TXD正好相反。它負(fù)載著從另一端的電腦或者設(shè)備上傳到你的工作站的數(shù)據(jù)。Mark和space的解析方法于TXD一致。
- DCD - Data Carrier Detect
DCD信號(hào)通常來自串口連結(jié)線的另一端。這條信號(hào)線上的space電壓表示另一端的電腦或者設(shè)備現(xiàn)在已經(jīng)連接。但是,DCD信號(hào)線卻不是總可以得到的,有些設(shè)備上有這條信號(hào)線,而有的則沒有。
- DTR - Data Terminal Ready
DTR信號(hào)是你的工作站產(chǎn)生的,用以告訴另一端的電腦或者設(shè)備你已經(jīng)是否已經(jīng)準(zhǔn)備好了。Space電壓表示準(zhǔn)備好了,而mark電壓表示沒有準(zhǔn)備好。當(dāng)你在工作站上打開串行接口時(shí),DTR通常自動(dòng)被設(shè)置位有效。
- CTS - Clear To Send
CTS則通常來自連結(jié)線的另一端。Space電壓表示你可以從工作站送出更多的數(shù)據(jù)。CTS通常用來協(xié)調(diào)你的工作站和另一端之間的串行數(shù)據(jù)流。
- RTS - Request To Send
如果RTS信號(hào)被設(shè)置成space電壓,這表示你準(zhǔn)備好了一些數(shù)據(jù)需要傳送。和CTS一樣,RTS也被用來協(xié)調(diào)工作站和另一端的電腦或者設(shè)備之間的數(shù)據(jù)流。有些工作站上會(huì)一直將這個(gè)信號(hào)設(shè)置位space。
異步通訊 ?
計(jì)算機(jī)為了弄懂傳給它的串行數(shù)據(jù),它需要確定每個(gè)字符開始和結(jié)束的位置。這通常是用異步串行數(shù)據(jù)來完成的。
在異步模式中,除非有字符被傳輸,否則串行數(shù)據(jù)線總是處于mark(1)狀態(tài)。有一個(gè)start位會(huì)被加入傳輸字符的各個(gè)位之前,在字符本身的位之后會(huì)有一個(gè)可選的parity位和一個(gè)或者多個(gè)stop位。Start位總是space(0)并且它會(huì)告訴計(jì)算機(jī)新的串行數(shù)據(jù)過來了。數(shù)據(jù)可以隨時(shí)被送出或者接收,這就是所謂的異步。
#ref(): File not found: "async.gif" at page "Linux串口編程詳解"
那個(gè)可選的parity位僅僅是所有傳輸位的和,這個(gè)和用以表示傳輸字符中有奇數(shù)個(gè)1還是偶數(shù)個(gè)1。在偶數(shù)parity中,如果有傳輸字符中有偶數(shù)個(gè)1,那么parity位被設(shè)置成0,而傳輸字符中有奇數(shù)個(gè)1,那么parity位被設(shè)置成1。在奇數(shù)parity中,位設(shè)置與此相反。還有一些術(shù)語,比如space parity, mark parity和no parity。Space parity是指parity位會(huì)一直被設(shè)置位0,而mark parity正好與此相反,parity會(huì)一直是1。No parity的意思就是根本不會(huì)傳輸parity位。剩余的位叫做stop位。傳輸字符之間可以有1個(gè),1.5個(gè)或者2個(gè)stop位,而且,它們的值總是1。傳統(tǒng)上,Stop位式用給計(jì)算機(jī)一些時(shí)間處理前面的字符的,但是它只是被用來同步接收數(shù)據(jù)的計(jì)算機(jī)和接受的字符。異步數(shù)據(jù)通常被表示成"8N1","7E1",或者與此類似的形式。這表示“8數(shù)據(jù)位,no parity和1個(gè)stop bit”,還有相應(yīng)得,“7數(shù)據(jù)位,even parity和1個(gè)stop bit”。
什么是全雙工和半雙工 ?
全雙工(Full duplex)是說計(jì)算機(jī)可以同時(shí)接受和發(fā)送數(shù)據(jù)——也就是它有兩個(gè)分開的數(shù)據(jù)傳輸通道(一個(gè)傳入,一個(gè)傳出)。
半雙工(Half duplex)表示計(jì)算機(jī)不能同時(shí)接受和發(fā)送數(shù)據(jù),而在某一時(shí)刻它只能單一的傳送或者接收。這通常意味著,它只有一個(gè)數(shù)據(jù)通道。半雙工并不是說RS-232的某些信號(hào)不能使用,而是,它通常是使用了有別于RS-232的其他不支持全雙工的標(biāo)準(zhǔn)。
什么是流控制 ?
兩個(gè)串行接口之間的傳輸數(shù)據(jù)流通常需要協(xié)調(diào)一致才行。這可能是由于用以通信的某個(gè)串行接口或者某些存儲(chǔ)介質(zhì)的中間串行通信鏈路的限制造成的。對(duì)于異步數(shù)據(jù)這里有兩個(gè)方法做到這一點(diǎn)。
第一種方法通常被叫做“軟件”流控制。這種方法采用特殊字符來開始(XON,DC1,八進(jìn)制數(shù)021)或者結(jié)束(XOFF,DC3或者八進(jìn)制數(shù) 023)數(shù)據(jù)流。而這些字符都在ASCII中定義好了。雖然這些編碼對(duì)于傳輸文本信息非常有用,但是它們卻不能被用于在特殊程序中的其他類型的信息。
第二種方法叫做“硬件”流控制。這種方法使用RS-232標(biāo)準(zhǔn)的CTS和RTS信號(hào)來取代之前提到的特殊字符。當(dāng)準(zhǔn)備就緒時(shí),接受一方會(huì)將CTS信號(hào)設(shè)置成為space電壓,而尚未準(zhǔn)備就緒時(shí)它會(huì)被設(shè)置成為mark電壓。相應(yīng)得,發(fā)送方會(huì)在準(zhǔn)備就緒的情況下將RTS設(shè)置成space電壓。正因?yàn)橛布骺刂剖褂昧擞跀?shù)據(jù)分隔的信號(hào),所以與需要傳輸特殊字符的軟件流控制相比它的速度很快。但是,并不是所有的硬件和操作系統(tǒng)都支持CTS/RTS流控制。
什么是BREAK ?
通常,直到有數(shù)據(jù)傳輸時(shí),接收和傳輸信號(hào)會(huì)保持在mark電壓。如果一個(gè)信號(hào)掉到space電壓并且持續(xù)了很長(zhǎng)時(shí)間,一般來說是1/4到1/2秒,那么就說有一個(gè)break條件存在了。
BREAK經(jīng)常被用來重置一條數(shù)據(jù)線或者用來改變像調(diào)制解調(diào)器這樣的設(shè)備的通訊模式。
同步通訊 ?
與異步數(shù)據(jù)不同,同步數(shù)據(jù)是一個(gè)穩(wěn)定的字節(jié)流。為了能夠在線路上讀取到數(shù)據(jù),計(jì)算機(jī)必須提供或者接受一個(gè)時(shí)鐘,這樣才能保證發(fā)送端和接收端同步。盡管已經(jīng)有同步時(shí)鐘,計(jì)算機(jī)還是必須以某種方式標(biāo)志數(shù)據(jù)流的開端。做這件事情最常見的辦法就是使用像Serial Data Link Control("SDLC")或者High-Speed Data Link Control("HDLC")這樣的數(shù)據(jù)包通訊協(xié)議。
這些協(xié)議每個(gè)都定義了一個(gè)確定的比特序列來表示數(shù)據(jù)包的開始和結(jié)束。當(dāng)然,它們也定義了一個(gè)用來表示沒有數(shù)據(jù)傳輸?shù)谋忍匦蛄小_@些比特序列可以幫助計(jì)算機(jī)識(shí)別數(shù)據(jù)包的開端。
因?yàn)橥絽f(xié)議可以不使用每個(gè)字符的同步比特位,所以通常它們的性能比異步通訊快最少25%,而且一般比較適用于遠(yuǎn)距離的網(wǎng)絡(luò)鏈接或者有兩個(gè)串口接口的配置的情況。盡管同步通訊的速度有優(yōu)勢(shì),大部分RS-232硬件卻不支持它,因?yàn)橥酵ㄓ嵭枰渌挠布蛙浖?/p>
用戶看到的串口和用戶空間的串口編程 ?
和其他設(shè)備一樣,Linux也是通過設(shè)備文件來提供訪問串口的功能。當(dāng)需要訪問串口的時(shí)候,你只需要open相應(yīng)的文件。
串口的設(shè)備文件 ?
Linux系統(tǒng)上一般有一個(gè)或者多個(gè)串口,而這些串口設(shè)備文件名字比較奇怪,如比下面這樣
串口設(shè)備文件名
操作系統(tǒng) |
串口1 |
串口2 |
USB/RS-232轉(zhuǎn)換器 |
Windows |
COM1 |
COM2 |
- |
Linux |
/dev/ttyS0 |
/dev/ttyS1 |
/dev/ttyUSB0 |
打開串口 ?
因?yàn)榇诤推渌O(shè)備一樣,在類Unix系統(tǒng)中都是以設(shè)備文件的形式存在的,所以,理所當(dāng)然得你可以使用open(2)系統(tǒng)調(diào)用/函數(shù)來訪問它。但 Linux系統(tǒng)中卻有一個(gè)稍微不方便的地方,那就是普通用戶一般不能直接訪問設(shè)備文件。你可以選擇以下方式做一些調(diào)整,以便你編寫的程序可以訪問串口。
- 改變?cè)O(shè)備文件的訪問權(quán)限設(shè)置 [#cd9bd1e0]
- 以root超級(jí)用戶的身份運(yùn)行程序 [#kdd0e577]
- 將你的程序編寫位setuid程序,以串口設(shè)備所有者的身份運(yùn)行程序 [#s7b703ff]
OK.假如你已經(jīng)準(zhǔn)備好了讓串口設(shè)備文件可以被所有用戶訪問,你可以在Linux系統(tǒng)中實(shí)驗(yàn)一下下面這個(gè)程序,它可以打開計(jì)算機(jī)的串口1。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h> /* File control definitions */
#include <errno.h>
#include <termios.h> /* POSIX terminal control definitions */
/*
* 'open_port()' - Open serial port 1
* Returns the file descriptor on success or -1 on error.
*/
int open_port(void)
{
int fd; /* File descriptor for the port */
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
/*
* Could not open the port.
*/
perror("open_port: Unable to open /dev/ttyS0 -");
}
else
{
fcntl(fd, F_SETFL, 0);
return (fd);
}
}
打開文件的選項(xiàng) ?
打開串口連接的時(shí)候,程序在open函數(shù)中除了Read+Write模式以外還指定了兩個(gè)選項(xiàng);
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
標(biāo)志O_NOCTTY可以告訴UNIX這個(gè)程序不會(huì)成為這個(gè)端口上的“控制終端”。如果不這樣做的話,所有的輸入,比如鍵盤上過來的Ctrl+C中止信號(hào)等等,會(huì)影響到你的進(jìn)程。而有些程序比如getty(1M/8)則會(huì)在打開登錄進(jìn)程的時(shí)候使用這個(gè)特性,但是通常情況下,用戶程序不會(huì)使用這個(gè)行為。
O_NDELAY標(biāo)志則是告訴UNIX,這個(gè)程序并不關(guān)心DCD信號(hào)線的狀態(tài)——也就是不關(guān)心端口另一端是否已經(jīng)連接。如果不指定這個(gè)標(biāo)志的話,除非DCD信號(hào)線上有space電壓否則這個(gè)程序會(huì)一直睡眠。
給端口上寫數(shù)據(jù) ?
給端口上寫入數(shù)據(jù)也很簡(jiǎn)單,使用write(2)系統(tǒng)調(diào)用就可以發(fā)送數(shù)據(jù)了:
n = write(fd, "ATZ\r", 4);
if (n < 0)
fputs("write() of 4 bytes failed!\n", stderr);
和寫入其他設(shè)備文件的方式相同,write函數(shù)也會(huì)返回發(fā)送數(shù)據(jù)的字節(jié)數(shù)或者在發(fā)生錯(cuò)誤的時(shí)候返回-1。通常,發(fā)送數(shù)據(jù)最常見的錯(cuò)誤就是EIO,當(dāng)調(diào)制解調(diào)器或者數(shù)據(jù)鏈路將Data Carrier Detect(DCD)信號(hào)線弄掉了,就會(huì)發(fā)生這個(gè)錯(cuò)誤。而且,直至關(guān)閉端口這個(gè)情況會(huì)一直持續(xù)。
從端口上讀取數(shù)據(jù) ?
從串口上讀取數(shù)據(jù)的時(shí)候就得?;ㄕ辛?。因?yàn)?,如果你在原?shù)據(jù)模式(raw data mode)操作端口的話,每個(gè)read(2)系統(tǒng)調(diào)用都會(huì)返回從串口輸入緩沖區(qū)中實(shí)際得到的字符的個(gè)數(shù)。在不能得到數(shù)據(jù)的情況下,read(2)系統(tǒng)調(diào)用就會(huì)一直等著,只到有端口上新的字符可以讀取或者發(fā)生超時(shí)或者錯(cuò)誤的情況發(fā)生。如果需要read(2)函數(shù)迅速返回的話,你可以使用下面這個(gè)方式:
fcntl(fd, F_SETFL, FNDELAY);
標(biāo)志FNDELAY可以保證read(2)函數(shù)在端口上讀不到字符的時(shí)候返回0。需要回到正常(阻塞)模式的時(shí)候,需要再次在不帶FNDELAY標(biāo)志的情況下調(diào)用fcntl(2)函數(shù):
fcntl(fd, F_SETFL, 0);
當(dāng)然,如果你最初就是以O(shè)_NDELAY標(biāo)志打開串口的,你也可在之后使用這個(gè)方法改變讀取的行為方式。
關(guān)閉串口 ?
可以使用close(2)系統(tǒng)調(diào)用關(guān)閉串口:
close(fd);
關(guān)閉串口會(huì)將DTR信號(hào)線設(shè)置成low,這會(huì)導(dǎo)致很多調(diào)制解調(diào)器掛起。
配置串口 ?
POSIX終端接口 ?
很多系統(tǒng)都支持POSIX終端(串口)接口。程序可以利用這個(gè)接口來改變終端的參數(shù),比如,波特率,字符大小等等。要使用這個(gè)端口的話,你必須將<termios.h>頭文件包含到你的程序中。這個(gè)頭文件中定義了終端控制結(jié)構(gòu)體和POSIX控制函數(shù)。
與串口操作相關(guān)的最重要的兩個(gè)POSIX函數(shù)可能就是tcgetattr(3)和tcsetattr(3)。顧名思義,這兩個(gè)函數(shù)分別用來取得設(shè)設(shè)置終端的屬性。調(diào)用這兩個(gè)函數(shù)的時(shí)候,你需要提供一個(gè)包含著所有串口選項(xiàng)的termios結(jié)構(gòu)體:
termios結(jié)構(gòu)體成員
成員 |
描述 |
c_cflag |
控制選項(xiàng) |
c_lflag |
行選項(xiàng) |
c_iflag |
輸入選項(xiàng) |
c_oflag |
輸出選項(xiàng) |
c_cc |
控制字符 |
c_ispeed |
輸入波特率(NEW) |
c_ospeed |
輸出波特率(NEW) |
控制選項(xiàng) ?
通過termios結(jié)構(gòu)體的c_cflag成員可以控制波特率,數(shù)據(jù)的比特?cái)?shù),parity,停止位和硬件流控制。下面這張表列出了所有可以使用的常數(shù)。
c_cflag常數(shù)
常量 |
描述 |
CBAUD |
Bit mask for baud rate |
B0 |
0 baud (drop DTR) |
B50 |
50 baud |
B75 |
75 baud |
B110 |
110 baud |
B134 |
134.5 baud |
B150 |
150 baud |
B200 |
200 baud |
B300 |
300 baud |
B600 |
600 baud |
B1200 |
1200 baud |
B1800 |
1800 baud |
B2400 |
2400 baud |
B4800 |
4800 baud |
B9600 |
9600 baud |
B19200 |
19200 baud |
B38400 |
38400 baud |
B57600 |
57,600 baud |
B76800 |
76,800 baud |
B115200 |
115,200 baud |
EXTA |
External rate clock |
EXTB |
External rate clock |
CSIZE |
Bit mask for data bits |
CS5 |
5 data bits |
CS6 |
6 data bits |
CS7 |
7 data bits |
CS8 |
8 data bits |
CSTOPB |
2 stop bits (1 otherwise) |
CREAD |
Enable receiver |
PARENB |
Enable parity bit |
PARODD |
Use odd parity instead of even |
HUPCL |
Hangup (drop DTR) on last close |
CLOCAL |
Local line - do not change "owner" of port |
LOBLK |
Block job control output |
CNEW_RTSCTS/CRTSCTS |
Enable hardware flow control (not supported on all platforms) |
在傳統(tǒng)的POSIX編程中,當(dāng)連接一個(gè)本地的(不通過調(diào)制解調(diào)器)或者遠(yuǎn)程的終端(通過調(diào)制解調(diào)器)時(shí),這里有兩個(gè)選項(xiàng)應(yīng)當(dāng)一直打開,一個(gè)是 CLOCAL,另一個(gè)是CREAD。這兩個(gè)選項(xiàng)可以保證你的程序不會(huì)變成端口的所有者,而端口所有者必須去處理發(fā)散性作業(yè)控制和掛斷信號(hào),同時(shí)還保證了串行接口驅(qū)動(dòng)會(huì)讀取過來的數(shù)據(jù)字節(jié)。
波特率常數(shù)(CBAUD,B9600等等)通常指用到那些不支持c_ispeed和c_ospeed成員的舊的接口上。后面文章將會(huì)提到如何使用其他POSIX函數(shù)來設(shè)置波特率。
千萬不要直接用使用數(shù)字來初始化c_cflag(當(dāng)然還有其他標(biāo)志),最好的方法是使用位運(yùn)算的與或非組合來設(shè)置或者清除這個(gè)標(biāo)志。不同的操作系統(tǒng)版本會(huì)使用不同的位模式,使用常數(shù)定義和位運(yùn)算組合來避免重復(fù)工作從而提高程序的可移植性。
設(shè)置波特率 ?
不同的操作系統(tǒng)會(huì)將波特率存儲(chǔ)在不同的位置。舊的編程接口將波特率存儲(chǔ)在上表所示的c_cflag成員中,而新的接口實(shí)裝則提供了c_ispeed和c_ospeed成員來保存實(shí)際波特率的值。
程序中可是使用cfsetospeed(3)和cfsetispeed(3)函數(shù)在termios結(jié)構(gòu)體中設(shè)置波特率而不用去管底層操作系統(tǒng)接口。下面的代碼是個(gè)非常典型的設(shè)置波特率的例子。
struct termios options;
/*
* Get the current options for the port...
*/
tcgetattr(fd, &options);
/*
* Set the baud rates to 19200...
*/
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);
/*
* Enable the receiver and set local mode...
*/
options.c_cflag |= (CLOCAL | CREAD);
/*
* Set the new options for the port...
*/
tcsetattr(fd, TCSANOW, &options);
函數(shù)tcgetattr(3)會(huì)將當(dāng)前串口配置回填到termio結(jié)構(gòu)體option中。然后,程序設(shè)置了輸入輸出的波特率并且將本地模式 (CLOCAL)和串行數(shù)據(jù)接收(CREAD)設(shè)置為有效,接著將新的配置作為參數(shù)傳遞給函數(shù)tcsetattr(3)。常量TCSANOW標(biāo)志所有改變必須立刻生效而不用等到數(shù)據(jù)傳輸結(jié)束。其他另一些常數(shù)可以保證等待數(shù)據(jù)結(jié)束或者刷新輸入輸出之后再生效。
tcsetattr常量
常量 |
描述 |
TCSANOW |
Make changes now without waiting for data to complete |
TCSADRAIN |
Wait until everything has been transmitted |
TCSAFLUSH |
Flush input and output buffers and make the change |
不同的系統(tǒng)上可能支持不同的輸入輸出速度,所以,通過串口連接兩臺(tái)機(jī)器或者設(shè)備的時(shí)候,應(yīng)該將波特率設(shè)置成兩者中較小的那個(gè),即MIN(speed1, speed2)。
設(shè)置字符大小 ?
設(shè)置字符大小的時(shí)候,這里卻沒有像設(shè)置波特率那么方便的函數(shù)。所以,程序中需要一些位掩碼運(yùn)算來把事情搞定。字符大小以比特為單位指定:
options.c_flag &= ~CSIZE; /* Mask the character size bits */
options.c_flag |= CS8; /* Select 8 data bits */
設(shè)置奇偶校驗(yàn) ?
與設(shè)置字符大小的方式差不多,這里仍然需要組合一些位掩碼來將奇偶校驗(yàn)設(shè)為有效和奇偶校驗(yàn)的類型。UNIX串口驅(qū)動(dòng)可以生成even,odd和no parity位碼。設(shè)置space奇偶校驗(yàn)需要耍點(diǎn)小手段。
options.c_cflag &= ~PARENB
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag |= PARENB
options.c_cflag &= ~PARODD
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
options.c_cflag |= PARENB
options.c_cflag |= PARODD
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
- Space parity is setup the same as no parity (7S1)
options.c_cflag &= ~PARENB
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
設(shè)置硬件流控制 ?
某些版本的UNIX系統(tǒng)支持通過CTS(Clear To Send)和RTS(Request To Send)信號(hào)線來設(shè)置硬件流控制。如果系統(tǒng)上定義了CNEW_RTSCTS和CRTSCTS常量,那么很可能它會(huì)支持硬件流控制。使用下面的方法將硬件流控制設(shè)置成有效:
options.c_cflag |= CNEW_RTSCTS; /* Also called CRTSCTS
將它設(shè)置成為無效的方法與此類似:
options.c_cflag &= ~CNEW_RTSCTS;
本地設(shè)置 ?
本地模式成員變量c_lflag可以控制串口驅(qū)動(dòng)怎樣控制輸入字符。通常,你可能需要通過c_lflag成員來設(shè)置經(jīng)典輸入和原始輸入模式。
成員變量c_lflag可以使用的常量
ISIG |
Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals |
ICANON |
Enable canonical input (else raw) |
XCASE |
Map uppercase \lowercase (obsolete) |
ECHO |
Enable echoing of input characters |
ECHOE |
Echo erase character as BS-SP-BS |
ECHOK |
Echo NL after kill character |
ECHONL |
Echo NL |
NOFLSH |
Disable flushing of input buffers after interrupt or quit characters |
IEXTEN |
Enable extended functions |
ECHOCTL |
Echo control characters as ^char and delete as ~? |
ECHOPRT |
Echo erased character as character erased |
ECHOKE |
BS-SP-BS entire line on line kill |
FLUSHO |
Output being flushed |
PENDIN |
Retype pending input at next read or input char |
TOSTOP |
Send SIGTTOU for background output |
選擇經(jīng)典輸入 ?
經(jīng)典輸入是以面向行設(shè)計(jì)的。在經(jīng)典輸入模式中輸入字符會(huì)被放入一個(gè)緩沖之中,這樣可以以與用戶交互的方式編輯緩沖的內(nèi)容,直到收到CR(carriage return)或者LF(line feed)字符。
選擇使用經(jīng)典輸入模式的時(shí)候,你通常需要選擇ICANON,ECHO和ECHOE選項(xiàng):
options.c_lflag |= (ICANON | ECHO | ECHOE);
選擇原始輸入 ?
原始輸入根本不會(huì)被處理。輸入字符只是被原封不動(dòng)的接收。一般情況中,如果要使用原始輸入模式,程序中需要去掉ICANON,ECHO,ECHOE和ISIG選項(xiàng):
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
輸入選項(xiàng) ?
可以通過輸入模式成員c_iflag來控制從端口上收到的字符的輸入過程。與c_cflag一樣,c_iflag的最終值是想要使用的所有狀態(tài)的位運(yùn)算OR的組合。
c_iflag成員可以使用的常量
常量 |
描述 |
INPCK |
Enable parity check |
IGNPAR |
Ignore parity errors |
PARMRK |
Mark parity errors |
ISTRIP |
Strip parity bits |
IXON |
Enable software flow control (outgoing) |
IXOFF |
Enable software flow control (incoming) |
IXANY |
Allow any character to start flow again |
IGNBRK |
Ignore break condition |
BRKINT |
Send a SIGINT when a break condition is detected |
INLCR |
Map NL to CR |
IGNCR |
Ignore CR |
ICRNL |
Map CR to NL |
IUCLC |
Map uppercase to lowercase |
IMAXBEL |
Echo BEL on input line too long |
設(shè)置輸入奇偶校驗(yàn)選項(xiàng) ?
當(dāng)程序在c_cflag中設(shè)置了奇偶校驗(yàn)成員(PARENB)的時(shí)候,程序就需要將輸入奇偶校驗(yàn)設(shè)置成為有效。與奇偶校驗(yàn)相關(guān)的常量有 INPCK,IGNPAR,PARMRK和ISTRIP。一般情況下,你可能需要選擇INPCK和ISTRIP將奇偶校驗(yàn)設(shè)置為有效同時(shí)從接收字串中脫去奇偶校驗(yàn)位:
options.c_iflag |= (INPCK | ISTRIP);
IGNPAR是一個(gè)比較危險(xiǎn)選項(xiàng),即便有錯(cuò)誤發(fā)生時(shí),它也會(huì)告訴串口驅(qū)動(dòng)直接忽略奇偶校驗(yàn)錯(cuò)誤給數(shù)據(jù)放行。這個(gè)選項(xiàng)在測(cè)試鏈接的通訊質(zhì)量時(shí)比較有用而通常不會(huì)被用在實(shí)際程序中。
PARMRK會(huì)導(dǎo)致奇偶校驗(yàn)錯(cuò)誤被標(biāo)志成特殊字符加入到輸入流之中。如果IGNPAR選項(xiàng)也是有效的,那么一個(gè)NUL(八進(jìn)制000)字符會(huì)被加入到發(fā)生奇偶校驗(yàn)錯(cuò)誤的字符前面。否則,DEL(八進(jìn)制177)和NUL字符會(huì)和出錯(cuò)的字符一起送出。
設(shè)置軟件流控制 ?
軟件流控制可以通過IXON,IXOFF和IXANY常量設(shè)置成有效:
options.c_iflag |= (IXON | IXOFF | IXANY);
將其設(shè)置為無效的時(shí)候,很簡(jiǎn)單,只需要對(duì)這些位取反:
options.c_iflag &= ~(IXON | IXOFF | IXANY);
XON(start data)和XOFF(stop data)字符卻是在c_cc數(shù)組中定義的,下面會(huì)詳細(xì)描述這個(gè)數(shù)組。
輸出選項(xiàng) ?
成員變量c_oflag之中包括了輸出過濾選項(xiàng)。和輸入模式相似,程序可以選擇使用經(jīng)過加工的或者原始的數(shù)據(jù)輸出。
c_oflag成員的常量
常量 |
描述 |
OPOST |
Postprocess output (not set = raw output) |
OLCUC |
Map lowercase to uppercase |
ONLCR |
Map NL to CR-NL |
OCRNL |
Map CR to NL |
NOCR |
No CR output at column 0 |
ONLRET |
NL performs CR function |
OFILL |
Use fill characters for delay |
OFDEL |
Fill character is DEL |
NLDLY |
Mask for delay time needed between lines |
NL0 |
No delay for NLs |
NL1 |
Delay further output after newline for 100 milliseconds |
CRDLY |
Mask for delay time needed to return carriage to left column |
CR0 |
No delay for CRs |
CR1 |
Delay after CRs depending on current column position |
CR2 |
Delay 100 milliseconds after sending CRs |
CR3 |
Delay 150 milliseconds after sending CRs |
TABDLY |
Mask for delay time needed after TABs |
TAB0 |
No delay for TABs |
TAB1 |
Delay after TABs depending on current column position |
TAB2 |
Delay 100 milliseconds after sending TABs |
TAB3 |
Expand TAB characters to spaces |
BSDLY |
Mask for delay time needed after BSs |
BS0 |
No delay for BSs |
BS1 |
Delay 50 milliseconds after sending BSs |
VTDLY |
Mask for delay time needed after VTs |
VT0 |
No delay for VTs |
VT1 |
Delay 2 seconds after sending VTs |
FFDLY |
Mask for delay time needed after FFs |
FF0 |
No delay for FFs |
FF1 |
Delay 2 seconds after sending FFs |
選擇加工過的輸出 ?
通過在c_oflag成員變量中設(shè)置OPOST選項(xiàng)的方法程序可以選擇加工過的輸入。
options.c_oflag |= OPOST;
在所有選項(xiàng)當(dāng)中,你可能只需要使用ONLCR選項(xiàng)來將行分隔符映射到CR-LF組合對(duì)上。其他選項(xiàng)主要是歷史遺留,僅僅與行打印機(jī)和終端跟不上串行數(shù)據(jù)的年代有關(guān)。
選擇原始輸出 ?
原始輸出方式可以通過在c_oflag中重置OPOST選項(xiàng)來選擇:
options.c_oflag &= ~OPOST;
如果OPOST選項(xiàng)被設(shè)置成無效的話,其他c_oflag中的選項(xiàng)都會(huì)失效。
控制字符 ?
字符數(shù)組c_cc里面包括了控制字符的定義和超時(shí)參數(shù)。這個(gè)數(shù)組的每個(gè)元素都是以常量定義的。
成員變量c_cc中的控制字符
常量 |
描述 |
鍵 |
VINTR |
Interrupt |
CTRL-C |
VQUIT |
Quit |
CTRL-Z |
VERASE |
Erase |
Backspace (BS) |
VKILL |
Kill-line |
CTRL-U |
VEOF |
End-of-file |
CTRL-D |
VEOL |
End-of-line |
Carriage return (CR) |
VEOL2 |
Second end-of-line |
Line feed (LF) |
VMIN |
Minimum number of characters to read |
- |
VSTART |
Start flow |
CTRL-Q (XON) |
VSTOP |
Stop flow |
CTRL-S (XOFF) |
VTIME |
Time to wait for data (tenths of seconds) |
- |
設(shè)置軟件流控制字符 ?
用來做軟件流控制的字符包含在數(shù)組c_cc的VSTART和VSTOP元素里面。通常情況下,它們應(yīng)該被設(shè)置成DC1(八進(jìn)制021)和DC3(八進(jìn)制023),它們?cè)贏SCII標(biāo)準(zhǔn)中代表著XON和XOFF字符。
設(shè)置讀取超時(shí) ?
UNIX串口驅(qū)動(dòng)提供了設(shè)置字符和包超時(shí)的能力。數(shù)組c_cc中有兩個(gè)元素可以用來設(shè)置超時(shí):VMIN和VTIME。在經(jīng)典輸入模式或者通過open(2)和fcntl(2)函數(shù)傳遞NDELAY選項(xiàng)時(shí),超時(shí)設(shè)置會(huì)被忽略。
VMIN可以指定讀取的最小字符數(shù)。如果它被設(shè)置為0,那么VTIME值則會(huì)指定每個(gè)字符讀取的等待時(shí)間。
如果VMIN不為零,VTIME會(huì)指定等待第一個(gè)字符讀取操作的時(shí)間。如果在這個(gè)指定時(shí)間中可以開始讀取某個(gè)字符,直到VMIN個(gè)數(shù)的所有字符全部被讀取,其他讀取操作將會(huì)被阻塞(等待)。也就是說,一旦讀取第一個(gè)字符,串口驅(qū)動(dòng)的預(yù)期就是接收到整個(gè)字符包(一共VMIN字節(jié))。如果在允許的時(shí)間內(nèi)沒有字符被讀取,那么read(2)調(diào)用就會(huì)返回0。通過這個(gè)方法可以確切得告訴串口驅(qū)動(dòng)程序需要讀取N個(gè)字節(jié),而且read(2)調(diào)用只會(huì)返回N或者 0。然而,超時(shí)設(shè)置只對(duì)第一個(gè)字符的讀取操作有效,所以,如果因?yàn)槟承┰蝌?qū)動(dòng)程序在N字節(jié)的包中丟失某個(gè)字符的話,read(2)調(diào)用將會(huì)一直等下去。
VTIME可以以十分之一秒為單位指定等待字符輸入的時(shí)間。如果VTIME設(shè)置為0(默認(rèn)情況),除非open(2)或者fcntl(2)函數(shù)設(shè)置了NDELAY選項(xiàng),否則read(2)將會(huì)永久得阻塞(等待)。
調(diào)制解調(diào)器通訊 ?
說到串口通訊就不得不提一下通過調(diào)劑解調(diào)器通訊的方式。這里給出的程序例子都適用于支持“事實(shí)上的”標(biāo)準(zhǔn)AT命令集的調(diào)制解調(diào)器。
什么是調(diào)制解調(diào)器 ?
調(diào)制解調(diào)器是一種可以將數(shù)字信號(hào)的串行數(shù)據(jù)轉(zhuǎn)化為模擬信號(hào)頻率的設(shè)備。通過這種轉(zhuǎn)換,信息就可以通過像電話線或者有線電視線纜那樣的模擬數(shù)據(jù)鏈路來傳輸了??谡Z中,經(jīng)常將調(diào)制解調(diào)器稱作“貓”。標(biāo)準(zhǔn)的電話調(diào)制解調(diào)器可以將串行數(shù)據(jù)轉(zhuǎn)化為能夠通過電話線傳輸?shù)囊纛l;因?yàn)檫@種轉(zhuǎn)化非常之快又非常復(fù)雜,所以如果你去聽一下的話,這些音頻很像是大聲尖叫時(shí)發(fā)出來的聲音。
今天可以見到的調(diào)制解調(diào)器可以通過電話線每秒傳輸53000比特——5.3Kbps——的數(shù)據(jù)。還有就是,大多數(shù)調(diào)制解調(diào)器都使用數(shù)據(jù)壓縮技術(shù),這樣就可以將某些類型數(shù)據(jù)的傳輸比特率提高到100kbps。
與調(diào)制解調(diào)器通訊 ?
于調(diào)制解調(diào)器通訊的第一步就是要以原始輸入模式打開和配置串口。
int fd;
struct termios options;
/* open the port */
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
fcntl(fd, F_SETFL, 0);
/* get the current options */
tcgetattr(fd, &options);
/* set raw input, 1 second timeout */
options.c_cflag |= (CLOCAL | CREAD);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
/* set the options */
tcsetattr(fd, TCSANOW, &options);
接下來就需要和調(diào)制解調(diào)器建立通訊連接。最好的辦法就是給調(diào)制解調(diào)器發(fā)送“AT”命令。這也會(huì)讓比較只能的調(diào)制解調(diào)器探測(cè)到你正在使用的波特率。如果正確地連接到調(diào)制解調(diào)器上,并且調(diào)制解調(diào)器開啟電源,它會(huì)返回一個(gè)回應(yīng)信號(hào)“OK”。
int /* O - 0 = MODEM ok, -1 = MODEM bad */
init_modem(int fd) /* I - Serial port file */
{
char buffer[255]; /* Input buffer */
char *bufptr; /* Current char in buffer */
int nbytes; /* Number of bytes read */
int tries; /* Number of tries so far */
for (tries = 0; tries < 3; tries ++)
{
/* send an AT command followed by a CR */
if (write(fd, "AT\r", 3) < 3)
continue;
/* read characters into our string buffer until we get a CR or NL */
bufptr = buffer;
while ((nbytes = read(fd, bufptr, buffer + sizeof(buffer) - bufptr - 1)) > 0)
{
bufptr += nbytes;
if (bufptr[-1] == '\n' | bufptr[-1] == '\r')
break;
}
/* nul terminate the string and see if we got an OK response */
*bufptr = '\0';
if (strncmp(buffer, "OK", 2) == 0)
return (0);
}
return (-1);
}
標(biāo)準(zhǔn)調(diào)制解調(diào)器命令 ?
大多數(shù)調(diào)制解調(diào)器都支持“AT”命令集。之所以這樣叫是因?yàn)檫@個(gè)命令集中的每個(gè)命令都是以“AT”字符開頭。每個(gè)命令都是以第一列的AT開頭字符后面跟上特殊命令參數(shù)和一個(gè)回車符CR(八進(jìn)制015)。調(diào)制解調(diào)器處理完這條命令之后會(huì)根據(jù)命令回復(fù)一些文本消息。
通過ATD命令可以撥打一個(gè)指定號(hào)碼。除過號(hào)碼和分隔符(-)以外,你還可以指定以音頻("T")或者脈沖("P")方式撥號(hào),暫停一秒(",")和等待撥號(hào)音("W"):
ATDT 555-1212
ATDT 18008008008W1234,1,1234
ATD T555-1212WP1234
調(diào)制解調(diào)器可能回復(fù)下面列出的某個(gè)消息:
NO DIALTONE
BUSY
NO CARRIER
CONNECT
CONNECT baud
通過ATH命令可以讓調(diào)制解調(diào)器掛斷。因?yàn)?,調(diào)制解調(diào)器如果在“命令”模式的話,你可能就不能打普通電話了。
如果DTR信號(hào)線掉了的話,大部分調(diào)制解調(diào)器也會(huì)掛斷。你可以將波特率設(shè)置成0并且持續(xù)至少1秒來做到這一點(diǎn)。再次讓DTR掉落同樣也可以把調(diào)制解調(diào)器重新拉回命令模式。
調(diào)制解調(diào)器成功掛斷以后,它會(huì)回復(fù)一個(gè)"NO CARRIER"回來。如果調(diào)制解調(diào)器仍然保持連接,它則會(huì)發(fā)送"CONNECT"或者"CONNECT baud"這樣的消息。
通過ATZ命令可以重置調(diào)制解調(diào)器。重置之后它會(huì)回復(fù)字符串"OK"。
- 與調(diào)制解調(diào)器通訊的常見問題
首先,也是最重要的一點(diǎn),千萬不要使用回聲輸入(input echoing)。回聲輸入會(huì)導(dǎo)致調(diào)制解調(diào)器和計(jì)算機(jī)之間產(chǎn)生反饋循環(huán)。
其次,當(dāng)發(fā)送調(diào)制解調(diào)器命令時(shí),命令必須以回車(CR)而不是換行(NL)結(jié)束。C語言中回車的字符常量是"\r"。
最后,處理調(diào)制解調(diào)器通訊的時(shí)候,要一定保證你使用了調(diào)制解調(diào)器支持的波特率。雖然大多數(shù)調(diào)制解調(diào)器都支持自動(dòng)探測(cè)波特率,但你也會(huì)注意到某些(通常是19.2kbps或者比較老的調(diào)制解調(diào)器)有局限性。
高級(jí)串口編程 ?
所謂高級(jí)串口編程其實(shí)說的就是使用更直接的底層的ioctl(2)和select(2)系統(tǒng)調(diào)用來操作串口。
串口的ioctl ?
前文中曾經(jīng)提到使用tcgetattr和tcsetattr函數(shù)來配置串口。UNIX環(huán)境下,這些函數(shù)都是使用ioctl(2)系統(tǒng)調(diào)用來實(shí)現(xiàn)的。
系統(tǒng)調(diào)用ioctl可以帶三個(gè)參數(shù):
int ioctl(int fd, int request, ...);
顯然,fd參數(shù)對(duì)于串口編程來說就是串口設(shè)備文件的文件描述符咯。而request參數(shù)是在<termios.h>頭文件中定義的常量,而且一般不會(huì)超出下表所列的范圍。
串口的IOCTL請(qǐng)求
REQUEST |
描述 |
POSIX函數(shù) |
TCGETS |
Gets the current serial port settings. |
tcgetattr |
TCSETS |
Sets the serial port settings immediately. |
tcsetattr(fd, TCSANOW, &options) |
TCSETSF |
Sets the serial port settings after flushing the input and output buffers. |
tcsetattr(fd, TCSAFLUSH, &options) |
TCSETSW |
Sets the serial port settings after allowing the input and output buffers to drain/empty. |
tcsetattr(fd, TCSADRAIN, &options) |
TCSBRK |
Sends a break for the given time. |
tcsendbreak, tcdrain |
TCXONC |
Controls software flow control. |
tcflow |
TCFLSH |
Flushes the input and/or output queue. |
tcflush |
TIOCMGET |
Returns the state of the "MODEM" bits. |
None |
TIOCMSET |
Sets the state of the "MODEM" bits. |
None |
FIONREAD |
Returns the number of bytes in the input buffer. |
None |
取得控制信號(hào) ?
TIOCMGET ioctl可以取得當(dāng)前調(diào)制解調(diào)器的狀態(tài)位。這個(gè)狀態(tài)位囊括了除去RXD和TXD信號(hào)線的所有RS-232信號(hào),這些都在下表中列出。
控制信號(hào)常量
常量 |
描述 |
TIOCM_LE |
DSR (data set ready/line enable) |
TIOCM_DTR |
DTR (data terminal ready) |
TIOCM_RTS |
RTS (request to send) |
TIOCM_ST |
Secondary TXD (transmit) |
TIOCM_SR |
Secondary RXD (receive) |
TIOCM_CTS |
CTS (clear to send) |
TIOCM_CAR |
DCD (data carrier detect) |
TIOCM_CD |
Synonym for TIOCM_CAR |
TIOCM_RNG |
RNG (ring) |
TIOCM_RI |
Synonym for TIOCM_RNG |
TIOCM_DSR |
DSR (data set ready) |
例如下面這個(gè)程序片段,你可以通過給ioctl帶一個(gè)用來保存狀態(tài)位的整形變量的指針來取得狀態(tài)位。
#include <unistd.h>
#include <termios.h>
int fd;
int status;
ioctl(fd, TIOCMGET, &status);
設(shè)置控制信號(hào) ?
TIOCMSET ioctl可以設(shè)置上面定義的調(diào)制解調(diào)器狀態(tài)位。下面的例子展示如何使用它來將DTR信號(hào)線設(shè)成掉線狀態(tài)。
#include <unistd.h>
#include <termios.h>
int fd;
int status;
ioctl(fd, TIOCMGET, &status);
status &= ~TIOCM_DTR;
ioctl(fd, TIOCMSET, &status);
可能被設(shè)置的狀態(tài)位取決于操作系統(tǒng),驅(qū)動(dòng)和正在使用的模式。關(guān)于更詳細(xì)的信息應(yīng)該去看以下你所使用的操作系統(tǒng)的文檔。