- 1 -
VC++實現串口通信的應用程序設計
摘 要:本文介紹了結合了Win32 的API 函數和C++類的基本思想封裝的一個串行通信類
CSerialPort 類。並通過具體的實例詳細介紹其在VC++6.0 下的實現串口通信方法和過程。
關鍵詞:VC++,串口通信,CSerialPort 類
1. 引言
在控制領域的研發中,PC 機與外圍控制設備的通訊方式有多種,如串行通信口、並行
通信口、一臺網口(需要網卡支持)、USB 通信口或自制危機接口卡。而串口通信則是在
數據通信速率部是很高的情況下,開發者所採用的最常見、最簡單、最通用的通信方式。並
且考慮到現在的PC 機標準配置都具備兩個串口,因此利用串口資源來開發PC 機與外圍控
制設備之間的通信應該是最方便快捷的[3]。
在目前常用的各種開發環境(如VB、VC 和Delphi 等)下實現串口通信的方式有很多
種:
首先,最簡便的方法是採用Microsofe 公司提供的ActiveX 控件實現串口通信,即
MSComm 控件。實現串口通信的編程方法原理上比較簡單,容易實現,但編程的靈活性稍差,
且應用程序運行時必須同時拷入與通信控件相關的文件。
其次,使用Win32 的API 函數實現串口通信亦是很好的方法。利用 API 函數實現串口
通信的編程方法功能強大 ,靈活性好 ,但原理上比較複雜 ,需要編程人員對串口的硬件工作
原理有較深入的瞭解。
最後,可以利用VC 運行時庫的標準通信函數實現串口通信。其編程原理簡單,但其使
用性和靈活性較差。
總之,各種串口通信的實現方式在使用條件、靈活性和複雜程度等方面各有優缺點,分
別適合於各自不同的應用場合。而本文介紹一個結合了Win32 的API 函數和C++類的基本
思想封裝了一個串行通信類CSerialPort 類,通過一個實例介紹,我們發現這個自定義的串
口通信類能夠使得串口通信的實現更加靈活、方便。
2. 串口通信的實現
雖然實現串口通信方法很多,但是一般來說,串行通信程序的工作過程一般分四步[2]:
(1)打開串口:在此步驟中,我們可以實現打開通信資源、設置通信參數、設置通信
事件、創建讀寫事件以及等待串口接收中斷等操作。
(2)讀串口:在此步驟中,當有字符或干擾到達串口時發生EV_ RXCHAR 消息的發
送 ,響應函數接收到此消息後讀取串口接收緩衝區。
(3)寫串口:該步驟是負責將要發送的字符寫入發送串口緩衝區。
(4)關閉串口。
2.1 CSerialPort 通信類的介紹
http://www.paper.edu.cn
- 2 -
2.1.1 CSerialPort 類的定義聲明
class CSerialPort
{
public:
void ClosePort();
CSerialPort();
virtual ~CSerialPort();
BOOL InitPort(CWnd* pPortOwner, UINT portnr = 1, UINT baud = 19200, char parity =
' N', UINT databits = 8, UINT stopbits = 1, DWORD dwCommEvents =
EV_RXCHAR, UINT writebuffersize = 1024);
HANDLE m_hComm;
BOOL StartMonitoring();
BOOL RestartMonitoring();
BOOL StopMonitoring();
DWORD GetWriteBufferSize();
DWORD GetCommEvents();
DCB GetDCB();
void WriteToPort(char* string);
Void WriteToPort(char* string,int n);
Void WriteToPort(LPCTSTR string);
void WriteToPort(LPCTSTR string,int n);
protected:
void ProcessErrorMessage(char* ErrorText);
static UINT CommThread(LPVOID pParam);
static void ReceiveChar(CSerialPort* port, COMSTAT comstat);
static void WriteChar(CSerialPort* port);
CWinThread* m_Thread;
CRITICAL_SECTION m_csCommunicationSync;
BOOL m_bThreadAlive;
HANDLE m_hWriteEvent;
HANDLE m_hShutdownEvent;
HANDLE m_hEventArray[3];
OVERLAPPED m_ov;
COMMTIMEOUTS m_CommTimeouts;
DCB m_dcb;
CWnd* m_pOwner;
UINT m_nPortNr;
char* m_szWriteBuffer;
DWORD _dwCommEvents;
DWORD m_nWriteBufferSize;
};
2.1.2 CSerialPort 類的函數說明
在構造函數 CSerialPort 中對該類的數據成員進行了初始化。InitPort 函數完成串口的初
始化工作,包括打開串口、設置 SPC 的參數、設置通信事件的時間、建立串口的設備控制
塊。由於串口是一種臨界資源,不允許多個線程或用戶同時訪問,因此在該函數中調用了兩
http://www.paper.edu.cn
- 3 -
個Windows API 函數EnterCriticalSection 和LeaveCriticalSection,以實現對串口的互斥訪問。
A,串口操作函數:
StartMonitoring 函數調用Windows API 函數:AfxBeginThread 啓動一個SPC 線程,打
開串口。
RestartMonitoring 函數調用CwinThread 的成員函數:ResumeThread 重啓SPC 線程,
重起串口;
StopMonitoring 函數調用CwinThread 的成員函數:SuspendThread 停止SPC 線程,關
閉串口。
B,串口讀寫函數:
WriteChar 函數調用Windows API 函數:WriteFile 向串口寫數據;
ReceiveChar 函數調用 Windows API 函數:ReadFile 從串口讀取數據。
WriteToPort 函數:另外擴充函數,通過不同的變量參數,適應不同的寫串口的需求。
CommThread 函數是SPC 的線程,完成SPC 的消息循環。該函數調用了WaitCommEvent
函數來等待事件消息,然後進行消息的處理和分發。在消息的處理中調用了WriteChar 函數
和ReceiveChar 函數。另外在這個SPC 線程函數中還進行了必要的異常處理。
C,其他的相關函數
其它的幾個函數 ProcessErrorMessage,GetDCB 和GetWriteBufferSize 則完成一些輔助
的功能。
2.2 CSerialPort 串口通信類的具體應用
前面介紹了CSerialPort 類的聲明以及其中一些重要的函數。下面介紹在VC++6.0 環境
下利用MFC 編寫一個基於對話框的串口通信測試的應用程序[1]。定義實現串口通信的類爲
CSerialPort。
2.2.1 串口初始化
在我們的例子中,我們在CSerialPort.h 中聲明一個串口類的對象:
CSerialPort m_SerialPort;
要實現串口首先需要對串口進行設置和初始化。打開串口後,才能對串口的狀態進行監
控。其串口初始化函數如下:
InitPort(this, nPort, band, checkbit, databits, stopbits,EV_RXFLAG | EV_RXCHAR,512);
初始化串口的狀態,每次只能初始化一個串口。其中參數nPort:端口號, band:波特率,
checkbit:校驗位, databits:數據個數, stopbits:停止位均可以通過界面設置,也可以在初始
化串口時直接定義。
初始化串口完畢後,需要通過StartMonitoring()啓動串口通信線程函數CommThread,
即可立即對所定義的串口進行監聽。
2.2.2 處理函數的定義
在文件CSerialPort.h 類CSerialPort 的定義中聲明自定義處理函數:
afx_msg void OnComm(WPARAM ch, LPARAM port);
在 CSerialPort.cpp 內添加函數OnComm()。實現了對接受到的數據的處理代碼。
在文件 CSerialPort.cpp 消息映射的BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP
之間添加自定義消息映射宏ON_MESSAGE(WM_COMM_RXCHAR, OnComm),即在接受
http://www.paper.edu.cn
- 4 -
到字節的情況下觸發函數。這樣就可以在串口上存在一個字節的時候就可以觸發OnComm
()函數來處理消息。
2.2.3 寫串口
在處理完接受的消息的後,就需要將反饋的消息再次寫到串口發送出來,從而完成串口
通信。在這裏我們使用m_SerialPort.WriteToPort(char* string,int n)來完成寫串口,其中定義
了寫到串口的字符串和字符的個數。在CSerialPort 類中,我們補充了其他的WriteToPort 的
函數以滿足其他情況下的需要,在使用的過程中大家可以根據需要選擇合適的寫串口函數,
也可以根據自己的需要來擴充其他的函數。
2.2.4 關閉串口
在串口通信完畢用m_SerialPort.ClosePort()來關閉串口。
3. 測試
使用“串口調試工具”對編寫的串口測試工具進行調試,用串口線將PC 機上的串口1 和
串口2 相連。將串口調試工具和串口測試工具的參數設置如下所示,其比特率,交驗位,
數據位,停止位設置必須相同,其兩個端口號分別選擇爲端口1,端口2。當兩個端口同時
打開的時候,PC 機上的串口連接線將兩個串口導通。當“串口調試工具”發送“this is a test
program!”信息時,在串口測試工具接受到該條信息。測試結果如下圖所示:圖1:串口調試
器發送信息;圖2:串口測試工具接受信息。
圖 1 串口調試器發送信息
圖 2 串口測試工具接受信息
4. 結束語
本文應用Win32 的API 函數和C++類的基本思想把對串口的操作封裝成一個串口通信
類的CSeriaPort,採用該串口通信類對串口設備的“屏蔽”,增加對串口操作的透明度,提高
串口傳輸數據的可靠性,方便程序員的編程。另外,還可以根據自己的需求對CSeriaPort
類進行功能擴充。
http://www.paper.edu.cn
參考文獻
[1] Kruglinski.《Visual C++ 技術內幕》[M].北京:電子工業出版社,1999.
[2] 李現勇.《Visual C+ +串口通信技術與工程實踐》[M].北京:人民郵電出版社.
[3] 王穎.《用 VC6.0 實現串行通信的三種方法》[J].VC 知識庫在線幫助期,http://www.vckbase.com/,
2000 第9 期:18-20.
Application design of serial communication based on VC++
Wang Zhen, Chen Yongtai
school of information engineering,Wuhan University of Technology, Wuhan, PRC (430070)
Abstract
This paper introduces a new Serial Port class, which is named CSerialPort and is comprised based on
Win32 API and some C++ classes. By introducing one example, we analysis the application of the
CSerialPort class in the serial communication based on VC++.
Keywords:VC++,Serial Communication,Class CSerialPort