我是在一家做硬件的的公司里面做软件开发工程师的,我做的软件大多是是编写软件通过串口去控制硬件,所以串口编程对于我来说是很重要的。串口编程之前一直使用的是自己写的简单串口(只有发送,没有接收)类,或者上网下的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