1. 程式人生 > >VC中實現串列埠通訊的摸索過程

VC中實現串列埠通訊的摸索過程

串列埠通訊對於需要進行嵌入式開發的小夥伴們來說是必不可少的,甚至說是無法迴避的。而VC卻又不像C#或者QT那樣人性化,沒有自帶串列埠類(貌似VC6時代還有一個串列埠控制元件可以下載然後通過安裝到VC6中),所以我們不得不到處尋找開源的串列埠通訊程式碼。
這裡我找到的是CSerialPort,雖然官網作者沒有繼續更新了(還停留在2000年8月),但國內的牛人則在繼續維護。
官網地址是這裡:https://www.codeguru.com/cpp/i-n/network/serialcommunications/article.php/c2483/A-communication-class-for-serial-port.htm


我找到了牛人的維護版本下載了,感覺實現起來還算比較簡單,這裡將摸索過程羅列出來。
首先,我們必須找到SerialPort.cpp和SerialPort.h兩個檔案,並把他們新增到我們自己的工程中。
在這裡插入圖片描述
我這裡建立一個基於對話方塊的MFC工程,新增完畢後注意引用到程式碼中,由於這個類修改者已經將SerialPort類置於了名稱空間itas109中,所以不要忘記引入名稱空間,開始程式碼如下:

第一步,引入必要的標頭檔案
// SerialPortTestDlg.h : header file
//

#pragma once
#include "SerialPort.h"
using namespace std;
using namespace itas109;

第二步,宣告串列埠變數及準備波特率資料

// CSerialPortTestDlg dialog
//此處準備我們需要用到的波特率及串列埠變數
int BaudRate[] = { 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600, 115200 };
CSerialPort m_SerialPort;

第三步,初始化串列埠(列舉所有串列埠)
這裡要宣告兩個ComboBox變數,分別來存放串列埠號和波特率
在這裡插入圖片描述
在這裡插入圖片描述
在對話方塊的OnInitDialog中增加介面及串列埠初始化程式碼(增加程式碼之前在對話方塊中增加三個按鈕和兩個文字框兩個下拉框)如下圖:
在這裡插入圖片描述

// TODO: Add extra initialization here
	//這裡新增我們初始化串列埠的必要程式碼
	CString temp;
	//新增波特率到下拉列表
	for (int i = 0; i < sizeof(BaudRate) / sizeof(int); i++)
	{
		temp.Format(_T("%d"), BaudRate[i]);
		m_BaudRate.AddString((LPCTSTR)temp);
	}

	temp.Format(_T("%d"), 9600);
	m_BaudRate.SetCurSel(m_BaudRate.FindString(0, temp));

	//獲取串列埠號
	CSerialPortInfo a;
	list<string> m_portsList = CSerialPortInfo::availablePorts();
	list<string>::iterator itor;
	TCHAR m_regKeyValue[255];
	for (itor = m_portsList.begin(); itor != m_portsList.end(); ++itor)
	{
#ifdef UNICODE
		int iLength;
		const char * _char = (*itor).c_str();
		iLength = MultiByteToWideChar(CP_ACP, 0, _char, strlen(_char) + 1, NULL, 0);
		MultiByteToWideChar(CP_ACP, 0, _char, strlen(_char) + 1, m_regKeyValue, iLength);
#else
		strcpy_s(m_regKeyValue, 255, (*itor).c_str());
#endif
		m_PortNr.AddString(m_regKeyValue);
	}
	m_PortNr.SetCurSel(0);
	

到這裡注意,如果我們編譯會出現這樣的錯誤:
在這裡插入圖片描述
一開始 ,我也是很鬱悶,總怎麼修改都有這個
Error C1010 unexpected end of file while looking for precompiled header. Did you forget to add ‘#include “stdafx.h”’ to your source? SerialPortTest
後來,經過摸索發現,應該將SerialPort.cpp預編譯設定修改為,不使用預編譯
在這裡插入圖片描述
我們再次編譯執行,一切正常,如下圖:
在這裡插入圖片描述
第四步,實現讀資料功能(建立接受函式的訊息對映)
通過類想到,找到Message選項,建立一個訊息對映(記住,根據SerialPort.cpp中的定義,這裡的訊息WM_COMM_RXSTR只能用,否則無效)
在這裡插入圖片描述
之後我們在OnReceiveStr中新增如下程式碼即可

	struct serialPortInfo
	{
		UINT portNr;//串列埠號
		DWORD bytesRead;//讀取的位元組數
	}*pCommInfo;
	pCommInfo = (serialPortInfo*)lParam;

	CString str1((char*)wParam);
	
	int len = _tcslen(str1.GetBuffer(0));
	if (len == pCommInfo->bytesRead)
	{
		m_ReceiveCtrl.SetSel(-1, -1);
		m_ReceiveCtrl.ReplaceSel(str1);
	}
	else
	{
		AfxMessageBox(_T("資料長度錯誤"));
	}
	
	return 0;

在這裡插入圖片描述
到這裡為止,我們的串列埠基本可以實現讀取資料的功能了。
寫功能比較簡單,在傳送資料的按鈕事件中新增下面的程式碼即可:

GetDlgItem(IDC_EDIT2)->SetFocus();
	CString temp;
	UpdateData(true);
	m_OpenCloseCtrl.GetWindowText(temp);
	if (temp == "開啟串列埠")///沒有開啟串列埠
	{
		AfxMessageBox(_T("請首先開啟串列埠"));
		return;
	}
	m_Send.GetWindowText(temp);
	size_t len = _tcsclen(temp) + 1;;
	char* m_str = NULL;
	size_t* converted = 0;
	m_str = new char[len];
#ifdef UNICODE
	wcstombs_s(converted, m_str, len, temp.GetBuffer(0), _TRUNCATE);
#else
	m_str = temp.GetBuffer(0);
#endif
	m_SerialPort.WriteToPort(m_str, len);

VS2017下編寫的串列埠通訊原始碼見下面連結:
VC2017串列埠通訊例項原始碼