軟件介紹
一個由印度人編寫的VC串口類(也是一種VC串口控件),他還配合這個類寫了VC 串口通信方面的一些基礎知識,如怎麼用VC打開串口,如何對串口進行配置,讀串口、寫串口等。
這個類有點特別,它沒有使用事件驅動原理,它是以查詢方式工作的。
簡介:
對沒有接觸過串口通信的VC程序員來說顯得非常困難,很久以前我在 codeguru.com 上搜索過串口通信相關信息得到了非常大的幫助,從那時起能編寫一個簡單易用的VC 串口類是我的夢想。
經過七個月在串口通信編程方面實踐經驗後,我編寫了一個基於API實現的簡單串口類,在介紹此串口類之前先介紹一下VC 串口通信方面的基礎知識。
串口通信基礎:
串口通信每個字節的傳輸以串行的方式進行,傳輸時低位先被發送,一個“包”由“開始位”+“數據位”+“奇偶校驗位”(不是必需)+“停止位” 組成。
奇偶校驗位是可選的,它用來進行錯誤檢測,您可以在軟件裡設置是否啟用奇偶校驗,而且還可以選擇啟用哪種校驗方式,如“奇”校驗(ODD)或“偶”校驗(EVEN)。
PC機通過串口發送和接收數據的流程如下:
1、打開串口
2、 配置串口通信參數,如:波特率、校驗方式、數據位數等 3、 設置通信超時時間 4、 寫數據 5、 讀數據 6、 關閉串口
用VC打開串口:
打開串口可以用API函數 CreateFile() 來實現,打開串口有兩種方式,分別為重疊I/O(OVERLAPPED)和非重疊(NON-OVERLAPPED)方式(其實這兩種方式分別對應串口的異步和同步通信方式-VC串口通信技術網注)。CSerialCom 類工作於非重疊(NON-OVERLAPPED)模式(即同步通信模式),有關更多 OVERLAPPED 和 NON-OVERLAPPED 方面的消息可查詢MSDN。
串口配置:
VC 串口通信程序編寫最重要的課題就是如何利用 DCB 結構來配置串口,對 DCB 結構填充不正確是大多數人常反犯的毛病,通常串口通信程序編寫好後出現這樣那樣的問題就是因為這個結構沒有正確填充所致。在利用 CreateFile() 函數打開串口時就需要我們對串口的波特率、校驗方式、數據位、停止位等進行配置。
設置超時時間:
每次打開串口時都必須利用 COMMTIMEOUTS 結構設置超時時間,如果未設置此結構,通信將以默認或上次打開此串口時設置的超時時間為准。
寫串口:
WriteFile() 函數可實現這一功能,在執行這一動作之前必須先打開並配置好串口。
讀串口:
利用 ReadFile() 可實現這一功能,同樣,在執行這一動作之前必須先打開並配置好串口。
關閉串口:
不再使用已經打開的串口後必須關閉它以將此串口資源釋放出來,這樣其它程序才可能再使用此串口資源,外於非重疊I/O(NON-OVERLAPPED)模式下的串口在打開期間是不能被其它程序或同一程序內的其它線程訪問的。使用 CloseHandle() 函數可以關閉串口, CloseHandle() 函數只有一個參數,它是由 CreateFile() 打開串口時返回的設置句柄。
CSerialCom 串口類
CSerialCom 類使用六個函數來實現上面提到的功能,它們分別是:
BOOL CSerialCom::OpenPort(CString portname) { portname= "//./" + portname; hComm = CreateFile(portname, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if(hComm==INVALID_HANDLE_VALUE){ return false;} else return true; }
OpenPort()成員函數用來打開串口,它需要的參數只有一個,就是串口名,如“COM1”,“COM2” 。
BOOL CSerialCom::ConfigurePort(DWORD BaudRate, BYTE ByteSize, DWORD fParity, BYTE Parity, BYTE StopBits) { if((m_bPortReady = GetCommState(hComm, &m_dcb))==0) { MessageBox("GetCommState Error","Error",MB_OK+MB_ICONERROR); CloseHandle(hComm); return false; } m_dcb.BaudRate =BaudRate; m_dcb.ByteSize = ByteSize; m_dcb.Parity =Parity ; m_dcb.StopBits =StopBits; m_dcb.fBinary=TRUE; m_dcb.fDsrSensitivity=false; m_dcb.fParity=fParity; m_dcb.fOutX=false; m_dcb.fInX=false; m_dcb.fNull=false; m_dcb.fAbortOnError=TRUE; m_dcb.fOutxCtsFlow=FALSE; m_dcb.fOutxDsrFlow=false; m_dcb.fDtrControl=DTR_CONTROL_DISABLE; m_dcb.fDsrSensitivity=false; m_dcb.fRtsControl=RTS_CONTROL_DISABLE; m_dcb.fOutxCtsFlow=false; m_dcb.fOutxCtsFlow=false; m_bPortReady = SetCommState(hComm, &m_dcb); if(m_bPortReady ==0) { MessageBox("SetCommState Error","Error",MB_OK+MB_ICONERROR); CloseHandle(hComm); return false; } return true; }
ConfigurePort() 函數對串口地配置,它所需參數如下所示:
DWORD BaudRate
DWORD BaudRate 用來描述串口通信使用的波特率,如此參數為 CBR_9600 時,波特率為9600bps,PC機支持的標准波特率有:CBR_110 ,CBR_300 ,CBR_600 ,CBR_1200,CBR_2400,CBR_4800,CBR_9600,CBR_14400, CBR_19200,CBR_38400,CBR_56000,CBR_57600,CBR_115200,CBR_128000,CBR_256000
BYTE ByteSize
此參數描述數據位位數,標准值為8或4。
DWORD fParity
奇偶校驗開關,如果此參數為真(TRUE)則開啟奇偶校驗,為假(FALSE)則關閉奇偶校驗。
BYTE Parity
校驗方式,可選方式如下:
●EVENPARITY
● MARKPARITY ● NOPARITY ● ODDPARITY ● SPACEPARITY
BYTE StopBits
停止位位數,可取值如下:
●ONESTOPBIT
● ONE5STOPBITS ● TWOSTOPBITS
備注:ConfigurePort() 函數是假定串口的流控制是由硬件來完成的,軟件在收發數據過程中不檢測CTS/RTS 和 Xon/Xoff 狀態,您可以修改DCB結構來啟用軟件流控制。
BOOL CSerialCom::SetCommunicationTimeouts(DWORD ReadIntervalTimeout, DWORD ReadTotalTimeoutMultiplier, DWORD ReadTotalTimeoutConstant, DWORD WriteTotalTimeoutMultiplier, DWORD WriteTotalTimeoutConstant) { if((m_bPortReady = GetCommTimeouts (hComm, &m_CommTimeouts))==0) return false; m_CommTimeouts.ReadIntervalTimeout =ReadIntervalTimeout; m_CommTimeouts.ReadTotalTimeoutConstant =ReadTotalTimeoutConstant; m_CommTimeouts.ReadTotalTimeoutMultiplier =ReadTotalTimeoutMultiplier; m_CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant; m_CommTimeouts.WriteTotalTimeoutMultiplier =WriteTotalTimeoutMultiplier; m_bPortReady = SetCommTimeouts (hComm, &m_CommTimeouts); if(m_bPortReady ==0) { MessageBox("StCommTimeouts function failed", "Com Port Error",MB_OK+MB_ICONERROR); CloseHandle(hComm); return false; } return true; }
SetCommunicationTimeouts() 成員函數用來設置讀/寫超時時間,它所需參數如下:
DWORD ReadIntervalTimeout
設置讀串口時,收到兩個字符的最大時間間隔,單位為毫秒。在執行ReadFile() 期間,一但收到兩個字符的時間間隔超過這一設定值,ReadFile()立即返回。如果這一參數設置為零,則表明這一特性未啟用。
ReadTotalTimeoutConstant
常量,用來計算讀操作總超時時間。每個讀操作過程中,這個參數被加到ReadTotalTimeoutMultiplier。如果ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant兩個參數都為零則表明總超時計算功能沒有啟用。
ReadTotalTimeoutMultiplier
用來保存讀操作總超時時間的
WriteTotalTimeoutConstant
常量,用來計算寫操作總超時時間。與ReadTotalTimeoutConstant差不多。
WriteTotalTimeoutMultiplier
用來保存寫操作總超時時間的,如果WriteTotalTimeoutMultiplier 和 WriteTotalTimeoutConstant兩參數均為零,表明寫操作總超時時間特性不被啟用。
例如,您需要傳送一塊數據包,設定了寫操作超時時間為500ms(每個字符間發送時間最大間隔),您可以用設置超時成員函數來設定,內容為:SetCommunicationTimeouts(0,500,0,0,0);如果設置成功,函數返回真,否則返回假。
BOOL CSerialCom::WriteByte(BYTE bybyte) { iBytesWritten=0; if(WriteFile(hComm,&bybyte,1,&iBytesWritten,NULL)==0) return false; else return true; }
WriteByte() 成員函數用來向串口寫數據。
BOOL CSerialCom::ReadByte(BYTE &resp) { BYTE rx; resp=0; DWORD dwBytesTransferred=0; if (ReadFile (hComm, &rx, 1, &dwBytesTransferred, 0)) { if (dwBytesTransferred == 1) { resp=rx; return true; } } return false; } View Code
ReadByte() 成員函數實現讀串口功能,如果您知道有數據發送來了,可能使用 ReadByte() 來讀取數據,如果不知道何時有數據發送過來,可以周期性調用此函數,當沒收到數據超過超時時間後, ReadByte() 自動返回。在實際應用中,通信雙方可能會以某種協議進行的,此時一般有表明通信數據包結束的標志,如3964協議的結束符是‘ETX’,您可能通過它來判斷是否傳輸結束。
void CSerialCom::ClosePort() { CloseHandle(hComm); return; }
ClosePort() 成員函數用來關閉一個已經打開的串口。
如何使用CSerialCom類
使用CSerialCom類前的准備工作:
1、復制SerialCom.h 和 SerialCom.cpp兩個文件到工程所在目錄
2、 在VC工程中導入這兩個文件 3、 加入#include "SerialCom.h"句代碼到程序適當位置 4、 創建CSerialCom類的一個實例現在就可以調用CSerialCom類成員函數來進行串口通信了,操作流程如下:
1 // 打開串口。 需要檢查函數返回值來判斷串口是否正確打開 2 port.OpenPort( ); 3 4 // 配置串口。需要檢查函數返回值來判斷否正確配置 5 port.ConfigurePort( ); 6 7 // 設置超時時間。需要檢查函數返回值來判斷否正確配置 8 port.SetCommunicationTimeouts( ); 9 10 // 寫串口,由於一次只能寫一個字節,一般需要多次調用此函數才能將需要發送的字符串發送完 11 port.WriteByte(); 12 13 // 讀串口,由於一次只能讀一個字節,一般需要多次調用此函數才能將需要讀取的字符串讀完 14 port.ReadByte( ); 15 16 // 關閉串口 17 port.ClosePort();
下載地址: http://pan.baidu.com/s/1mghzhvq (一個由印度人編寫的VC++串口類_serialport+CSerialCom_demo)