1. 程式人生 > >串列埠通訊基礎知識及VC++實現

串列埠通訊基礎知識及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)例項效果圖: