一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

POSIX操作系統(tǒng)的串行編程指南

 weicat 2007-08-02
POSIX操作系統(tǒng)的串行編程指南
第五版
Michael R.Sweet
Copyright 1994-1999, Allrights Reserved

目錄

序言

第一章 基本的串口通訊
什么是串口通訊
什么是RS-232
信號(hào)定義
異步通訊
什么是雙工和單工
流量控制
什么是斷開/break
同步通訊
訪問串行端口
串行端口文件
打開串行端口
寫入端口
讀出端口
關(guān)閉端口

第二章 配置串行端口
POSIX終端接口
控制選項(xiàng)
本地選項(xiàng)
輸入選項(xiàng)
輸出選項(xiàng)
控制字符

第三章 Modem通訊
什么是Modem
與Modem通訊
標(biāo)準(zhǔn)Modem命令
常見的Modem通訊問題

第四章 高級(jí)串行端口編程
串行端口IOCTLs
獲得控制信號(hào)
設(shè)置控制信號(hào)
獲得有效字節(jié)數(shù)
從一個(gè)串行端口中選擇輸入
select系統(tǒng)調(diào)用
使用select系統(tǒng)調(diào)用
使用X Intrinsics庫的Select接口
附錄A.引出線
RS-232 引出線
RS-422 引出線
RS-574 (IBM PC/AT)引出線
SGI 引出線

附錄B.控制符的ASCII編碼
控制編碼


序言
這篇POSIX操作系統(tǒng)的串口編程指南將告訴你如何正確,有效,可移植地對PC上的Unix工作站的串行端口進(jìn)行編程.每一章提供了
使用POSIX終端控制函數(shù)的程序范例,只需要進(jìn)行少量的更動(dòng)就可以在IRIX,HP-UX,SunOS,Solaris,DigitalUnix,Linux
和其它的Unix上運(yùn)行.并且你將會(huì)發(fā)現(xiàn),各個(gè)操作系統(tǒng)之間的最大區(qū)別僅僅是用于標(biāo)志串口設(shè)備和鎖文件的文件名不同.

該指南被按如下的章節(jié)和附錄給予說明.

第一章 基本的串口通訊
第二章 配置串行端口
第三章 Modem通訊
第四章 高級(jí)串行端口編程
附錄A.引出線
附錄B.控制符的ASCII編碼



第一章 基本的串口通訊
這一章介紹了串行通訊,RS-232和其它用于大多數(shù)計(jì)算機(jī)上的標(biāo)準(zhǔn),同時(shí)給出了一個(gè)用于訪問串口的C程序.

1.1 什么是串口通訊 ?

計(jì)算機(jī)在某一時(shí)間內(nèi)會(huì)傳送一個(gè)或多個(gè)位,而串口是一次一位地傳送.串口通訊包括大多數(shù)網(wǎng)絡(luò)設(shè)備,鍵盤,鼠標(biāo),
調(diào)制解調(diào)器和終端設(shè)備.

當(dāng)使用串口通訊時(shí),你發(fā)送或收到的每一個(gè)字,(比如一個(gè)字節(jié)或者一個(gè)字符),實(shí)際上都是一次一位地傳送的.每一
位或者為1或者為0.之后在你將聽到的術(shù)語中,mark表示on(1),space表示off(0).

串行數(shù)據(jù)的速度經(jīng)常用每秒位數(shù)(bps)或者波特率(baud)來表示.用來表示一秒中有多少1或者0被傳送.在計(jì)算機(jī)
發(fā)明的初期,300baud被認(rèn)為是很快的,而今天計(jì)算機(jī)的RS232可以達(dá)到430,800baud的速度!當(dāng)波特率超過1,000時(shí),
你通常會(huì)發(fā)現(xiàn)速率用千波特率,或kps(例如9,6k,19,2k)來表示.對于超過1,000,000的速率用兆波特率,或Mbps
(例如1.5Mbps).

當(dāng)提到串口設(shè)備或者端口時(shí),它們或者被標(biāo)記為數(shù)據(jù)通信設(shè)備(‘DCE‘)或者數(shù)據(jù)終端設(shè)備(‘DTE‘).兩者的不同非常簡單:
每一個(gè)信號(hào)對,比如發(fā)送和接收,剛好反過來了.當(dāng)要將兩個(gè)DTE或者兩個(gè)DCE接口連在一起時(shí),一個(gè)串行的可以交換信號(hào)
對的NULL-Modem電纜或適配器可以完成這一任務(wù).


1.2 什么是RS-232

RS-232是一種標(biāo)準(zhǔn)的用于EIA定義的串口通訊的電氣接口.RS-232實(shí)際上由三種不同特點(diǎn)組成.每一種定義了不同
電壓范圍的on和off.常見的是RS-232C,定義mark(1)(on)指-3V到-12V之間的電壓,space(0)指+3V到+12V之間的電壓.
RS-232C規(guī)范中指出這些信號(hào)可以發(fā)送到25英尺(約8米)遠(yuǎn).如果波特率足夠低的話,這些信號(hào)可以發(fā)送的更遠(yuǎn)些.

除了用于傳輸?shù)木€路,還要提供定時(shí),狀態(tài)和握手:

表1  RS-232 引腳定義

引出口號(hào)  說明        引出口號(hào)   說明            引出口號(hào)  說明     引出口號(hào)  說明            引出口號(hào)  說明   
---------+-----------+----------+---------------+---------+--------+---------+---------------+---------+------------
1        |接地       |6         |DSR數(shù)據(jù)序列就緒|11       |未定義  |16       |后備RXD        |21       |信號(hào)質(zhì)量檢測
---------+-----------+----------+---------------+---------+--------+---------+---------------+---------+------------
2        |TXD輸出    |7         |GND邏輯地      |12       |后備DCD |17       |接收者時(shí)鐘     |22       |鬧鐘檢測
---------+-----------+----------+---------------+---------+--------+---------+---------------+---------+------------
3        |RXD輸入    |8         |DCD數(shù)據(jù)負(fù)載檢測|13       |后備CTS |18       |未定義         |23       |數(shù)據(jù)速率選擇
---------+-----------+----------+---------------+---------+--------+---------+---------------+---------+------------
4        |RTS請求發(fā)送|9         |保留           |14       |后備TXD |19       |后備RTS        |24       |傳輸時(shí)鐘
---------+-----------+----------+---------------+---------+--------+---------+---------------+---------+------------
5        |CTS請求接收|10        |保留           |15       |傳輸時(shí)鐘|20       |DTR數(shù)據(jù)終端就緒|25       |未定義
---------+-----------+----------+---------------+---------+--------+---------+---------------+---------+------------



另外還有用于串口的兩個(gè)標(biāo)準(zhǔn),RS-422和RS-574.RS-422使用更低的電壓和微分信號(hào)使電纜通訊距離達(dá)到將近1000英尺
(約300米).RS-574則定義了9針的PC串口連接器和電壓.

1.3 信號(hào)定義

RS-232標(biāo)準(zhǔn)定義了18個(gè)不同的用于串口通訊的信號(hào).其中,僅有6個(gè)在Unix環(huán)境中是普遍適用的.

GND-邏輯地

嚴(yán)格地來說,邏輯地并不是信號(hào),但是沒有它,其它的信號(hào)無法工作.邏輯地作為一個(gè)參照電壓以告訴電器
哪個(gè)電壓是正哪些是負(fù).

TXD-數(shù)據(jù)被發(fā)送

TXD信號(hào)承載從你的工作站發(fā)送到其它的機(jī)器或設(shè)備上的數(shù)據(jù).mark電壓表示1,space電壓表示0.

RXD-被接收的數(shù)據(jù)
RXD信號(hào)承載從其它機(jī)器或設(shè)備上向你的工作站發(fā)送數(shù)據(jù).類似TXD,mark和space電壓分別表示1和0.

DCD-數(shù)據(jù)載波探測
DCD信號(hào)從串口電纜的另一端的機(jī)器或設(shè)備發(fā)送出來.串行線上的space(0)電壓表示機(jī)器或設(shè)備處于連線狀態(tài).
DCD并不總是被使用.

DTR-數(shù)據(jù)終端就緒
DTR信號(hào)是從你的工作站發(fā)送出來,告訴另一端的機(jī)器或設(shè)備你已經(jīng)就緒或者尚未就緒,分別用space(0)電壓和
mark(1)電壓表示.自從你的工作站打開串行接口之后,DTR一直處于自動(dòng)激活狀態(tài).

CTS-設(shè)備接收就緒,等待新的數(shù)據(jù)被發(fā)送 ( Clear to Send )
CTS信號(hào)來自串行電纜的另一端.space(0)電壓表示你可以從你的工作站上發(fā)送更多數(shù)據(jù)了.(以前接收的已
經(jīng)處理完畢)

CTS常用來調(diào)節(jié)工作站與串行線另一端的數(shù)據(jù)傳送流量.

RTS-請求發(fā)送
RTS信號(hào)被你的工作站置成space(0)電壓用來表示有更多的數(shù)據(jù)等待發(fā)送.
與CTS類似,RTS也是用來調(diào)節(jié)串行電纜兩個(gè)終端之間的數(shù)據(jù)傳送流量.大多數(shù)工作站把這個(gè)信號(hào)一直置為
space(0)電壓.

1.4 異步通訊
對于支持串行通訊的機(jī)器而言,它需要知道如何判別數(shù)據(jù)起始和終止.這篇指南將介紹異步串行數(shù)據(jù).

在異步模式下,串行數(shù)據(jù)直到有字符被發(fā)送前一直保持mark(1)狀態(tài).在每個(gè)字符之前有一開始位,緊接著是結(jié)束位,一
個(gè)可選的奇偶位和若干個(gè)停止位.起始位總是space(0),告訴機(jī)器串行數(shù)據(jù)已經(jīng)準(zhǔn)備好了.數(shù)據(jù)可以在任何時(shí)候被發(fā)送
或接收,因此稱之為異步的.

圖1 異步數(shù)據(jù)傳輸

space    +--+     +-----+  +--+  +--+       +12伏
         |開|0  1 |2  3 |4 |5 |6 |7 |
         |始|位 位|位 位|位|位|位|位|
         |  |     |     |  |  |  |  |
mark ----+  +-----+ +--+  +--+  +------ -12伏

可選的奇偶位簡單地統(tǒng)計(jì)數(shù)據(jù)中包含奇數(shù)個(gè)1還是偶數(shù)個(gè)1.如果有偶數(shù)個(gè)1,則這位為0,稱偶校驗(yàn)位.如果是奇數(shù)個(gè)1,則
該位為0,稱奇校驗(yàn)位.通常還有spaceparity,mark parity和no parity的說法.SpaceParity就是校驗(yàn)位總是0,markParity
就是校驗(yàn)位總是1,NoParity表示不使用或不傳輸校驗(yàn)位.

接著的那位是終止位.在字符之間可以有1,1.5或2個(gè)終止位,它們的值總是1.以前終止位是為了讓機(jī)器有更多的時(shí)間去
處理前一個(gè)字符,但現(xiàn)在僅僅是用于在機(jī)器接收字符時(shí)的同步.

異步數(shù)據(jù)格式通常用諸如‘8N1‘,‘7E1‘等等表示.前者表示8個(gè)數(shù)據(jù)位,沒有校驗(yàn)位,1個(gè)終止位.后者表示7個(gè)數(shù)據(jù)位,偶校
驗(yàn)位,1個(gè)終止位.

1.4.1 什么是全雙工和單雙工

全雙工表示機(jī)器可以同時(shí)既發(fā)送數(shù)據(jù)又可以接收數(shù)據(jù),有兩個(gè)獨(dú)立的數(shù)據(jù)通道(一進(jìn)一出).

單雙工表示機(jī)器不能在發(fā)送數(shù)據(jù)的同時(shí)又接收數(shù)據(jù).通常這意味這僅僅有一個(gè)數(shù)據(jù)通道在使用.但這并不意味不能使用
RS-232信號(hào),而是通訊聯(lián)接僅能使用不支持全雙工操作的其它的標(biāo)準(zhǔn),而不是RS-232.


1.4.2 流量控制

當(dāng)在兩個(gè)串行接口之間傳輸數(shù)據(jù)時(shí)通常有需要調(diào)節(jié)數(shù)據(jù)流量.這可能需要對之間的串行通訊聯(lián)接,某個(gè)串行接口或者某個(gè)
存儲(chǔ)介質(zhì)實(shí)行一些限制.對于異步數(shù)據(jù)通常有兩種方法:

一是軟件流量控制.使用特殊的字符去標(biāo)志數(shù)據(jù)流的開始(XON,DC1,八進(jìn)制的021或結(jié)束(XOFF,DC3,八進(jìn)制的023).這些
字符可以在ASCII中找到定義.然而當(dāng)傳輸文本信息時(shí),這些字符本身擁有一定的含義,不能被使用.

另一種是硬件流量控制,用RS232的CTS和RTS信號(hào)代替特殊字符用于控制.當(dāng)接收方準(zhǔn)備接收更多的數(shù)據(jù)時(shí),設(shè)置CTS為
space(0),反之設(shè)成mark(1).對應(yīng)的,當(dāng)發(fā)送方準(zhǔn)備發(fā)送更多的數(shù)據(jù)時(shí),設(shè)置RTS為space(0).由于硬件的流量控制使用
獨(dú)立的一套信號(hào),比軟件的實(shí)現(xiàn)更快,因?yàn)樽魍瑯拥墓ぷ?后者需要發(fā)送或接收多位信息.另外需要注意的是,并不是所
有的硬件和操作系統(tǒng)都支持CTS/RTS流量控制.

1.4.3 什么是中斷/Break

一般而言,一個(gè)接收或者傳輸數(shù)據(jù)的信號(hào)直到一個(gè)新的字符被傳送之前一直保持mark(1).信號(hào)過了很長時(shí)間后才被降
低到space(1),通常時(shí)1/4到1/2秒,那么我們稱這種狀態(tài)為break.

Break有時(shí)被用來重置通訊線路或者改變諸如Modem的通訊設(shè)備的工作模式.第三章的‘如何操作Modem‘將更深入地談?wù)?br>這個(gè)問題.

1.5 同步通訊

與異步數(shù)據(jù)不同的是,同步數(shù)據(jù)是一種恒定的位流.為了從通訊線上讀出數(shù)據(jù),機(jī)器必須發(fā)送或者接收一個(gè)普通的位作為
時(shí)鐘以達(dá)到發(fā)送端和接收端的同步.

對于同步,機(jī)器必須標(biāo)志數(shù)據(jù)的起始位置.實(shí)現(xiàn)它的最普通的方法時(shí)使用類似串行數(shù)據(jù)鏈路控制SDLC或者高速數(shù)據(jù)鏈路控
制HDLC之類的數(shù)據(jù)包協(xié)議.

每一個(gè)協(xié)議定義了固定的位順序以表示數(shù)據(jù)包的開始和結(jié)束,同時(shí)也定義了被用來表示沒有數(shù)據(jù)時(shí)使用的位順序.機(jī)器
根據(jù)這些位順序可以知道數(shù)據(jù)包的開始位.

因?yàn)橥絽f(xié)議不使用每個(gè)字符的同步位,所以它們一般能比異步通訊提高至少25%的性能,適合遠(yuǎn)程網(wǎng)絡(luò)和兩個(gè)以上的串行
接口的配置.

盡管同步協(xié)議擁有速度優(yōu)勢,但大多數(shù)RS232硬件仍然由于額外的硬件和必要的軟件而沒有支持它.


1.6 訪問串行端口

類似于所有設(shè)備,UNIX系統(tǒng)通過設(shè)備文件提供了對串行端口的訪問.為了訪問它,僅僅需要打開相應(yīng)的設(shè)備文件.

1.6.1 串行端口文件
在UNIX系統(tǒng)的每一個(gè)串行端口都有一個(gè)或者更多的設(shè)備文件與它們相對應(yīng)(在/dev/目錄下).

表2 -----串行端口的設(shè)備文件名
            ----------------------------------------+------------------+-------------- --+
操作系統(tǒng)                 |     端口1       |      端口2      |
                             ---------------------------------------+------------------+-----------------+
IRIX(R)                    |      /dev/ttyf1   |    /dev/ttyf2    |
                             ---------------------------------------+------------------+-----------------+
HP-UX                                     |    /dev/tty1p0  |   /dev/tty2p0 |
                             ---------------------------------------+------------------+-----------------+
Solairis(R)/SunOS(R)          |      /dev/ttya     |  ./dev/ttyb      |
                             ---------------------------------------+------------------+-----------------+
Linux(R)                                  |  /dev/ttyS0     |  /dev/ttyS1     |
                             ---------------------------------------+------------------+-----------------+
Digital UNIX(R)                     |  /dev/tty01      | /dev/tty02       |
                             ---------------------------------------+------------------+-----------------+

1.6.2 打開串行端口

既然串行端口是一個(gè)文件,open(2)函數(shù)可以被用來訪問它.UNIX系統(tǒng)的一個(gè)特點(diǎn)是一般用戶無法訪問設(shè)備文件.所以需要
更改你所關(guān)心的設(shè)備文件的訪問權(quán)限,以超級(jí)用戶來運(yùn)行程序或者在你的程序中使用setuid,從而擁有設(shè)備文件的訪問權(quán).

這里,我們假設(shè)該文件可以被所有用戶訪問.在運(yùn)行IRIX的SGI工作站上打開串行端口的代碼如下:

listing 1 open a serial port

#include <stdio.h> /*標(biāo)準(zhǔn)的輸入輸出*/
#include <string.h> /*字符串相關(guān)函數(shù)*/
#include <unistd.h> /*UNIX標(biāo)準(zhǔn)的函數(shù)*/
#include <fcntl.h> /*文件控制*/
#iclude <errno.h> /*出錯(cuò)信息*/
#include <termios.h> /*POSIX終端控制定義*/

/* open_port() ----打開串行端口*/
打開成功則返回文件描述符,否則返回-1
*/

int open_port(void)
{
int fd;
fd = open(‘/dev/ttyf1‘,O_RDWR | O_NOCTTY | O_NDELAY );
if( fd == -1 ){
perror(‘open_port:Unable to open /dev/ttyf1 -‘);
}
else
fcntl(fd,F_SETFL,0);

return fd;
}
其他的系統(tǒng)只需要更換設(shè)備文件名,其它代碼是一樣的.

1.6.3 端口的打開選項(xiàng)

你會(huì)發(fā)現(xiàn)當(dāng)我們打開設(shè)備文件后,我們除了用讀寫模式外還用了另外兩個(gè)標(biāo)志:
fd = open(‘/dev/ttyf1‘,O_RDWR | O_NOCTTY | O_NDELAY );

O_NOCTTY標(biāo)志告訴UNIX系統(tǒng),這個(gè)程序不會(huì)成為對應(yīng)這個(gè)端口的控制終端,如果沒有指定這個(gè)標(biāo)志,那么任何一個(gè)
輸入,諸如鍵盤中止信號(hào)等等,都將會(huì)影響你的進(jìn)程.類似于getty的程序當(dāng)啟動(dòng)login進(jìn)程時(shí)都使用了這個(gè)特性,
但是一般的用戶程序不需要這這樣作.

O_NDELAY標(biāo)志告訴UNIX系統(tǒng)這個(gè)程序不關(guān)心DCD信號(hào)線所處的狀態(tài),它用來表示端口的另一端是否激活或者停止.
如果你想指定這個(gè)標(biāo)志,你的進(jìn)程將會(huì)一直處在睡眠態(tài),直到DCD信號(hào)線是space(0).

1.6.4 寫數(shù)據(jù)到端口

寫數(shù)據(jù)到端口很簡單,就是用write(2)系統(tǒng)調(diào)用把數(shù)據(jù)發(fā)送出去.

n = write(fd,‘ATZ\r‘,4);
if( n < 0 )
fputs(‘write() of 4 bytes failed!\n‘,stderr);

write返回有多少個(gè)字節(jié)被發(fā)送出去,如果出錯(cuò),則返回為-1.通常你可能遇到的唯一的錯(cuò)誤是EIO,當(dāng)MODEM或者
數(shù)據(jù)鏈路撤銷數(shù)據(jù)載波探測(DCD linke)時(shí)會(huì)出現(xiàn)這種情況,這種情況將一直存在,直到你關(guān)閉端口.

1.6.5 從端口中讀取數(shù)據(jù)

從端口中讀出數(shù)據(jù)有些技巧.當(dāng)你在RAW數(shù)據(jù)模式下操作時(shí),每一個(gè)read(2)系統(tǒng)調(diào)用將返回當(dāng)前串行輸入緩存區(qū)中
存在的字符數(shù).如果沒有字符,這個(gè)系統(tǒng)調(diào)用將一直阻塞到有字符到達(dá)或者間隔時(shí)鐘過期,或者錯(cuò)誤發(fā)生.當(dāng)read函數(shù)
如下設(shè)置后將會(huì)立即返回.

fcntl(fd,F_SETFL,FNDELAY);

FNDELAY選項(xiàng)將導(dǎo)致當(dāng)端口上沒有字符可讀時(shí),read函數(shù)返回0.為恢復(fù)到一般狀態(tài),可以在調(diào)用fcntl時(shí)不帶FNDELAY選項(xiàng).

fcntl(fd,F_SETFL,0);

在用O_NDELAY打開端口之后也可以這樣來恢復(fù).

1.6.6 關(guān)閉串行端口

為了關(guān)閉串行端口,只需要使用close系統(tǒng)調(diào)用

close(fd);

關(guān)閉串行端口經(jīng)常會(huì)設(shè)置DTR信號(hào)為低,導(dǎo)致大多數(shù)的MODEM掛起.


第二章 配置串行端口
這一章將討論如何用C語言的POSIX終端接口去配置串行端口.

2. 1 POSIX終端接口

大多數(shù)系統(tǒng)都支持POSIX終端接口,用于改變諸如波特率,字符大小等等參數(shù).你所需要作的第一件事情是將termios.h
include到你的程序中,這個(gè)文件中其中定義了POSIX控制函數(shù)和終端控制結(jié)構(gòu).

兩個(gè)重要的POSIX函數(shù)是tcgetattr(3)和tcsetattr(3),分別用于獲得和設(shè)置終端屬性;你需要提供一個(gè)包含所有可用串
行選項(xiàng)的終端結(jié)構(gòu):

表3 - Termios結(jié)構(gòu)的成員
+---------------------------------------------------------------+
| 成員                | 說明                                               |
+---------------------------------------------------------------+
| c_cflag             | 控制選項(xiàng)                                     |
+---------------------------------------------------------------+
| c_cflag             | 線路選項(xiàng)                                     |
+---------------------------------------------------------------+
| c_iflag              | 輸入選項(xiàng)                                     |
+---------------------------------------------------------------+
| c_oflag            | 輸出選項(xiàng)                                      |
+---------------------------------------------------------------+
| c_cc                 | 控制特性                                      |
+---------------------------------------------------------------+
| c_ispeed         | 輸入波特律(新接口)               |
+---------------------------------------------------------------+
| c_ospeed        | 輸出波特律(新接口)               |
+---------------------------------------------------------------+

2.2 控制選項(xiàng)

c_cflag成員用于控制波特率,數(shù)據(jù)位的數(shù)目,奇偶校驗(yàn)位,終止位和硬件流控制.以下是所支持的配置常數(shù).

表4 - c_cfalg成員的可設(shè)置常量
+---------------------+-----------------------------------------+
| 常量                   | 說明                                             |
+---------------------+-----------------------------------------+
| CBAND               | 波特律的位掩碼                    |
+---------------------+-----------------------------------------+
| B0                        | 0 波特 (放棄DTR)                    |
+---------------------+-----------------------------------------+
| B50                      |  50 波特                         |
+---------------------+-----------------------------------------+
| B75                     | 75 波特                         |
+---------------------+-----------------------------------------+
| B110                   | 110 波特                                      |
+---------------------+-----------------------------------------+
| B134                   | 134 波特                                      |
+---------------------+-----------------------------------------+
| B150                   | 150 波特                                      |
+---------------------+-----------------------------------------+
| B200                   | 200 波特                                      |
+---------------------+-----------------------------------------+
| B300                   | 300 波特                                      |
+---------------------+-----------------------------------------+
| B600                   | 600 波特                                      |
+---------------------+-----------------------------------------+
| B1200                 | 1200 波特                                   |
+---------------------+-----------------------------------------+
| B1800                 | 1800 波特                                   |
+---------------------+-----------------------------------------+
| B2400                 | 2400 波特                                   |
+---------------------+-----------------------------------------+
| B4800                 | 4800 波特                                   |
+---------------------+-----------------------------------------+
| B9600                 | 9600 波特                                   |
+---------------------+-----------------------------------------+
| B19200               | 19200 波特                                |
+---------------------+-----------------------------------------+
| B38400               | 38400 波特                                |
+---------------------+-----------------------------------------+
| B57600               | 57600 波特                                |
+---------------------+-----------------------------------------+
| B115200            | 115200 波特                              |
+---------------------+-----------------------------------------+
| EXTA                  | 外部時(shí)鐘律                              |
+---------------------+-----------------------------------------+
| EXTB                  | 外部時(shí)鐘律                              |
+---------------------+-----------------------------------------+
| CSIZE                 | 數(shù)據(jù)位的位掩碼                    |
+---------------------+-----------------------------------------+
| CS5                     |  5個(gè)數(shù)據(jù)位                               |
+---------------------+-----------------------------------------+
| CS6                     | 6個(gè)數(shù)據(jù)位                                 |
+---------------------+-----------------------------------------+
| CS7                     | 7個(gè)數(shù)據(jù)位                                 |
+---------------------+-----------------------------------------+
| CS8                     | 8個(gè)數(shù)據(jù)位                                 |
+---------------------+-----------------------------------------+
| CSTOPB            | 2個(gè)停止位(不設(shè)則是1個(gè)停止位)  |
+---------------------+-----------------------------------------+
| CREAD               | 接收使能                                   |
+---------------------+-----------------------------------------+
| PARENB            | 校驗(yàn)位使能                               |
+---------------------+-----------------------------------------+
| PARODD           | 使用奇校驗(yàn)而不使用偶校驗(yàn) |
+---------------------+-----------------------------------------+
| HUPCL               | 最后關(guān)閉時(shí)掛線(放棄DTR)            |
+---------------------+-----------------------------------------+
| CLOCAL            | 內(nèi)部線路 - 不改變端口所有者     |
+---------------------+-----------------------------------------+
| LOBLK               | 塊作業(yè)控制輸出                          |
+---------------------+-----------------------------------------+
| CNET_CTSRTS  | 硬件流控制使能                      |
| CRTSCTS             | (并非所有硬件都支持)                |
+---------------------+-----------------------------------------+

c_cflag成員包含了兩個(gè)應(yīng)該一直激活的選項(xiàng),CLOCAL和 CREAD.These will ensure that your program does not
become the ‘owner‘ of the port to sporatic job control and hangup signals,and also that the serail
interface driver will read incomfing data bytes.

波特率常數(shù)(CBAUD,B9600,等)被用于沒有c_ispeed 和 c_ospeed成員的早期接口.下一小節(jié)中將使用POSIX函數(shù)設(shè)置波特率.

不要直接去初始化c_cflag的(或其它標(biāo)志的)成員;你應(yīng)該總是去使用逐位的AND,OR和NOT操作符去設(shè)置或清除成員中的位.
不同版本的操作系統(tǒng)(甚至補(bǔ)丁)都可以不同方式地使用這些位,所以用逐位操作符將會(huì)避免你使用將在更新的串口驅(qū)動(dòng)
中使用的位標(biāo)志.

2.2.1 設(shè)置波特率

不同的系統(tǒng)的波特率儲(chǔ)存在不同的位置.早期的接口用表4中的某一個(gè)波特率常數(shù)儲(chǔ)存在c_cflag中,然而更新的接口則
是使用c_ispeed和c_ospeed去儲(chǔ)存實(shí)際的波特率值.

cfsetospeed和cfsetispeed函數(shù)用來設(shè)置termios結(jié)構(gòu)中的波特率,不管是在哪一個(gè)系統(tǒng)接口下.一般你可以用以下的代
碼設(shè)置波特率:

listing-2 Setting the baud rate.

stuct termios options;

/* Get the current optinos 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);

tcgetattr(3) 函數(shù)將當(dāng)前串行端口的配置填充到options結(jié)構(gòu)中.在我們設(shè)置波特率,激活本地模式和串行數(shù)據(jù)接收后,用
tcsetattr(3)去設(shè)置新的配置.TCSANOW常數(shù)指定所有的更改立即生效,而不會(huì)去等待輸出的數(shù)據(jù)發(fā)送完畢和輸入的數(shù)據(jù)接收
完畢,也可以用其它的常數(shù)去等待輸入和輸出的完成或者刷新輸入和輸出緩存.

大多數(shù)系統(tǒng)不支持輸入與輸出的速率不等,所以為了可移植性必須將它們設(shè)成相等的值.

表5 - tcsetattr可設(shè)置常量
+---------------------+-----------------------------------------+
| 常量                   | 說明                                             |
+---------------------+-----------------------------------------+
| TCSANOW        | 不等數(shù)據(jù)傳輸完全就改變|
+---------------------+-----------------------------------------+
| TCSADRAIN     | 等待所有數(shù)據(jù)傳輸結(jié)束     |
+---------------------+-----------------------------------------+
| TCSAFLUSH    | 清空輸入輸出緩沖區(qū)并設(shè)置|
+---------------------+-----------------------------------------+

2.2.2 設(shè)置字符的大小

不象波特率,設(shè)置字符大小沒有可用的函數(shù).你不得不用位掩碼去設(shè)置它們.字符大小用位指定:

options.c_cflag &= ~CSIZE; /* mask the character size bits */
options.c_cflag |= CS8; /* select 8 data bits */

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

類似字符大小,你必須手工激活奇偶校驗(yàn)和設(shè)置校驗(yàn)類型.UNIX串行驅(qū)動(dòng)支持偶,奇和無校驗(yàn)位.space(0)將用更好的方式去
表示.

.NO parity(8N1):

options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= ~CS8;

.Even parity(7E1):

options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;

.Odd Parity(7O1):

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;

2.2.4 設(shè)置硬件流控制

一些版本的UNIX支持使用CTS(Clear to Send)和RTS(Requeut to send)信號(hào)線的硬件流量控制.如果你的系統(tǒng)中定義了
CNEW_RTSCTS或者CRTSCTS常數(shù),那么就可能支持硬件流量控制.以下可以激活硬件流量控制:

options.c_cflag |= CNEW_RTSCTS; /* also called CRTSCTS */

類似地可以這樣關(guān)閉硬件流量控制:

options.c_cflag &= ~CNEW_RTSCTS;


2.3 本地選項(xiàng)

本地模式c_lflags控制驅(qū)動(dòng)程序如何管理輸入字符.一般而言,你可以配置c_lflag為規(guī)范或者原始輸入.

表6 - c_lflag成員可設(shè)置常量
+---------------------+-----------------------------------------+
| 常量                   | 說明                                             |
+---------------------+-----------------------------------------+
| ISIG                     | 將SIGINTR, SIGSUSP, SIGDSUSP
               |和  SIGQUIT信號(hào)使能            |
+---------------------+-----------------------------------------+
| ICANON             | 標(biāo)準(zhǔn)(canonical)輸入模式使能
(否則是原始[raw]方式)          |
+---------------------+-----------------------------------------+
| XCASE               | 映射大寫字母為 \小寫字母(此常量已過時(shí))  |
+---------------------+-----------------------------------------+
| ECHO                | 輸入字符回顯使能                |
+---------------------+-----------------------------------------+
| ECHOE               | 刪除字符回顯為BS-SP-BS使能 |
+---------------------+-----------------------------------------+
| ECHOK               | kill字符后回顯NL(新行)字符 |
+---------------------+-----------------------------------------+
| ECHONL            | 回顯NL字符                            |
+---------------------+-----------------------------------------+
| NOFLUSH         | 取消中斷或退出字符后清空輸入緩沖區(qū)|
+---------------------+-----------------------------------------+
| IEXTEN              | 擴(kuò)展功能使能                         |
+---------------------+-----------------------------------------+
| ECHOCTL         | 回顯控制字符為‘^字符‘, 刪除字符為‘~?‘|
+---------------------+-----------------------------------------+
| ECHOPRT         | 回顯被刪除的字符為字符刪除|
+---------------------+-----------------------------------------+
| ECHOKE              | 在行kill字符時(shí)回顯全行BS-SP-BS|
+---------------------+-----------------------------------------+
| FLUSHO            | 清空輸出                                   |
+---------------------+-----------------------------------------+
| PENDIN              | 在下一個(gè)讀入或輸入字符
                                                  時(shí)重打入等待輸入 數(shù)據(jù)   |
+---------------------+-----------------------------------------+
| TOSTOP            | 在后臺(tái)輸出時(shí)發(fā)送SIGTTOU信號(hào)|
+---------------------+-----------------------------------------+

2.3.1 選擇規(guī)范輸入
規(guī)范輸入是面向行的輸入方式.輸入字符被放進(jìn)用于和用戶交互可以編輯的緩存區(qū)中,直到讀入回車鍵或者換行符才結(jié)束.
當(dāng)選擇這種模式時(shí),你一般可以使用ICANON,ECHO和ECHOE幾個(gè)選項(xiàng):

options.c_lflag |= ( ICANON | ECHO | ECHOE );

2.3.2 選擇原始輸入
原始輸入是未經(jīng)處理的.當(dāng)接收時(shí),輸入的字符在它們被收到后立即被傳送.使用原始輸入時(shí),一般你可以取消選擇
ICANOON,ECHO,ECHOE和ISIG選項(xiàng):
options.c_lflag &= ~ ( ICANON | ECHO | ECHOE );

2.3.3 輸入回顯的注意事項(xiàng)
輸入模式c_iflag控制端口接收端的字符輸入處理.類似于c_cflag,儲(chǔ)存在c_iflag中的值是所需選項(xiàng)的逐位或.

2.4 輸入選項(xiàng)

Table 7

2.4.1 設(shè)置輸入奇偶選項(xiàng)

當(dāng)你激活c_cflag中的奇偶檢驗(yàn)后,你應(yīng)該激活輸入的奇偶檢驗(yàn).與之相關(guān)的常數(shù)有INPCK,IGNPAR,PARMRK和ISTRTP.一般你
將選擇INPCK和ISTRTP去激活檢驗(yàn)和移除奇偶位:

options.c_iflag |= (INPCK | ISTRIP );

IGNPAR有些危險(xiǎn),它告訴串行驅(qū)動(dòng)忽略奇歐錯(cuò)誤,繼續(xù)傳送字符就好像沒有錯(cuò)誤發(fā)生一樣.這可能對檢驗(yàn)通訊鏈路的質(zhì)量
有幫助,當(dāng)一般情況下由于實(shí)際原因而不使用.

PARMRK導(dǎo)致奇偶錯(cuò)誤在輸入流中用特殊字符被標(biāo)記.如果IGNPAR被激活,在每一個(gè)奇偶錯(cuò)誤發(fā)生的字符之前,NULL字符
(000八進(jìn)制)將被發(fā)送給你的程序.否則,DEL(177八進(jìn)制)和 NUL字符將和錯(cuò)誤的字符一起被發(fā)送.

2.4.2 設(shè)置軟件流控制

軟件流控制可以用IXON,IXOFF和IXANY常數(shù)來激活:

options.c_iflag |= (IXON | IXOFF | OXANY );

取消它僅需將那些位掩住:

options.c_iflag &= ~(IXON | IXOFF | OXANY );

IXON(起始數(shù)據(jù))和XOFF(終止數(shù)據(jù))在以下介紹的c_cc數(shù)組中被定義

2.5 輸出選項(xiàng)

c_oflag包含了輸出過濾選項(xiàng).類似于輸入模式,你可以選擇已預(yù)處理或者原始的數(shù)據(jù)輸出.

Table 8

2.5.1 選擇預(yù)處理的輸出

可以通過設(shè)置OPOST選項(xiàng)來選擇預(yù)處理的輸出:

options.c_oflag |= OPOST;

在所有各種選項(xiàng)中,你也許僅僅可以使用ONLCR選項(xiàng),它將新行映射成CR和LF兩個(gè)符號(hào).
其它的輸出選項(xiàng)主要是由于過去的行式打印機(jī)和終端的速率不能跟上串行數(shù)據(jù)流.

2.5.2 選擇原始輸出

原始輸出可以用c_oflag的OPOST選項(xiàng)

options.c_oflag &= ~OPOST;

當(dāng)OPOST選項(xiàng)取消后,所有c_oflag的其它選項(xiàng)位都忽略.


2.6 控制字符

c_cc字符數(shù)組包含了過時(shí)參數(shù)和控制字符的定義.數(shù)組中的每一個(gè)元素都用常數(shù)定義.

Table 9

2.6.1 設(shè)置軟件流控制字符

c_cc數(shù)組中的VSTART 和 VSTOP是勇于軟件流控制的字符.一般而言,它們應(yīng)該被設(shè)置成
DC1(021八進(jìn)制)和DC3(023八進(jìn)制),分別表示ASCII碼中的XON和XOFF字符.

2.6.2 設(shè)置讀超時(shí)

UNIX串行接口驅(qū)動(dòng)提供了對字符和數(shù)據(jù)包的讀超時(shí)控制.c_cc數(shù)組中的VMIN和VTIME就是
這樣的兩個(gè)控制字符.在規(guī)范的輸入模式下或者當(dāng)NDELAY選項(xiàng)在對文件操作的open或fcntl
被指定時(shí),這兒的超時(shí)控制就被忽略而使用無效.

VMIN指定了最少讀取的字符數(shù).如果被設(shè)置為零,那么VTIME值就指定了讀取每個(gè)字符的等待
時(shí)間.注意的是,這并不意味著讀取N字節(jié)的read系統(tǒng)調(diào)用將會(huì)等待到讀取N個(gè)字符為止.相反,
這個(gè)超時(shí)控制僅僅用于第一個(gè)字符,read系統(tǒng)調(diào)用將立即返回有效的字符數(shù)(倚賴于read請求
的字符數(shù)).

/*------這地方?jīng)]明白,好像是如果你請求了n個(gè)字節(jié),這樣設(shè)置的話,當(dāng)讀到一個(gè)字
節(jié)的話,read立即返回,并返回為n,也許這種情況下,多用于1個(gè)字節(jié)的超時(shí)讀取,n=1.所以這種i
情況下讀取n個(gè)字節(jié)的話,應(yīng)該for(int i = 0;i< n; i++) read(fd,c,1);
如果是這樣的話,原文這樣寫就好懂多了.
Rather,the timeout will apply the first charater and the read call will return one
or zero,at most one byte.So if you want to read n bytes,you should loop again,which
is up to the number you want to request.
*/

如果VMIN非零,VTIME指定了讀取第一個(gè)字符的等待時(shí)間,如果在給定時(shí)間內(nèi)讀取了一個(gè)字符,那么
read系統(tǒng)調(diào)用將阻塞直到所有VMIN指定的字符數(shù)被讀取.也就是說一旦讀到第一個(gè)字符,串行接口
驅(qū)動(dòng)將期望收到完整的VMIN長度的數(shù)據(jù)包.如果在給定的時(shí)間內(nèi)沒有沒有讀到任何字符.read調(diào)
用將會(huì)返回為零.這種設(shè)置要求串行驅(qū)動(dòng)準(zhǔn)確地讀取N字節(jié)的字符,read調(diào)用要么返回為零或者N.
但是,超時(shí)僅僅指定在讀取第一個(gè)字符,所以如果由于某種原因,驅(qū)動(dòng)丟失了N字節(jié)數(shù)據(jù)包中的一個(gè)
字符,那么read調(diào)用將會(huì)永久性地阻塞在這兒,等待更多的輸入字符.

VTIME是以1/10秒為單位指定接收字符的超時(shí)時(shí)間.如果VTIME設(shè)置為零(缺省情況下),而該端口又沒
有用open或fcntl設(shè)置NDELAY,read將會(huì)阻塞不確定的時(shí)間.


第三章 Modem通訊
這一章描述了撥號(hào)電話調(diào)制解調(diào)器通訊的基本知識(shí).并給出了一個(gè)使用標(biāo)準(zhǔn)AT指令集的MODEM范例.

3.1 什么是Modem

MODEMs是一個(gè)將串行數(shù)據(jù)調(diào)制可以在模擬數(shù)據(jù)鏈路上傳輸?shù)囊欢l率的設(shè)備,比如電話線或者有線電
視線 . 一個(gè)標(biāo)準(zhǔn)的電話調(diào)制解調(diào)將串行數(shù)據(jù)轉(zhuǎn)換成可以可以在電話線上傳輸?shù)囊粽{(diào);由于這種轉(zhuǎn)換
的速度和復(fù)雜,這些音調(diào)聽起來更象大聲的尖叫.

現(xiàn)在的電話MODEMs可以以每秒53,000位,也就是53kbps的速度在電話線上傳輸數(shù)據(jù),另外大多數(shù)的MODEMs
使用數(shù)據(jù)壓縮技術(shù)提高傳輸速率,有些類型的數(shù)據(jù)可以超過100kbps.

3.2 與MODEM通訊

第一步是打開并配置原始輸入的端口
Listing 3 配置原始輸入端口
int fd;
struct termios options;

/*打開端口*/
fd = open(‘/dev/ttyf1‘,O_RDWR|O_NOCTTY|O_NDELAY);

fcntl(fd,F_SETFL,0);

/*獲取當(dāng)前選項(xiàng)*/
tcgetattr(fd,&options);

/*設(shè)置原始輸入,1秒的超時(shí)*/
options.c_cflag |= (CLOCAL|CREAD);
options.c_lflag &= ~(ICANON | ECHO | ECHOE |ISIG);
optiions.c_oflag &= ~OPOST;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;

/*設(shè)定選項(xiàng)*/
tcsetattr(fd,TCSANOW,&options);

下一步是建立預(yù)MODEM的通訊.最好的方法是發(fā)送AT命令給MODEM.這也可以讓MODEM去探測你
將使用的波特率.當(dāng)MODEM打開并成功地連接上后,它將回應(yīng)‘OK‘.

Listing 4 初始化MODEM
int /* 返回值 0 = 成功, -1 = 失敗 */
init_modem(int fd) /* 串行端口文件描述符 */
{
char buffer[255]; /* 輸入緩沖區(qū) */
char *bufptr; /* 緩存區(qū)中的當(dāng)前字符 */
int  nbytes; /* 讀取的字節(jié)數(shù) */
int tries; /* 目前重試的次數(shù) */

for(tries = 0; tries < 3 ;tries ++)
{
/*發(fā)送AT命令,后跟一個(gè)CR */
if(write(fd,‘AT\r‘,3) < 3)
continue;

/*將字符讀入字符串緩沖中,直到一個(gè)新行 */
bufptr = buffer;
while( ( nbytes = read(fd,bufptr,buffer+sizeof(buffer) - bufptr -1 )) > 0)
{
bufptr += nbytes;
if( bufptr[-1] == ‘\n‘ || bufptr[-1] == ‘\r‘ )
break;
}

/*設(shè)置 NULL中止字符串,看我們是否得到了一個(gè)成功的回應(yīng) */
*bufptr = ‘\0‘;
if( strncmp(buffer,‘OK‘,2) == 0)
return (0);
}
return (-1);
}

3.3 標(biāo)準(zhǔn)的MODEM命令

大多數(shù)的MODEM支持AT命令集,所以每個(gè)命令前冠以‘AT‘.每個(gè)命令按照以下根式被發(fā)送:AT+指定的命令+回車字符
(CR,015八進(jìn)制).在處理命令之后,MODEM將會(huì)根據(jù)命令回應(yīng)相應(yīng)的文本消息.

3.3.1 ATD ----撥單個(gè)數(shù)字

ATD命令撥指定的數(shù)字.除了數(shù)字和長劃符號(hào)外,你可以指定音調(diào)(‘T‘),脈沖(‘P‘),每秒鐘的暫停(‘,‘)和等待撥號(hào)音(‘W‘):
ATDT 555-1212
ATDT 18009009009W1234,1,1234
ATD  T555-1212WP1234

MODEM的回應(yīng)消息有以下幾種:
NO DIALTONE
BUSY
NO CARRIER
CONNECT
CONNECT baud

3.3.2 ATH---掛起

ATH命令導(dǎo)致MODEM掛起.因?yàn)镸ODEM必須是在‘命令‘模式中,你也許在普通的電話呼叫中不使用它.

如果DTR被dropped,大多數(shù)MODEM也會(huì)掛起.你可以通過在至少一秒的時(shí)間中設(shè)置波特率為0實(shí)現(xiàn)這一點(diǎn).DroppingDTR也會(huì)讓MODEM
回到命令模式中.

在一次成功的掛起之后,MODEM將會(huì)回應(yīng)‘NO CARRIER‘.如果MODEM仍然是被連接的,‘CONNECT‘或者‘CONNECT baud‘消息將會(huì)被發(fā)送.

3.3.3 ATZ---重置MODEM命令

ATZ命令將重置MODEM.MODEM將回應(yīng)‘OK‘.

3.4 一般MODEM通訊的問題

首先最重要的是,不要忘記取消輸入回顯.輸入回顯將會(huì)造成MODEM和機(jī)器之間的一次反饋.

其次,當(dāng)發(fā)送MODEM命令時(shí),你必須以回車CR來結(jié)束它,而不是一個(gè)新行NL.C語言中CR的字符是‘\r‘.

最后,當(dāng)使用MODEM時(shí),取保你使用的是MODEM所支持的波特率.盡管許多MODEM可以自動(dòng)波特率探測,但一些仍然有19.2kbps的限制,
不得不注意.

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多

    日韩精品视频高清在线观看| 亚洲熟妇av一区二区三区色堂| 日本淫片一区二区三区| 欧美成人精品国产成人综合| 黄片在线观看一区二区三区| 国产日韩精品激情在线观看| 亚洲男女性生活免费视频| 国产偷拍精品在线视频| 亚洲一区二区欧美在线| 中文字幕亚洲视频一区二区| 亚洲精品高清国产一线久久| 东京不热免费观看日本| 亚洲国产黄色精品在线观看| 免费播放一区二区三区四区| 日韩精品中文字幕亚洲| 国产精品免费福利在线| 日韩在线免费看中文字幕| 亚洲一区二区三区免费的视频| 亚洲中文字幕三区四区| 欧美丰满大屁股一区二区三区| 国产精品免费精品一区二区| 亚洲欧美日本视频一区二区| 91日韩在线观看你懂的| 国产欧洲亚洲日产一区二区| 久久国产成人精品国产成人亚洲 | 免费午夜福利不卡片在线 视频| 日本人妻中出在线观看| 亚洲精选91福利在线观看 | 国产一区二区精品丝袜| 不卡一区二区在线视频| 国产精品福利一级久久| 欧美日韩一区二区午夜| 欧美成人国产精品高清| 麻豆剧果冻传媒一二三区| 深夜少妇一区二区三区| 激情内射日本一区二区三区| 国产成人午夜在线视频| 日韩欧美一区二区不卡视频| 青草草在线视频免费视频| 国产农村妇女成人精品| 日韩欧美二区中文字幕|