我是在一家做硬件的的公司里面做软件开发工程师的,我做的软件大多是是编写软件通过串口去控制硬件,所以串口编程对于我来说是很重要的。串口编程之前一直使用的是自己写的简单串口(只有发送,没有接收)类,或者上网下的CSerialPort类(个人觉得不好用啊,互锁变量一堆,代码一开始还让人看不懂,对于上位机使用不合适)。对于我做的上位机软件,其实使用串口只是需要顺序发送,接收数据无误就行了,不需要考虑太多东西。所以最近有点空,就自己再写了一个串口类(希望可以简单使用的,没有太高的要求的)。
(1)界面

界面是粗糙了点,随便显示数据而已。
(2)代码
①代码文件列表

通过继承和多态让串口相关的类可以随意替换,另外上面那个“串口管理委托"类,其实是参照Object-C的委托,觉得很好,自己也一直使用这种设计模式
②代码介绍
串口管理类:主要给主窗口调用,逻辑分层:主窗口-串口管理-串口类
#pragma once
#include "BaseComManage.h"
class CBaseCom;
class CComManage : public CBaseComManage
{
public:
CComManage(void);
~CComManage(void);
//初始化
virtual void Init();
//获取串口状态
virtual BOOL GetComState();
//打开串口
virtual BOOL OpenCom(CString szComName, CString szBaudRate,
CString szByteSize, CString szParity, CString szStopBits);
//关闭串口
virtual void CloseCom();
//发送串口数据
virtual BOOL SendData(const char* pData, const int nLen);
//添加串口名称到ComboBox
virtual void AddComNameToComboBox(CComboBox* pComBox);
//添加波特率到ComboBox
virtual void AddBaudRateToComboBox(CComboBox* pComBox);
//添加数据位到ComboBox
virtual void AddByteSizeToComboBox(CComboBox* pComBox);
//添加停止位到ComboBox
virtual void AddStopBitToComboBox(CComboBox* pComBox);
//添加检验位到ComboBox
virtual void AddParityToComboBox(CComboBox* pComBox);
private:
//获取检验位
BYTE GetParity(CString szData);
//获取停止位
BYTE GetStopBit(CString szData);
//获取数据位
BYTE GetByteSize(CString szData);
//获取波特率
DWORD GetBaudRate(CString szData);
//获取串口名称
CString GetComName(CString szComName);
private:
//串口
CBaseCom* m_pCom;
};
#include "StdAfx.h"
#include "ComManage.h"
#include "DelegateComManage.h"
#include "XCom.h"
CComManage::CComManage(void)
{
m_pCom = nullptr;
}
CComManage::~CComManage(void)
{
if (nullptr != m_pCom)
{
delete m_pCom;
m_pCom = nullptr;
}
}
/***********************************************************
** 功能描述: 初始化
************************************************************/
void CComManage::Init()
{
m_pCom = new XCom;
}
/***********************************************************
** 功能描述: 获取串口状态
************************************************************/
BOOL CComManage::GetComState()
{
return m_pCom->GetComState();
}
/***********************************************************
** 功能描述: 打开串口
************************************************************/
BOOL CComManage::OpenCom(CString szComName, CString szBaudRate,
CString szByteSize, CString szParity, CString szStopBits)
{
return m_pCom->OpenCom(m_pDelegate->GetHWND(), GetComName(szComName),
GetBaudRate(szBaudRate), GetParity(szParity), GetByteSize(szByteSize), GetStopBit(szStopBits));
}
/***********************************************************
** 功能描述: 关闭串口
************************************************************/
void CComManage::CloseCom()
{
m_pCom->CloseCom();
}
/***********************************************************
** 功能描述: 发送串口数据
************************************************************/
BOOL CComManage::SendData(const char* pData, const int nLen)
{
return m_pCom->SendData(pData, nLen);
}
/***********************************************************
** 功能描述: 添加串口名称到ComboBox
************************************************************/
void CComManage::AddComNameToComboBox(CComboBox* pComBox)
{
if (nullptr != pComBox)
{
pComBox->ResetContent();
HKEY hKey;
//打开串口注册表
LONG nResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Hardware\\DeviceMap\\SerialComm"),
NULL, KEY_READ, &hKey);
if (ERROR_SUCCESS == nResult)
{
DWORD dwPortName = MAX_PATH;
DWORD dwComName = MAX_PATH;
TCHAR cPortName[MAX_PATH];
TCHAR cComName[MAX_PATH];
DWORD dwIndex = 0;
CString szTemp = _T("");
while(1)
{
ZeroMemory(cPortName, MAX_PATH);
ZeroMemory(cComName, MAX_PATH);
dwPortName = MAX_PATH;
dwComName = MAX_PATH;
if (::RegEnumValue(hKey, dwIndex, cPortName, &dwPortName, NULL, NULL, (LPBYTE)cComName,
&dwComName) == ERROR_NO_MORE_ITEMS)
{
break;
}
szTemp.Format(_T("%s"), cComName);
pComBox->AddString(cComName);
dwIndex++;
}
RegCloseKey(hKey);
}
}
}
/***********************************************************
** 功能描述: 添加波特率到ComboBox
************************************************************/
void CComManage::AddBaudRateToComboBox(CComboBox* pComBox)
{
if (nullptr != pComBox)
{
pComBox->ResetContent();
pComBox->AddString(_T("2400"));
pComBox->AddString(_T("4800"));
pComBox->AddString(_T("9600"));
pComBox->AddString(_T("14400"));
pComBox->AddString(_T("19200"));
pComBox->AddString(_T("38400"));
pComBox->AddString(_T("57600"));
pComBox->AddString(_T("115200"));
pComBox->AddString(_T("128000"));
pComBox->AddString(_T("256000"));
}
}
/***********************************************************
** 功能描述: 添加数据位到ComboBox
************************************************************/
void CComManage::AddByteSizeToComboBox(CComboBox* pComBox)
{
if (nullptr != pComBox)
{
pComBox->ResetContent();
pComBox->AddString(_T("4"));
pComBox->AddString(_T("5"));
pComBox->AddString(_T("6"));
pComBox->AddString(_T("7"));
pComBox->AddString(_T("8"));
}
}
/***********************************************************
** 功能描述: 添加停止位到ComboBox
************************************************************/
void CComManage::AddStopBitToComboBox(CComboBox* pComBox)
{
if (nullptr != pComBox)
{
pComBox->ResetContent();
pComBox->AddString(_T("1"));
pComBox->AddString(_T("1.5"));
pComBox->AddString(_T("2"));
}
}
/***********************************************************
** 功能描述: 添加检验位到ComboBox
************************************************************/
void CComManage::AddParityToComboBox(CComboBox* pComBox)
{
if (nullptr != pComBox)
{
pComBox->ResetContent();
pComBox->AddString(_T("NO"));
pComBox->AddString(_T("ODD"));
pComBox->AddString(_T("EVEN"));
pComBox->AddString(_T("MARK"));
}
}
/***********************************************************
** 功能描述: 获取检验位
************************************************************/
BYTE CComManage::GetParity(CString szData)
{
BYTE cData = 0;
if (szData == _T("EVEN"))
{
cData = EVENPARITY;
}
else if (szData == _T("ODD"))
{
cData = ODDPARITY;
}
else if (szData == _T("NO"))
{
cData = NOPARITY;
}
else if (szData == _T("MARK"))
{
cData = MARKPARITY;
}
return cData;
}
/***********************************************************
** 功能描述: 获取停止位
************************************************************/
BYTE CComManage::GetStopBit(CString szData)
{
BYTE cData = 0;
if (szData == _T("1"))
{
cData = ONESTOPBIT;
}
else if (szData == _T("1.5"))
{
cData = ONE5STOPBITS;
}
else if (szData == _T("2"))
{
cData = TWOSTOPBITS;
}
return cData;
}
/***********************************************************
** 功能描述: 获取数据位
************************************************************/
BYTE CComManage::GetByteSize(CString szData)
{
return (BYTE)_ttoi(szData);
}
/***********************************************************
** 功能描述: 获取波特率
************************************************************/
DWORD CComManage::GetBaudRate(CString szData)
{
return (DWORD)_ttoi(szData);
}
/***********************************************************
** 功能描述: 获取串口名称
************************************************************/
CString CComManage::GetComName(CString szComName)
{
return _T("\\\\.\\") + szComName;
}#pragma once
#include "BaseCom.h"
class XCom : public CBaseCom
{
public:
XCom(void);
~XCom(void);
//打开串口
virtual BOOL OpenCom(HWND pPortOwner, CString szComName,
DWORD nBaudRate, BYTE cParity, BYTE nByteSize, BYTE cStopsBits);
//获取串口状态
virtual BOOL GetComState();
//关闭串口
virtual void CloseCom();
//发送串口数据
virtual BOOL SendData(const char* pData, const int nLen);
public:
//串口线程函数
static UINT ComThread(LPVOID pParam);
//接收字符
BOOL ReceiveChar(DWORD dwLen);
private:
//打开串口
BOOL OpenCom(CString szComName);
//设置DCB
BOOL SetDCB(DWORD nBaudRate, BYTE cParity, BYTE nByteSize,
BYTE cStopsBits);
//开始监控
void StartMonitoring();
//停止监控
void StopMonitoring();
public:
//串口句柄
HANDLE m_hComm;
//线程结束事件句柄
HANDLE m_hThreadEndEvent;
//窗口句柄
HWND m_Owner;
private:
//串口状态
BOOL m_bComSate;
//串口DCB
DCB m_dcb;
};#include "StdAfx.h"
#include "XCom.h"
#include "Constant.h"
XCom::XCom(void)
{
m_bComSate = FALSE;
m_Owner = NULL;
m_hComm = INVALID_HANDLE_VALUE;
m_hThreadEndEvent = NULL;
}
XCom::~XCom(void)
{
CloseCom();
}
/***********************************************************
** 功能描述: 打开串口
************************************************************/
BOOL XCom::OpenCom(HWND pPortOwner, CString szComName,
DWORD nBaudRate, BYTE cParity, BYTE nByteSize, BYTE cStopsBits)
{
if (OpenCom(szComName))
{
if (SetDCB(nBaudRate, cParity, nByteSize, cStopsBits))
{
if (SetCommMask(m_hComm, EV_RXCHAR))
{
if(PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR
| PURGE_RXABORT | PURGE_TXABORT))
{
StartMonitoring();
m_Owner = pPortOwner;
m_bComSate = TRUE;
}
}
}
}
if (!m_bComSate)
{
CloseCom();
}
return m_bComSate;
}
/***********************************************************
** 功能描述: 设置DCB
************************************************************/
BOOL XCom::SetDCB(DWORD nBaudRate, BYTE cParity, BYTE nByteSize,
BYTE cStopsBits)
{
if (!GetCommState(m_hComm, &m_dcb))
{
return FALSE;
}
m_dcb.BaudRate = nBaudRate;
m_dcb.Parity = cParity;
m_dcb.ByteSize = nByteSize;
m_dcb.StopBits = cStopsBits;
return SetCommState(m_hComm, &m_dcb);
}
/***********************************************************
** 功能描述: 获取串口状态
************************************************************/
BOOL XCom::GetComState()
{
return m_bComSate;
}
/***********************************************************
** 功能描述: 关闭串口
************************************************************/
void XCom::CloseCom()
{
m_bComSate = FALSE;
if (INVALID_HANDLE_VALUE != m_hComm)
{
CloseHandle(m_hComm);
m_hComm = INVALID_HANDLE_VALUE;
}
StopMonitoring();
}
/***********************************************************
** 功能描述: 打开串口
************************************************************/
BOOL XCom::OpenCom(CString szComName)
{
m_hComm = CreateFile(szComName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
if (INVALID_HANDLE_VALUE == m_hComm)
{
return FALSE;
}
else
{
return TRUE;
}
}
/***********************************************************
** 功能描述: 开始监控
************************************************************/
void XCom::StartMonitoring()
{
m_hThreadEndEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
AfxBeginThread(ComThread, this);
}
/***********************************************************
** 功能描述: 停止监控
************************************************************/
void XCom::StopMonitoring()
{
if (NULL != m_hThreadEndEvent)
{
WaitForSingleObject(m_hThreadEndEvent, INFINITE);
CloseHandle(m_hThreadEndEvent);
m_hThreadEndEvent = NULL;
}
}
/***********************************************************
** 功能描述: 发送串口数据
************************************************************/
BOOL XCom::SendData(const char* pData, const int nLen)
{
DWORD nNumberOfBytesWritten;
OVERLAPPED overlapped = {0};
BOOL bResultWrite = WriteFile(m_hComm, pData, nLen, &nNumberOfBytesWritten, &overlapped);
BOOL bResult = FALSE;
if (bResultWrite)
{
bResult = TRUE;
}
else
{
DWORD dwError = GetLastError();
if (ERROR_IO_PENDING == dwError)
{
bResultWrite = GetOverlappedResult(m_hComm, &overlapped, &nNumberOfBytesWritten, TRUE);
if (bResultWrite)
{
bResult = TRUE;
}
}
}
return bResult;
}
/***********************************************************
** 功能描述: 接收字符
************************************************************/
BOOL XCom::ReceiveChar(DWORD dwLen)
{
DWORD BytesRead = 0;
unsigned char* pData = new unsigned char[dwLen];
OVERLAPPED overlapped = {0};
BOOL bReadResult = ReadFile(m_hComm, pData, dwLen, &BytesRead, &overlapped);
BOOL bResult = FALSE;
if (bReadResult)
{
bResult = TRUE;
}
else
{
DWORD dwError = GetLastError();
if (ERROR_IO_PENDING == dwError)
{
bReadResult = GetOverlappedResult(m_hComm, &overlapped, &BytesRead, TRUE);
if (bReadResult)
{
bResult = TRUE;
}
}
}
if (bResult)
{
::PostMessage(m_Owner, MSG_COM_RECEIVEDATA, (WPARAM)pData, BytesRead);
}
return bResult;
}
/***********************************************************
** 功能描述: 串口线程函数
************************************************************/
UINT XCom::ComThread(LPVOID pParam)
{
TRACE("XCOM ComThread:Start\n");
XCom *pCom = (XCom*)pParam;
DWORD dwEvtMask = 0;
BOOL bResult = TRUE;
DWORD dwError = 0;
COMSTAT comstat;
BOOL bRunning = TRUE;
while (bRunning)
{
bResult = WaitCommEvent(pCom->m_hComm, &dwEvtMask, NULL);
if (!bResult)
{
DWORD dwError = GetLastError();
switch (dwError)
{
case ERROR_IO_PENDING:
{
break;
}
case 87:
{
break;
}
default:
{
TRACE("XCOM ComThread WaitCommEvent:Error\n");
::PostMessage(pCom->m_Owner, MSG_COM_ERROR, NULL, NULL);
bRunning = FALSE;
break;
}
}
}
else
{
bResult = ClearCommError(pCom->m_hComm, &dwError, &comstat);
if (0 == comstat.cbInQue)
{
continue;
}
pCom->ReceiveChar(comstat.cbInQue);
}
}
SetEvent(pCom->m_hThreadEndEvent);
TRACE("XCOM ComThread:End\n");
return 0;
}(3)感想
我知道写得并不是很好,但足够我自己用了,试过没有问题,所以放上来给大家看看,供参考.
源码地址:http://pan.baidu.com/share/link?shareid=3711001912&uk=2852477476
原文地址:http://blog.csdn.net/cvbtvbwu/article/details/24694739