串列埠通訊基礎知識及VC++實現
串列埠是計算機上一種非常通用裝置通訊的協議。大多數計算機包含兩個基於RS232的串列埠。串列埠通訊的概念非常簡單,串列埠按位(bit)傳送和接收位元組。儘管比按位元組(byte)的並行通訊慢,但是由於串列埠通訊是非同步的,串列埠可以在使用一根線傳送資料的同時用另一根線接收資料。它很簡單並且能夠實現遠距離通訊。串列埠通訊最重要的引數是波特率、資料位、停止位和奇偶校驗。
而在VC++中實現串列埠通訊也是一名VC程式設計師必須要掌握的技能。下面結合例項詳細介紹在VC++中實現串列埠通訊的過程(完整的例項可在我的CSDN資源中下載:http://download.csdn.net/detail/margin1988/6408513
在這個例項中,實現了系統中可用串列埠的自動檢測(通過登錄檔資訊)、開啟、傳送、接收、關閉等基本的操作,若將串列埠線的TX(傳送)和RX(接收)引腳連起來,便採用了“一根線傳送資料的同時用另一根線接收資料”的方式測試了傳送和接收功能的可用性和正確性。該例項對於初學者學習和掌握基於VC的串列埠通訊將會有非常大的幫助。
(1)例項中所要用的主要控制元件及其屬性、事件設定情況:
控制元件 |
ID |
caption |
繫結變數 |
繫結事件 |
組合框 |
IDC_COMBO1 |
- |
CComboBox m_com; |
- |
按鈕 |
IDC_BUTTON1 |
開啟 |
CButton m_open; |
OnBnClickedButton1() |
按鈕 |
IDC_BUTTON2 |
傳送 |
CButton m_send; |
OnBnClickedButton2() |
按鈕 |
IDC_BUTTON3 |
關閉 |
CButton m_close; |
OnBnClickedButton3() |
編輯框 |
IDC_EDIT1 |
傳送輸入 |
CString m_sendstr; |
- |
編輯框 |
IDC_EDIT2 |
接收顯示 |
CString m_receivestr; |
- |
MSComm |
IDC_MSCOMM1 |
- |
CMSComm m_ctrlComm; |
OnComm() |
(2)需要的硬體條件及情況說明:
需要一根串列埠線,一端接在PC的某個串列埠上,另一端的TX引腳和RX引腳用銅線連線起來,這樣便形成了一個迴路,資料傳送通過TX引腳出去後,又從RX引腳進來,程式中便可以得到接收到的資料了,接收到的資料應該和傳送的資料一致,說明串列埠的傳送、接收操作成功了。(3)COM元件(MSComm控制元件)訊息響應巨集定義的重要注意點:
BEGIN_EVENTSINK_MAP (CPoint20Dlg, CDialog)
ON_EVENT (CPoint20Dlg, IDC_MSCOMM1, 1, OnComm, VTS_NONE)
END_EVENTSINK_MAP ()
(4)從登錄檔中檢測系統中可用串列埠並新增到介面組合框中:
HKEY hKey;
int rtn;
rtn = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Hardware\\DeviceMap\\SerialComm", NULL, KEY_READ, &hKey);
if( rtn == ERROR_SUCCESS) // 開啟串列埠登錄檔
{
int i=0;
char portName[256], commName[256];
DWORD dwLong,dwSize;
while (1)
{
dwSize = sizeof(portName);
dwLong = dwSize;
rtn = RegEnumValue ( hKey, i, portName, &dwLong, NULL, NULL, (PUCHAR)commName, &dwSize ); // 列舉串列埠
if( rtn == ERROR_NO_MORE_ITEMS )
break; // commName就是串列埠名字
m_com.AddString(commName);// 將可用串列埠新增到介面組合框
i++;
}
RegCloseKey(hKey);
}
m_com.SetCurSel(0);
(5)開啟並設定串列埠引數:
if (!m_ctrlComm.GetPortOpen())
{
char commName[256];//串列埠名
m_com.GetWindowText (commName, 256);
m_ctrlComm.SetCommPort(_ttoi(&commName[3]));//從串列埠名中得到串列埠號
m_ctrlComm.SetInputMode (1);
m_ctrlComm.SetSettings ("9600, n, 8, 1");
m_ctrlComm.SetPortOpen (TRUE);
m_ctrlComm.SetRThreshold (1);
m_ctrlComm.SetInputLen (0);
m_ctrlComm.GetInput ();
MessageBox(" 串列埠已開啟 ");
}
else
MessageBox("沒有發現此串列埠或被佔用");
(6)傳送資料:
if (m_ctrlComm.GetPortOpen())
{
UpdateData();
CByteArray sendArr;//欲傳送的資料,需從CString轉化為CByteArray型
WORD wLen;
wLen=m_sendstr.GetLength();
sendArr.SetSize(wLen);
for (int i=0;i<wLen;i++){
sendArr.SetAt(i,m_sendstr.GetAt(i));
}
m_ctrlComm.SetOutput (COleVariant (sendArr));//傳送資料
}
else
MessageBox("串列埠未開啟");
(7)接收資料(onComm()函式):
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len,k;
BYTE rxdata[6000];
CString strtemp;
if (m_ctrlComm.GetCommEvent()==2)
{
variant_inp=m_ctrlComm.GetInput ();
safearray_inp=variant_inp;
len=safearray_inp.GetOneDimSize();
for (k=0;k<len;k++)
{
safearray_inp.GetElement(&k,rxdata+k);
BYTE bt=*(char*)(rxdata+k);
//strtemp.Format(_T("%02X"),bt);//十六進位制格式接收
strtemp.Format(_T("%c"),bt);//字元格式接收
m_receivestr+=strtemp;
}
UpdateData(FALSE);
}
(8)關閉串列埠:
if(m_ctrlComm.GetPortOpen())
{
m_ctrlComm.SetPortOpen (FALSE);
MessageBox("串列埠已關閉");
}
(9)例項效果圖: