1. 程式人生 > >MFC串列埠通訊(二)——使用MSComm控制元件實現串列埠通訊

MFC串列埠通訊(二)——使用MSComm控制元件實現串列埠通訊

 

由於專案需要,最近在寫一個簡單的串列埠通訊,基於MFC框架,寫完之後特此回顧記錄一下學習的過程:

串列埠通訊主體框架
(1) 初始化介面(自動獲取全部可用串列埠)
(2) 開啟串列埠 (讀取串列埠號,初始化串列埠引數(波特率、校驗位、資料位等),若串列埠已經開啟則關閉串列埠)
(3) 傳送資料 (更新控制元件狀態,進入MSComm事件驅動函式,讀緩衝區,資料轉換,更新編輯框成員函式,更新編輯框內容)
(4) 退出介面 (檢測串列埠是否開啟,若開啟則關閉串列埠,再進行退出)

  • 在MFC中建立對話方塊的基礎上,新增兩個控制元件CComBox和Button控制元件,CComBox負責掃描所有可用串列埠,Button用於開啟和關閉串列埠,然後右鍵滑鼠,點選插入ActiveX控制元件,選擇控制元件,出現如控制元件(電話圖示),則表示插入控制元件成功

 

  • 給控制元件新增變數,變數名為m_mscom,之後專案中會出現對應.h和.cpp檔案

  • 加Eidit Control控制元件用於接受訊息,繫結變數m_EditReveive,然後新增串列埠控制元件事件處理處理程式

 

點選新增編輯按鈕(第一次新增會是新增編輯,再次新增的話會是編輯程式碼按鈕),會出現如下程式碼:

void CCommTestDlg::OnCommMscomm2()
{
    // TODO: 在此處新增訊息處理程式程式碼

}

新增自動接收程式碼(專案中通訊協議是測試結果自動上傳),並直接顯示在接收控制元件中,程式碼如下:

​
void CComCommunicateDlg::OnCommMscomm2()	//事件驅動
{
	if (m_mscom.get_CommEvent() == 2)	//事件值為2表示接收緩衝區內有字元
	{
		char str[1024] = { 0 };
		long k;
		VARIANT InputData = m_mscom.get_Input();	//讀緩衝區
		COleSafeArray fs;
		fs = InputData;	//VARIANT型變數轉換為COleSafeArray型變數
		for (k = 0; k<fs.GetOneDimSize(); k++)
			fs.GetElement(&k, str + k);	//轉換為BYTE型陣列

		m_EditReveive += str;      //	接收到編輯框裡面
		//SetTimer(1,10,NULL);		//延時10ms
		UpdateData(false); //更新到控制元件
	}
}

​

 

  • 由於專案比較簡單,就將串列埠引數寫死了,若想修改引數可以在原始碼裡修改,開啟/關閉串列埠程式碼實現如下:
​
void CComCommunicateDlg::OnBnClickedButtonOpen()	//開啟串列埠按鈕
{
	CString str, n;					//定義字串
	GetDlgItemText(IDC_BUTTON_OPEN, str);  //獲取給定控制元件的文字
	CWnd *h1;
	h1 = GetDlgItem(IDC_BUTTON_OPEN);		//指向控制元件的caption

	if (!m_mscom.get_PortOpen())			
	{	
		try 
		{
			m_mscom.put_CommPort(num);	//選擇串列埠
		}
		catch (CException* e)
		{
			m_mscom.put_OutBufferCount(0);
			
			AfxMessageBox(L"開啟串列埠 失敗");
			return;
		}
		m_mscom.put_InputMode(1);			//設定輸入方式為二進位制方式
		m_mscom.put_Settings(_T("115200,n,8,1"));		//設定串列埠引數,波特率,無奇偶校驗,位停止位,位資料位
		m_mscom.put_InputLen(1024);		//設定當前接收區資料長度為1024
		m_mscom.put_RThreshold(1);			//接收緩衝區有1個及1個以上字元時,觸發OnComm事件
		m_mscom.put_RTSEnable(1);			//設定RT允許


		m_mscom.put_PortOpen(true);		//開啟串列埠
		
		if (m_mscom.get_PortOpen())
		{
			str = _T("關閉串列埠");
			UpdateData(true);
			h1->SetWindowText(str);			//改變按鈕名稱為‘’關閉串列埠”
		}
	}
	else
	{
		m_mscom.put_PortOpen(false);		//關閉串列埠
		if (str != _T("開啟串列埠"))
		{
			str = _T("開啟串列埠");
			UpdateData(true);				//將控制元件的狀態傳給其關聯的變數
			h1->SetWindowText(str);			//改變按鈕名稱為開啟串列埠
		}
	}
}

​

 

  • 最後是選擇串列埠下拉框,起初用的比較笨的方法,新增在ComBox新增1-8個串列埠,然後到裝置管理器中檢視串列埠資訊,再開啟串列埠。後來改用自動掃描已開啟埠號,其功能封裝在GetCom()函式裡,在初始化的時候執行即可。程式碼如下
void CComCommunicateDlg::GetCom()
{
	//程式啟動時獲取全部可用串列埠
	HANDLE hCom;
	int i, k;
	CString str;
	BOOL flag;
 
	((CComboBox *)GetDlgItem(IDC_COMBO1))->ResetContent();
	flag = FALSE;
	num = 0;
	for (i = 1; i <= 16; i++)
	{//此程式支援16個串列埠
		str.Format(L"\\\\.\\COM%d", i);	
		hCom = CreateFile(str, 0, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
		if (INVALID_HANDLE_VALUE != hCom)
		{//能開啟該串列埠,則新增該串列埠
			CloseHandle(hCom);
			str = str.Mid(4);
			((CComboBox *)GetDlgItem(IDC_COMBO1))->AddString(str);
			if (flag == FALSE)
			{
				flag = TRUE;
				num = i;
			}
		}
	}
	i = ((CComboBox *)GetDlgItem(IDC_COMBO1))->GetCount();
	if (i == 0)
	{//若找不到可用串列埠則禁用“開啟串列埠”功能
		((CComboBox *)GetDlgItem(IDC_COMBO1))->EnableWindow(FALSE);
		
	}
	else
	{
		k = ((CComboBox *)GetDlgItem((IDC_COMBO1)))->GetCount();
		((CComboBox *)GetDlgItem(IDC_COMBO1))->SetCurSel(k - 1);
		//mCom.BindCommPort(num);
	}
}

 

  • 最終軟體執行頁面,串列埠通訊訊息的傳送暫時沒有用到,以後用到了再進行記錄

 

  •