1. 程式人生 > >基於VC++的串列埠程式設計

基於VC++的串列埠程式設計

序列通訊介面標準有多個版本,但是基本上都是在RS-232標準的基礎上發展而來。RS-232C標準時美國EIA和BELL等公司一起開發並於1969年公佈的通訊協議。1997年TIA發不了最新的一個版本,命名為TIA/EIA-232-F。ITU和CCITT釋出了一個類似的標準-V.28。RS-232C標準最初是為遠端通訊連線資料終端裝置DTE和資料通訊裝置DCE而制定的。因此RS-232C標準中所提到的傳送和接收都是站在DTE立場上,而不是站在DCE的立場上來定義的。
RS-232採用負邏輯,即+3V~+15V表示邏輯0,而-3V~-15V表示邏輯1。而在RTS/CTS/DSR/DTR/DCD等控制線上,+3V~+15V表示訊號有效,-3V~-15V表示訊號無效。
RS-232C並未定義聯結器的物理特性,因此出現了DB-25、DB-15和DB-9各種型別的聯結器,其引腳的定義也各不相同,DB9定義如圖1所示。通訊速率低於20kbps時,且碼元畸變小於4%時,要求驅動器的負載電容小於2500pF,支援最長距離為15m。

image

圖1 RS232 DB9引腳定義

PC機的每個串列埠都保留了一序列的埠資源,大多數都有一個指定的中斷請求IRQ或中斷請求級別,埠被命名為COM1、COM2等。在Widnows中可以在控制面板中瀏覽埠資源。埠可以使用硬體支援的任何地址和IRQ號,每個埠保留8個連續地址,從基址開始的暫存器。序列介面包括4個主要暫存器,即控制暫存器、狀態暫存器、資料輸入暫存器及資料輸出暫存器。

序列通訊協議分為同步協議和非同步協議
(1)面向字元的同步協議,這種協議的典型代表是IBM公司開發的BSC協議。它的特點是一次傳送由若干字元組成的資料塊,而不是隻傳送一個字元,並規定了10個字元作為這個資料塊的開頭和結束標誌以及整個傳輸過程的控制資訊,也叫做通訊控制字。此種協議涉及到“資料透明”和“字元填充技術”。
(2)面向位元的同步協議HDLC,不是靠特定字元來標識幀的開始和結束,故稱“面向位元”的協議。包含有標識場、地址場、控制場、資訊場和幀校驗資訊。
(3)起止式非同步協議,一個字元一個字元地傳輸,並且傳送一個字元總是以起始位元開始,以停止位結束,字元之間沒有固定的時間間隔要求。起始位元是用來通知收方,以此來重新核對收發雙方同步。若接收裝置和傳送裝置兩者的時鐘頻率略有偏差,也不會因偏差的累積而導致錯位。但是由於需要起始位和停止位元位這樣一些附加位,使得傳輸效率只有約80%。因此這種協議一般用在資料速率較慢的場合,而高速傳送時,一般要採用同步協議。

Widnows系統下進行串列埠程式設計有多種方法:1)API方式:CreateFile,GetCommState,SetCommState,ReadFile,WriteFile。2)ActiveX方式:MSComm控制元件。3)直接嵌入彙編方式:Windows98以前使用。4)VXD或者WDM實現。

MSComm控制元件通過序列傳輸和接收資料,並且在VC,CB以及Delphi等語言中都可以使用。MSComm提供了兩種處理通訊問題的方法:一是事件驅動方法,一是查詢法。

1.事件驅動方式
當發生特定事件,比如接收到一個字元或者一個RTS/CD事件時,就會發生OnComm事件,而且還可以檢查和處理通訊錯誤。在程式設計過程中,可以在OnComm事件處理函式中加入自己的處理程式碼。這種方法的優點是程式響應及時,可靠性高。每個MSComm控制元件對應著一個串列埠,如果應用程式要訪問多個換行埠,必須使用多個MSComm控制元件。

2.查詢方式
查詢方式本質上還是屬於事件驅動,通過檢查CommEvent屬性的值來檢查事件和錯誤,只要CommEvent屬性的值有了變化,就表明一個通訊事件或一個錯誤發生。如果應用程式較小,且自成一體,這種方法是比較方便的。

MSComm控制元件的屬性:
(1)CommPort屬性
void SetCommPort(short nNewValue);
short GetCommPort();
此屬性用於設定和返回連線的串列埠號,必須在開啟埠之前設定CommPort屬性。設定時,nNewValue可以設定成1~16的任何數(預設為1)。但是如果用PortOpen方法開啟一個並不存在的埠時,MSComm控制元件會產生錯誤68(裝置無效)。
(2)Settings屬性
void SetSettings(LPCTSTR lpszNewValue);
String GetSettings();
該屬性包含資料傳輸速率、奇偶校驗、資料位元、停止位元位引數,開啟埠前必須設定。當埠開啟時,如果value非法,則控制元件產生錯誤380(非法屬性值)。其中lpszNewValue用字串表示,由四個設定值組成,有如下的組成格式:
“BBBB,P,D,S”
BBBB為資料傳輸速率,P為就校驗,D為資料位元數,S為停止位元數。

(3)RThreshold屬性
void SetRThreshold(short nNewValue);
short GetRThreshold();
控制元件設定CommEvent屬性為comEvReceive併產生OnComm之前要接收的字元數。當接收字元後,如果RThreshold屬性為0,則不會產生OnComm事件。否則當接收緩衝區內位元組個數達到或超過該值就會產生OnComm事件。
(4)SThreshold屬性
void SetSThreshold(short nNewValue);
short GetSThreshold();
控制元件設定CommEvent屬性為comEvSend併產生OnComm事件之前,設定並返回傳輸緩衝區中允許的最小字元數。nNewValue代表在OnComm事件產生之前在傳輸緩衝區中的最小字元數。如果設定SThreshold屬性為0(預設值),資料傳輸事件不會產生OnComm事件。若設定SThreshold屬性為1,當傳輸緩衝區完全空時,MSCOmm空間產生OnComm事件。如果在傳輸緩衝區的字元數小於Value,CommEvent屬性設定為comEvSend,併產生OnComm事件。CommEvSend事件僅當字元數與SThreshold交叉時被啟用一次。
(5)InputMode屬性
void SetInputMode(long nNewValue);
long GetInputMode();
該屬性用於設定或者返回傳輸資料的型別,即以文字或二進位制方式取回資料
(6)InputLen屬性
void SetInputLen(short nNewVlaue);
short GetInputLen();
該屬性用於設定並返回Input屬性從接受緩衝區讀取的字元數。如果設定為0,則Input將讀取接受緩衝區的所有資料。在使用Input前,使用者可以選擇檢查InBufferCount屬性來確定緩衝區中是否已有需要數目的字元,該屬性在從輸出格式為定常資料的機器讀取資料時非常有用。
(7)InBufferSize屬性
void SetInBufferSize(short nNewValue);
short GetInBufferSize();
設定和返回輸入緩衝區的大小,預設值為1024位元組
(8)InBufferCount屬性
void setInBufferCount(short nNewValue);
short GetInBufferCount();
返回輸入緩衝區內的等待讀取的位元組個數,可以通過該屬性值為0來清除接收緩衝區
(9)Input屬性
VARIANT GetInput();
表示從接收緩衝區移走一串字元,將緩衝區接收到的資料讀入變數,屬性值為Variant型變數,即當InputMode屬性值為0(文字模式)時,變數中含String型資料。當InputMode屬性值為1(二進位制模式)時,變數中含有Byte型陣列資料。該屬性在埠未開啟時不可用,在執行時是隻讀的。
(10)PortOpen屬性
void SetPortOpen(BOOL bNewValue);
BOOL GetPortOpen();
開啟或關閉埠,通常需要顯式開啟或關閉串列埠。
(11)OutBuffersize屬性
void SetOutBufferSize(short nNewValue);
設定或者返回傳送緩衝區的大小,預設為512位元組。傳送緩衝區設定越大,應用程式可用記憶體就越小,然而如果設定太小,緩衝區將會溢位,除非使用握手協議。
(12)OutBufferCounter屬性
void SetOutBufferCounter(short nNewValue);
short GetOutBufferSize();
返回傳送緩衝區內等待發送的位元組數,可以用來清空傳送緩衝區。
(13)OutPut屬性
void SetOutput(const VARIANT &newValue);
向傳送緩衝區寫資料流,屬性為Variant變數。在埠未開啟時不可用,在執行時是隻寫的。Output屬性可以傳送文字資料或二進位制資料,通常傳送ANSI字串可以以文字方式傳送,如果資料包含了內嵌控制字元,Null字元等,必須將其作為二進位制傳輸。
(14)DTREnable屬性
void SetDTREnable(BOOL bNewValue);
BOOL GetDTREnable();
設定DTR線是否有效
(15)RTSEnable屬性
void SetRTSEnable(BOOL bNewValue);
BOOL GetRTSEnable();
設定RST線是否有效。
(16)DSRHolding屬性
判斷DSR線是否有效
(17)CDHolding屬性
判斷CD線的狀態是否有效
(18)CTSHolding屬性
用於判斷CTS先的狀態

API串列埠通訊程式設計
在WIN32 API中,串列埠使用檔案方式進行訪問,其操作的API基本上與檔案操作的API一致。
開啟串列埠:
Win32中用於開啟串列埠的API函式為CreateFile,其原型為:
HANDLE CreateFile (
LPCTSTR lpFileName, //將要開啟的串列埠邏輯名,如COM1 或COM2
DWORD dwAccess, //指定串列埠訪問的型別,可以是讀取、寫入或兩者並列
DWORD dwShareMode, //指定共享屬性,由於串列埠不能共享,該引數必須置為0
LPSECURITY_ATTRIBUTES lpsa, //引用安全性屬性結構,預設值為NULL
DWORD dwCreate, //建立標誌,對串列埠操作該引數必須置為OPEN EXISTING
DWORD dwAttrsAndFlags, //屬性描述,用於指定該串列埠是否可進行非同步操作,
//FILE_FLAG_OVERLAPPED:可使用非同步的I/O
HANDLE hTemplateFile //指向模板檔案的控制代碼,對串列埠而言該引數必須置為NULL
);
windows檔案操作分為同步I/O和重疊I/O(Overlapped I/O)兩種方式,在同步I/O方式中,API會阻塞直到操作完成以後才能返回(在多執行緒方式中,雖然不會阻塞主執行緒,但是仍然會阻塞監聽執行緒);而在重疊I/O方式中,API會立即返回,操作在後臺進行,避免執行緒的阻塞。重疊I/O非常靈活,它也可以實現阻塞(比如可以設定一定要讀取到一個數據才能進行到下一步操作)。如果進行I/O操作的API在沒有完成操作的情況下返回,我們可以通過呼叫GetOverLappedResult()函式阻塞到I/O完成後返回。
配置串列埠:
配置串列埠是通過改變裝置控制塊DCB(Device Control Block)的成員變數來實現的,接收緩衝區和傳送緩衝區的大小可通過SetupComm函式來設定。
DCB結構體定義為:
typedef struct _DCB { // dcb
DWORD DCBlength; // sizeof(DCB)
DWORD BaudRate; // current baud rate
DWORD fBinary: 1; // binary mode, no EOF check
DWORD fParity: 1; // enable parity checking
DWORD fOutxCtsFlow:1; // CTS output flow control
DWORD fOutxDsrFlow:1; // DSR output flow control
DWORD fDtrControl:2; // DTR flow control type
DWORD fDsrSensitivity:1; // DSR sensitivity
DWORD fTXContinueOnXoff:1; // XOFF continues Tx
DWORD fOutX: 1; // XON/XOFF out flow control
DWORD fInX: 1; // XON/XOFF in flow control
DWORD fErrorChar: 1; // enable error replacement
DWORD fNull: 1; // enable null stripping
DWORD fRtsControl:2; // RTS flow control
DWORD fAbortOnError:1; // abort reads/writes on error
DWORD fDummy2:17; // reserved
WORD wReserved; // not currently used
WORD XonLim; // transmit XON threshold
WORD XoffLim; // transmit XOFF threshold
BYTE ByteSize; // number of bits/byte, 4-8
BYTE Parity; // 0-4=no,odd,even,mark,space
BYTE StopBits; // 0,1,2 = 1, 1.5, 2
char XonChar; // Tx and Rx XON character
char XoffChar; // Tx and Rx XOFF character
char ErrorChar; // error replacement character
char EofChar; // end of input character
char EvtChar; // received event character
WORD wReserved1; // reserved; do not use
} DCB;

而SetupComm函式的原型則為:
BOOL SetupComm(
HANDLE hFile, // handle to communications device
DWORD dwInQueue, // size of input buffer
DWORD dwOutQueue // size of output buffer
);