介紹:
本文的目的是介紹如何在Win32中處理串口。串口通訊可以通過多種技術實現,例如:ActiveX,I/O存取和文件操作。本文介紹Win32平台下通過文件操作技術使用串口。程序員可以使用 Microsoft Visual C++ Version 6.0所提供的kernel32.lib。在Microsoft Windows(2000,Me,XP and 95/98)中,串口作為文件處理。因此可以通過Windows文件創建函數打開串口。
文章不僅介紹了串口通訊,也介紹了在串口通訊應用程序中實現多任務,多任務可以使串口通訊應用程序在同一時間處理更多的任務,例如:讀數據任務,發送數據任務,GUI任務等。
以下主題描述了Win32中基本的串口操作:
初始化/打開串口通訊
創建端口句柄
獲取配置(DCB)
修改配置
保存配置
設置通訊超時
接收/發送數據
發送數據
接收數據
關閉串口
設計步驟:
初始化/打開串口
打開串口的第一步是初始化或設置串口配置,目的是創建串口代理,整篇文章我們都將用文件句柄作為串口代理。
創建端口句柄
串口句柄是可以被用來存取的串口對象句柄,創建串口句柄的函數是CreateFile,如下代碼所示:
handlePort_ = CreateFile(portName, // 端口設備: 默認 "COM1"
GENERIC_READ | GENERIC_WRITE, // 設備打開模式: 允許讀寫
0, // 不共享
NULL, // 默認安全設置
OPEN_EXISTING, // 打開方式:打開已經存在的端口
0, // 默認
NULL); // 默認
如圖2所示,portName = "COM1": portName 示一個const char*變量,它指定想創建串口句柄的端口名稱。
圖2:CreateFile函數
獲取配置
在控制設備中獲取當前配置,配置中包含了用於設置串口通訊設備的參數。
可以用 GetCommState函數得到當前設備配置並用指定通訊設備的當前配置填充設備控制塊(DCB結構),如下代碼所示:
// 獲取串口當前配置
if (GetCommState(handlePort_,&config_) == 0)
{
AfxMessageBox("Get configuration port has problem.");
return FALSE;
}
修改配置
當你已經在DCB結構中獲取串口配置,你應該修改其中的參數,如下代碼所示:
// 指定用戶參數
config_.BaudRate = dcb.BaudRate; // 波特率
config_.StopBits = dcb.StopBits; // 停止位
config_.Parity = dcb.Parity; // 奇偶校驗
config_.ByteSize = dcb.ByteSize; // 數據位
DWORD BaudRate :
波特率 (默認 = 9600)
BYTE StopBits :
0,1,2 = 1, 1.5, 2 (默認 = 0)
BYTE Parity :
0-4= 無, 奇, 偶, 標志, 空格 (默認 = 0)
BYTE ByteSize :
數據位, 4-8 (默認 = 8)
對於典型的通訊,建議程序員使用默認值。圖3所示,Watch對話框顯示了典型通訊使用的默認值。
圖3:串口配置
保存配置
下一步是將已經修改的配置保存到設備控制中。調用SetCommState API函數保存配置。SetCommState函數設備控制塊(DCB結構)配置通訊設備。該函數重新初始化所有的硬件控制設定,但不清空輸入輸出隊列。代碼如下所示:
if (SetCommState(handlePort_,&config_) == 0)
{
AfxMessageBox("Set configuration port has problem.");
return FALSE;
}
設置通訊超時
開啟端口的最後一步是通過使用COMMTIMEOUTS數據結構和調用SetCommTimeouts函數進行通訊超時設置。如下代碼所示:
// COMMTIMEOUTS對象
COMMTIMEOUTS comTimeOut;
// 接收時,兩字符間最大的時延
comTimeOut.ReadIntervalTimeout = 3;
// 讀取每字節的超時
comTimeOut.ReadTotalTimeoutMultiplier = 3;
// 讀串口數據的固定超時
// 總超時 = ReadTotalTimeoutMultiplier * 字節數 + ReadTotalTimeoutConstant
comTimeOut.ReadTotalTimeoutConstant = 2;
// 寫每字節的超時
comTimeOut.WriteTotalTimeoutMultiplier = 3;
// 寫串口數據的固定超時
comTimeOut.WriteTotalTimeoutConstant = 2;
// 將超時參數寫入設備控制
SetCommTimeouts(handlePort_,&comTimeOut);
ReadIntervalTimeout
指定通訊線上兩個字符到達的最大時延,以毫秒為單位。在ReadFile操作期間,時間周期從第一個字符接收到算起。如果收到的兩個字符之間的間隔超過該值,ReadFile操作完畢並返回所有緩沖數據。如果ReadIntervalTimeout為0,則該值不起作用。
如果值為MAXDWORD, 並且ReadTotalTimeoutConstant和ReadTotalTimeoutMultiplier兩個值都為0, 則指定讀操作攜帶已經收到的字符立即返回,即使沒有收到任何字符。
ReadTotalTimeoutMultiplier
指定以毫秒為單位的累積值。用於計算讀操作時的超時總數。對於每次讀操作,該值與所要讀的字節數相乘。
ReadTotalTimeoutConstant
指定以毫秒為單位的常數。用於計算讀操作時的超時總數。對於每次讀操作,ReadTotalTimeoutMultiplier與所要讀的字節數相乘後與該值相加。
如果ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant都為0,則在讀操作時忽略總超時數。
WriteTotalTimeoutMultiplier
指定以毫秒為單位的累積值。用於計算寫操作時的超時總數。對於每次寫操作,該值與所要寫的字節數相乘。
WriteTotalTimeoutConstant
指定以毫秒為單位的常數。用於計算寫操作時的超時總數。對於每次寫操作, WriteTotalTimeoutMultiplier與所要寫的字節數相乘後與該值相加。
如果 WriteTotalTimeoutMultiplier 和 WriteTotalTimeoutConstant都為0,則在寫操作時忽略總超時數。
提示:用戶設置通訊超時後,如沒有出錯,串口已經被打開。
發送數據
串口數據發送多作為寫文件處理的,程序員可以應用文件操作函數發送數據到串口。采用WriteFile函數發送數據到串口。
if (WriteFile(handlePort_, // 文件句柄
outputData, // 數據緩沖區指針
sizeBuffer, // 字節數
&length,NULL) == 0) // 接收成功發送數據長度的指針
{
AfxMessageBox("Reading of serial communication has problem.");
return FALSE;
}
提示:如果函數成功,返回非0值
接收數據
串口數據接收多作為讀文件處理。程序員可以應用文件操作函數從串口接收數據。用ReadFile函數接收串口的數據。
if (ReadFile(handlePort_, // 句柄
inputData, // 數據緩沖區指針
sizeBuffer, // 字節數
&length, // 指向已經讀入的字節數
NULL) == 0) // 重疊I/O結構體
{
AfxMessageBox("Reading of serial communication has problem.");
return FALSE;
}
提示:如果函數成功,返回非0值
關閉串口
可以調用CloseHandle API函數關閉串口
if(CloseHandle(handlePort_) == 0) // 調用該函數關閉串口
{
AfxMessageBox("Port Closeing isn''t successed.");
return FALSE;
}
提示:如果函數成功,返回非0值
本文配套源碼