VC编程之上位机简单串口类,VC串口类
小标 2018-09-04 来源 : 阅读 1208 评论 0

摘要:本文主要向大家介绍了VC编程之上位机简单串口类,VC串口类,通过具体的内容向大家展示,希望对大家学习VC编程有所帮助。

本文主要向大家介绍了VC编程之上位机简单串口类,VC串口类,通过具体的内容向大家展示,希望对大家学习VC编程有所帮助。

我是在一家做硬件的的公司里面做软件开发工程师的,我做的软件大多是是编写软件通过串口去控制硬件,所以串口编程对于我来说是很重要的。串口编程之前一直使用的是自己写的简单串口(只有发送,没有接收)类,或者上网下的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;
}
串口是用异步模式创建的,但使用是拿来当同步使用,是不是有大材小用,傻X是不,其实本是是想写成异步的,便同步比较好做,简单,就搞成四不像吧,方便进化成彻底异步模式。串品有数据到来时是用new一个char数组进行保存,然后发消息到主窗口,所以分配和释放内存这么多次不知道好不好,但如果只用一个共用的char数组进行保存时,就要使用互斥变量,处理慢。
(3)感想
我知道写得并不是很好,但足够我自己用了,试过没有问题,所以放上来给大家看看,供参考.

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言VC/MFC频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved