介绍如何使用win32API函数进行通信端口的编程,因为串口数据接收需要不停地监视串口和处理串口事件,因此,再本实例中将其封装为单个线程执行类。

创建串口线程类并初始化,由CThreadCom1对象的构造函数完成,它实现串口工作变量的初始化工作。

CThreadCom1::CThreadCom1(HANDLE hCom)
{m_hCom=hCom;m_bInit=false;m_sCom="";m_sError="No Error!";m_hThread=NULL;m_dwSendMsgToParent=0;m_dwRecvMsgToParent=0;m_pWndParent=NULL;memset((unsigned char*)&m_overRead,0,sizeof(OVERLAPPED));memset((unsigned char*)&m_overWrite,0,sizeof(OVERLAPPED));m_overRead.hEvent=CreateEvent(NULL,true,false,NULL);m_overWrite.hEvent=CreateEvent(NULL,true,false,NULL);}CThreadCom1::~CThreadCom1()
{CloseHandle(m_overRead.hEvent);CloseHandle(m_overWrite.hEvent);
}BOOL CThreadCom1::InitInstance()
{// TODO: 在此执行任意逐线程初始化m_bAutoDelete=false;m_bDone=false;return TRUE;
}int CThreadCom1::ExitInstance()
{// TODO: 在此执行任意逐线程清理BOOL bFlag=CloseCom();return CWinThread::ExitInstance();
}

串口接收线程的处理工作由CThreadCom1对象的Run()函数完成。它实现

循环从串口读取数据,并将接收的数据发送给处理函数的功能。

int CThreadCom1::Run(void)//重载线程类的Run()运行函数
{//return 0;DWORD dwError,dwReadNum,dwByteRead,dwEvent;COMSTAT  ComStat;//串口状态变量BYTE rBuf[MAXCOMINBUF];//输入缓冲区while(!m_bDone){while(m_hCom!=INVALID_HANDLE_VALUE){if(::WaitCommEvent(m_hCom,&dwEvent,NULL))//等待注册的串口事件发生{dwByteRead=0;//初始化读字节数if(dwEvent&EV_RXCHAR){ClearCommError(m_hCom,&dwError,&ComStat);//清空当前串口事件if(ComStat.cbInQue!=0)//输入列队中的数据个数{dwReadNum=ComStat.cbInQue;dwByteRead=0;if(dwReadNum>200)dwReadNum=200;memset(rBuf,0,sizeof(rBuf));//清空接收缓冲区变量DWORD i=::ReadFile(m_hCom,rBuf,dwReadNum,&dwByteRead,&m_overRead);for(i=dwByteRead;i<1024;i++)rBuf[i]=0;//用0x00填充剩余字节}}if(dwByteRead)if(m_pWndParent)m_pWndParent->SendMessage(m_dwRecvMsgToParent,(DWORD)rBuf,dwByteRead);//读取的数据发送到父窗口}}Sleep(1000);}return CWinThread::Run();//调用基类的Run()函数
}

//打开串口,根据程序配置,打开指定工作串口的功能

BOOL CThreadCom1::OpenCom(CString strCom, CWnd* pWndParent, DWORD dwSendMsgToParent, DWORD dwRecvMsgToParent)
{//return 0;CloseCom();CString strLog;m_hCom=::CreateFile(strCom,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);//打开串口if(m_hCom==INVALID_HANDLE_VALUE){strLog.Format("Open %s Error",strCom);AfxMessageBox(strLog);return FALSE;}::SetupComm(m_hCom,MAXCOMINBUF,MAXCOMOUTBUF);//设置串口输入输出缓冲区DCB dcb;//定义DCB结构if(!GetCommState(m_hCom,&dcb)){AfxMessageBox("获取串口状态错误");CloseHandle(m_hCom);m_hCom=INVALID_HANDLE_VALUE;return FALSE;}if(!SetCommState(m_hCom,&dcb)){CloseHandle(m_hCom);m_hCom=INVALID_HANDLE_VALUE;strLog.Format("set %s CommState Error!",strCom);AfxMessageBox(strLog);return FALSE;}//m_sError="No Error";  m_pWndParent    =  pWndParent;//存储父窗口句柄m_dwSendMsgToParent = dwSendMsgToParent;//存储接收发送消息的父窗口m_dwRecvMsgToParent  = dwRecvMsgToParent;//存储接收接收消息的父窗口//DWORD CommMask;CommMask=0|EV_BREAK|EV_CTS|EV_DSR|EV_ERR|EV_EVENT1|EV_EVENT2|EV_PERR|EV_RING|EV_RLSD|EV_RX80FULL|EV_RXCHAR|EV_RXFLAG|EV_TXEMPTY;::SetCommMask(m_hCom,CommMask);//注册要处理的事件::GetCommTimeouts(m_hCom,&m_Commtimeout);//读取超时时间设置m_Commtimeout.ReadTotalTimeoutMultiplier=5;m_Commtimeout.ReadTotalTimeoutConstant=100;m_bInit=true;return TRUE;}

//关闭串口

BOOL CThreadCom1::CloseCom(void)
{//return 0;if(m_hCom!=INVALID_HANDLE_VALUE){PurgeComm(m_hCom,PURGE_RXCLEAR);//释放串口事件CloseHandle(m_hCom);m_hCom=INVALID_HANDLE_VALUE;//设置句柄无效}m_bInit=false;return true;
}

//发送数据

BOOL CThreadCom1::SendData(BYTE* s, DWORD dwLen)
{//return 0;if(!dwLen)return false;::GetCommTimeouts(m_hCom,&m_Commtimeout);m_Commtimeout.WriteTotalTimeoutMultiplier=0;//设置读操作超时时间m_Commtimeout.WriteTotalTimeoutConstant=2*dwLen;//设置读操作超时常量::SetCommTimeouts(m_hCom,&m_Commtimeout);//设置超时时间设置if(m_hCom!=INVALID_HANDLE_VALUE){DWORD dwSend;m_pWndParent->SendMessage(m_dwSendMsgToParent,(DWORD)s,dwLen);//发送日志if(!WriteFile(m_hCom,s,dwLen,&dwSend,&m_overWrite))//向串口发送数据{m_sError="串口发送数据失败";return false;}return true;}else{m_sError="串口句柄无效";return false;}
}

串口线程类代码结束后。界面的处理,对话框类中,实现相关按钮触发事件。

对话框类头文件相关声明:

public:
//  CString m_Log;CString m_editSend;CString m_editReceive;CComboBox m_comboComm;afx_msg void OnBnClickedButtonOpenserial();CThreadCom1* pThreadCom; BOOL m_bCom;void WriteLog(CString log);afx_msg void OnBnClickedButtonSend();
//  void OnSendMsg(DWORD dwEvent, DWORD dwLen);CEdit m_Log;
//  void OnRecvMsg(DWORD dwEvent, DWORD dwLen);//HRESULT OnSendMsg(DWORD dwEvent, DWORD dwLen);HRESULT OnSendMsg(WPARAM dwEvent, LPARAM dwLen);//HRESULT OnRecvMsg(DWORD dwEvent, DWORD dwLen);HRESULT OnRecvMsg(WPARAM dwEvent, LPARAM dwLen);CEdit m_edit_Receive1;

//打开串口的按钮

void CTxwtechWin32API_CommDlg::OnBnClickedButtonOpenserial()
{// TODO: 在此添加控件通知处理程序代码if(pThreadCom!=NULL) return;CString str;CString com;//int com1;//com1=m_comboComm.GetCurSel();//com1+=1;//com=m_comboComm.GetWindowText();m_comboComm.GetWindowTextA(com);//获取组合框com的内容//com.Format("%s",com1);pThreadCom=(CThreadCom1*)AfxBeginThread(RUNTIME_CLASS(CThreadCom1));pThreadCom->SetComStr(com);//设置串口线程的串口名称变量if(pThreadCom->OpenCom(com,(CWnd*)this->GetSafeOwner(),WM_USER_COMSENDMESSAGE,WM_USER_COMRECVMESSAGE)){str.Format("打开串口%s成功",pThreadCom->GetComStr());WriteLog(str);}else{str.Format(pThreadCom->m_sError+",请重新配置串口");WriteLog(str);pThreadCom->m_bInit=FALSE;return;}m_bCom=TRUE;m_comboComm.EnableWindow(FALSE);return;
}

//发送按钮绑定的代码

void CTxwtechWin32API_CommDlg::OnBnClickedButtonSend()
{// TODO: 在此添加控件通知处理程序代码UpdateData(true);int iLen=m_editSend.GetLength();BYTE* s=new BYTE[iLen];memset(s,0x00,iLen);//初始化数据缓冲区memcpy(s,(LPCTSTR)m_editSend,iLen);//复制数据pThreadCom->SendData((unsigned char*)s,iLen);
}

//发送数据通知

HRESULT CTxwtechWin32API_CommDlg::OnSendMsg(WPARAM dwEvent, LPARAM dwLen)
{if(!dwLen)return 0;BYTE* temp=new BYTE[dwLen+1];memset(temp,0x00,dwLen+1);memcpy(temp,(const void*)dwEvent,dwLen);CString log;log.Format("\r\n发送数据%s",(LPCTSTR)temp);if(m_Log){CEdit* editLog=(CEdit*)FromHandle(m_Log);if(editLog->GetWindowTextLength()>50000){editLog->SetSel(0,-1);//把发送区的全部内容选中editLog->Clear();//清空全部内容editLog->SetSel(0,0);//设置光标到0字节处editLog->ReplaceSel(log);//更新新的内容}else{editLog->SetSel(editLog->GetWindowTextLength(),editLog->GetWindowTextLength());//光标指向句末editLog->ReplaceSel(log);//添加新内容}}
//  return;return E_NOTIMPL;
}

//接收消息通知

HRESULT CTxwtechWin32API_CommDlg::OnRecvMsg(WPARAM dwEvent, LPARAM dwLen)
{if(!dwLen) return 0;BYTE* temp=new BYTE[dwLen+1];memset(temp,0x00,dwLen+1);memcpy(temp,(const void*)dwEvent,dwLen);CString log;log.Format("\r\n接收数据=%s",(LPCTSTR)temp);if(m_editReceive.GetLength()>50000)m_editReceive="";m_editReceive+=log;CEdit* editLog=(CEdit*)FromHandle(m_edit_Receive1);editLog->SetSel(editLog->GetWindowTextLength(),editLog->GetWindowTextLength());editLog->ReplaceSel(log);//UpdateData(false);return E_NOTIMPL;
}

相关调试遇到的问题:

error C2511: “CThreadCom1::CThreadCom1(HANDLE)”:“CThreadCom1”中没有找到重载的成员函数
原因:头文件未定义。
CThreadCom1(HANDLE hCom=INVALID_HANDLE_VALUE);
error C2668: “CThreadCom1::CThreadCom1”: 对重载函数的调用不明确
头文件中只有有一个重载函数,把默认的删除掉

TxwtechWin32API_Comm.exe 中的 0x100c14cf (msvcr100d.dll) 处有未经处理的异常: 0xC0000005: 读取位置 0x00000002 时发生访问冲突,
rootcause:连接串口不能是数值,而是字符串COM1...

TxwtechWin32API_Comm.exe 中的 0x7898391c (mfc100d.dll) 处有未经处理的异常: 0xC0000005: 读取位置 0x00000020 时发生访问冲突
缺少如下两句://m_dwSendMsgToParent 没有获取父窗口的值
//m_dwSendMsgToParent = dwSendMsgToParent;
 m_dwRecvMsgToParent = dwRecvMsgToParent;

接收框中无法接收消息,注意消息的映射与宏定义

#define WM_USER_COMSENDMESSAGE WM_USER+200
#define WM_USER_COMRECVMESSAGE WM_USER+201

BEGIN_MESSAGE_MAP(CTxwtechWin32API_CommDlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON_OpenSerial, &CTxwtechWin32API_CommDlg::OnBnClickedButtonOpenserial)ON_BN_CLICKED(IDC_BUTTON_Send, &CTxwtechWin32API_CommDlg::OnBnClickedButtonSend)ON_MESSAGE(WM_USER_COMSENDMESSAGE,OnSendMsg)ON_MESSAGE(WM_USER_COMRECVMESSAGE,OnRecvMsg)
END_MESSAGE_MAP()

vs2010基于Win32API串口通信MFC实例相关推荐

  1. Proteus的串口通信仿真实例(八路数据采集系统)

    用proteus和虚拟串口调试助手进行串口通信仿真 实例是一个八路数字电压表,将采集到的八路数字电压经过RS232串口发送至接收上位机.进行串口通信仿真首先要安装一个虚拟串口软件,创建一对虚拟串口.用 ...

  2. 基于蓝牙串口通信,实现实时脉象采集(项目总结与思路梳理)

    写在前面 本项目用到的 主要知识点: 手机蓝牙 (动态权限申请,蓝牙打开,连接,配对,基于2.0蓝牙串口 Socket 通信),自定义View SurfaceView(实时绘制采集到的脉象波形).本人 ...

  3. simulink接收串口数据_基于Unity串口通信的解决方案

    思路有三种,等下我会详细介绍. 后面的博客详细介绍是我收录两年前写的博客,现在我已经没有往串口方向进行开发了,所以只能将一些思路分享给大家. ​ ​ 解决方式一:将Unity串口通信数据模块(接收与发 ...

  4. VS2010中MSCOMM 串口通信控件的注册使用

    VS2010本身并不自带MSCOMM控件,因此在Win7.win8/8.1系统中使用VS2010进行串口编程时, 在COM控件一栏中没法找到. 网上解决这个问题的文章很多,但尝试了很多种方法都没有解决 ...

  5. 基于STC串口通信和VC6.0MFC编程的电子琴设计

    电子实训课程实验项目 --电子琴 [前言] 为进一步激发学生对于硬件编程的兴趣而开展的课程"电子实训"课程到目前为止已经要告一段落了.将近四周的时间,从电路板印刷.贴片参观,到自己 ...

  6. Qt笔记-QSerialPort的使用(串口通信简单实例)

    程序运行截图如下: 虚拟串口设置如下: 源码如下: SerialDemo.pro QT += core serialport QT -= guiCONFIG += c++11TARGET = Seri ...

  7. python 串口测试,基于python串口通信简单实现物联网设备的自动化测试

    1.环境 python2.7 serial 库 2.AT command 什么是AT command: https://baike.baidu.com/item/AT命令/3441555?fr=ala ...

  8. stm32f103c8t6与stm32f103zet6 基于SX1276串口通信-----发送端(二)

    矩阵按键控制代码 源码链接 使用4*4矩阵,主控芯片为STM32F103C8T6,串口发送配置在下面这篇文章里面 串口发送端配置博文 /******************************** ...

  9. stm32f103c8t6与stm32f103zet6 基于SX1276串口通信-----发送端(一)

    STM32发送端的设计 发送端采用stm32f103c8t6为主控设计,采用矩阵按键作为发送输入端,进行信号传入. 如下图可以看出模块主要采用的是泽耀SX1276无线模块,频段采用433MHz ##接 ...

  10. VS2013基于对话框的MFC串口通信简单案例教程

    本例程是在VS2013环境下,使用MFC做的是一个简单的串口通信程序. 虚拟的串口软件工具下载地址:https://pan.baidu.com/s/1D-oddZk3Z_ioXBUpXE7ksw 密码 ...

最新文章

  1. java 左右键_js 区分鼠标左右键点击
  2. 【Linux服务器初上手】MobaXterm/系统版本/hostname/hosts/yum源配置/jdk/docker(不断完善)
  3. mysql索引 物理文件_MySQL架构和MySQL索引
  4. SAP Spartacus routing parameter mapping介绍
  5. 工业级千兆以太网光纤收发器产品介绍
  6. maven 项目管理和构建工具
  7. “十亿赌约”,雷军输,董明珠胜?
  8. 通俗编程——白话NIO之Buffer
  9. 文件操作Python
  10. javascript特效:会随着鼠标而动的眼睛
  11. 二叉搜索树的后序遍历序列(C++)
  12. 一段经典的 Java 风格程序 ( 类,包 )
  13. 辽宁师范大学计算机学院查寝吗,辽宁师范大学宿舍怎么样 住宿条件好不好
  14. 《深入浅出MySQL》开发篇
  15. Redhat rpm常用命令以及如何配置yum软件仓库使用yum install
  16. 美国enom域名的优势
  17. 合同管理数据库设计mysql_工程合同管理信息系统的数据设计理念
  18. Linux 工具 | 第1篇:高级流控-TC+HTB+IFB+内核模块
  19. html5手机 一键开发,Html5变革下的H5和手机app开发工具
  20. 计算机组成中位、字节、字、字长、存储单元、存储字、存储字的辨析

热门文章

  1. 2021-2027全球与中国数控龙门镗铣床市场现状及未来发展趋势
  2. STC89C51单片机串口程序下载失败总结
  3. 北大 宾州树库 语料标注集
  4. 制作简单启动型 U 盘_附制作工具下载
  5. Delphi7·ProgressBar控件
  6. 苹果iPad在使用蓝牙键盘时,无法使用五笔输入法
  7. vue实现上传图片并预览效果 html+css+js
  8. 星际2 BETA客户端背景音乐打包下载(附提取方法)
  9. McAfee Endpoint Security安装失败排查步骤
  10. html5趣味智力答题测试,10个趣味智力题及答案