使用MFC来编写串口程序,需要有一定的c++语言功底,要清楚MFC代码的组织方式。

鉴于绝大多数的教程还停留在vc6.0这个骨灰级的环境,特在此说明一下VC2012下的代码组织方式,和大家一起交流下~

本文略去建立窗体的步骤,但是给出了窗体的样式,不会建立窗体的童鞋可以百度一下就知道了,很简单的,所以就不多说啦 ~

0、准备工作

使用的通讯控件是:Microsoft Communications Control, Version 6.0

需要安装同时VC6.0和VS2012才可以使用这个通讯控件。

工具->选择工具箱->COM组件 添加到工具条中,然后再添加到窗体上,任何位置都OK,编译运行以后不显示。

新建MFC窗体,win32下,基于对话框,命名为MFC(建议和我一样,这样方便些。)。应该都知道(不知道的可以参考百度文库里,好多,不多说了)

本代码是最简单的串口程序,参数设置都在代码中提醒。只需要设置COM号

窗体样式:

可以核对一下,头文件名:

MFC.h
MFCDlg.h  // main frame 主要窗体、父窗体的头文件,主要的修改和添加代码区
Resource.h
stdafx.h
targetver.h
源文件名:
MFC.cpp
MFCDlg.cpp   // main frame 主要窗体、父窗体的cpp文件,主要的修改和添加代码区
stdafx.cpp

一、准备工作

1.设置控件属性

各ID如下:

IDC_COMBO_CommSeclect 属性里面的Data:COM1;COM2;COM3;COM4;COM5;COM6; // 注意使用;分隔

2.使用  项目->类向导  定义变量如下

编译一下,应该不会有错。

下面准备添加代码

主要的代码区是 MFCDlg.h 和 MFCDlg.cpp 特别要注意,不要乱 ~

二、准备添加代码,接收下位机发来的数据并显示

1.MFCDlg.cpp中初始化

函数名:
BOOL CMFCDlg::OnInitDialog()

添加如下:

// TODO: 在此添加额外的初始化代码m_ComboBox.SetCurSel(2);//打开软件时串口选择框默认显示COM1  子选项编号的排序是从0开始的。

2.MFCDlg.cpp中BUTTON1消息响应函数 // 打开串口

双击绘图窗口里的BUTTON1控件进入代码编辑区添加代码如下:(想省事,直接看下面的代码)

或者进入类向导(建议此方法,有利于体会MFC的代码组织方式)

添加代码如下:  //  接收下位机的数据  看懂了注释你就可以按照需要自由组织啦。当下只是最简单的,8位数据,1停止,9600,无校验

void CMFCDlg::OnBnClickedButton1()
{// TODO: 在此添加控件通知处理程序代码//m_Index_int = ((CComboBox*)GetDlgItem(IDC_COMBO_CommSelect))->GetCurSel();//当前选中的/***********GetCurSel() 函数:用以得到用户选中下拉列表框中数据的索引值.返回的值是重0开始的,如果没有选择任何选项将会返回-1************/
//返回的是打开的端口号switch(m_ctrlComm.get_PortOpen())//点击打开或关闭串口按键时,根据当前的串口是否打开经行相应操作{case 0://当前串口是关闭的,则进行打开串口操作m_Index = ((CComboBox*)GetDlgItem(IDC_COMBO_CommSeclect))->GetCurSel();//当前选中的行m_ctrlComm.put_CommPort(m_Index + 1);//如果要打开串口则应先选择哪个串口m_ctrlComm.put_PortOpen(TRUE);//打开串口UpdateData(FALSE);//更新按键状态if(m_ctrlComm.get_PortOpen())//如过已经打开串口,{SetDlgItemText(IDC_BUTTON1,_T("关闭串口"));//更改按键提示m_ctrlComm.put_Settings(_T("9600,n,8,1"));//打开软件时端口设置默认波特率9600,无校验位,8位数据,1位停止m_ctrlComm.put_InputMode(1);//1:表示以二进制方式捡取数据;//0:表示以文本方式捡取数据m_ctrlComm.put_RThreshold(1);//参数1 表示每当串口接收缓冲区中有多余或等于一个字符时将引发一个接收数据的OnComm事件//参数0 表示数据传输事件不会引发OnComm事件,即不响应。m_ctrlComm.put_InputLen(0);//0: 缺省值。表示使MSComm控件读取接收缓冲区中的所有内容。m_ctrlComm.get_Input();//先预读缓冲区以清除残留数据UpdateData(FALSE);}elseAfxMessageBox(_T("串口打开失败"));break;case 1://当前串口是打开的则进行关串口操作
//      m_ctrlComm.SetCommPort(m_Index_int + 1);//如果要打开串口则应先选择哪个串口m_ctrlComm.put_PortOpen(FALSE);if(!m_ctrlComm.get_PortOpen())//如果已经关闭串口,{ SetDlgItemText(IDC_BUTTON1,_T("打开串口"));UpdateData(FALSE);}elseAfxMessageBox(_T("串口关闭失败"));break;default:AfxMessageBox(_T("cannot open Serial Port"));break;}m_ComboBox.SetCurSel(m_Index);//打开软件时串口选择框默认显示COM1  子选项编号的排序是从0开始的。
//  m_BaudRate_M.SetCurSel(m_BaudRate);//打开软件时波特率选择框默认显示9600
//  m_Data_Select_M.SetCurSel(m_Data_Select);//打开软件时数据位选择框默认显示8
//  m_StopBit_M.SetCurSel(m_StopBit);//打开软件时停止位选择框默认显示N  无停止位
//  m_ParityCheck_M.SetCurSel(m_ParityCheck);// 奇偶校验}

3.MFCDlg.cpp中Oncomm事件响应(就是那个“电话”控件的事件响应)

注意,此刻的头文件和源文件的内容有一些变化了,可以看一下,这两个是IDC_MSCOMM1控件带来的(添加OnComm事件后才会出现)。

添加代码如下:

void CMFCDlg::OnOncommMscomm1()
{// TODO: 在此处添加消息处理程序代码VARIANT variant_inp;COleSafeArray safearry_inp;LONG len,k;BYTE rxdata[2048];CString strtemp;int order;if(m_ctrlComm.get_CommEvent() == 2)//事件值为2表示接收缓冲区内有数据{//以下根据自己的通讯协议添加处理代码variant_inp = m_ctrlComm.get_Input();//读缓冲区safearry_inp = variant_inp;//VARIANT转化为COleSafeArraylen = safearry_inp.GetOneDimSize();//字符长度for(k=0;k<len;k++){safearry_inp.GetElement(&k,rxdata+k);//转化为BYTE型数组}for(k=0;k<len;k++)//将数组转化成Cstring型变量{BYTE bt = *(char*)(rxdata+k);//if(m_ctrlHexSend.GetCheck())//   strtemp.Format("%02x",bt);//elsestrtemp.Format(_T("%c"),bt);//将字符送入临时变量strtemp中存放  m_strRXData+=strtemp;//加入接收编辑框对应字符串/*******************以上的语句可以进行对sbuf的读取。***********************/order = _ttoi(strtemp);//order是字符转化后的int值}UpdateData(FALSE);//更新编辑框内容(主要是接收编辑框中的)}m_ComboBox.SetCurSel(m_Index);//打开软件时串口选择框默认显示COM1  子选项编号的排序是从0开始的。
//  m_BaudRate_M.SetCurSel(m_BaudRate);//打开软件时波特率选择框默认显示9600
//  m_Data_Select_M.SetCurSel(m_Data_Select);//打开软件时数据位选择框默认显示8
//  m_StopBit_M.SetCurSel(m_StopBit);//打开软件时停止位选择框默认显示N  无停止位
//  m_ParityCheck_M.SetCurSel(m_ParityCheck);// 奇偶校验}

编译运行,Bingo!

三、准备添加代码,向下位机发送数据

1.MFCDlg.cpp中 IDC_SendBtn 消息响应函数 // 打开串口

void CMFCDlg::OnBnClickedSendbtn()
{// TODO: 在此添加控件通知处理程序代码UpdateData(TRUE);long len;CByteArray array;len = m_strTXData.GetLength();//发送数据的长度array.RemoveAll();array.SetSize(len);for(int i=0;i<len;i++)array.SetAt(i, m_strTXData[i]);m_ctrlComm.put_Output(COleVariant(array)); // 发送数据}

然后,就没有然后啦~

四、最后说明下一些tips

1.VC2012 和 VC6.0的一些函数名的变化(坑死人)

比如:在VC6.0下
<span style="white-space:pre">     </span>m_ComPort.SetPortOpen(FALSE);m_ComPort.SetCommPort(m_comn+1); //设置串口号m_ComPort.SetInBufferSize(1024); //接收缓冲区 m_ComPort.SetOutBufferSize(1024);//发送缓冲区 m_ComPort.SetInputLen(0);//设置当前接收区数据长度为0,表示全部读取 m_ComPort.SetInputMode(1);//以二进制方式读写数据 m_ComPort.SetRThreshold(1);//接收缓冲区有1个及1个以上字符时,将引发接收数据的OnCommMscomm事件

在VC2012下,函数名需要做一下改动:

m_ComPort.put_PortOpen(FALSE);m_ComPort.put_CommPort(m_comn+1); //设置串口号m_ComPort.put_InBufferSize(1024); //接收缓冲区 m_ComPort.put_OutBufferSize(1024);//发送缓冲区 m_ComPort.put_InputLen(0);//设置当前接收区数据长度为0,表示全部读取 m_ComPort.put_InputMode(1);//以二进制方式读写数据 m_ComPort.put_RThreshold(1);//接收缓冲区有1个及1个以上字符时,将引发接收数据的OnCommMscomm事件

还有GetPortOpen()  要改成 get_PortOpen()

以此类推。

2.本方法必须安装VC6.0环境,不然这个控件就不能使用了。

3.分享是这个时代的基本品质 ~ 祝大家成功 ~

五、功能补充,使用十六进制发送和接收(modbus通讯协议)

modbus的串口通讯的发送方式是使用16进制数,和上文的字符发送方式不同,但是本质上都是使用2进制传送。
其最大差别在于比如要传送(01),字符方式:0->48(ASCII值),0x30(ASCII值的十六进制形式)->0010 0000 第一次发送;
     1->49(ASCII值),0x31(ASCII值的十六进制形式)->0010 0001第二次发送。结束
16进制方式: 0x01->1(10进制),对应的ASCII字符(SOH(start of headling))->0000 0001 一次发送结束。
注意,这里标出来的不是说要经过这样的转化以后才能发送,本质上串口发出去的都是二进制。差别在于你要选择发什么数据给put_Output()。不理解的话,可以实践一下加深理解。
TOOL 1: 串口调试器,可以监控,不占COM。http://pan.baidu.com/s/1qXTZudm
TOOL 2: 虚拟串口 http://pan.baidu.com/s/1nuUfzT3
参考资料:(串口程序部分)

http://wenku.baidu.com/view/9e9b258c6c175f0e7cd137b6.html?from=search

1.16进制方式发送

添加两个函数(第一个)

函数名在.h文件中声明Public:int String2Hex(CString str,CByteArray &senddata);

函数体如下:

int CSerialModbus331Dlg::String2Hex(CString str,CByteArray &senddata)
{int hexdata,lowhexdata;int hexdatalen = 0;int len = str.GetLength();senddata.SetSize(len/2);for(int i = 0;i<len;){char lstr;char hstr = str[i];if(hstr == ' '){i++;continue;}i++;if(i>len)break;lstr = str[i];hexdata = ConvertHexChar(hstr);lowhexdata = ConvertHexChar(lstr);if((hexdata == 16)||(lowhexdata == 16))break;elsehexdata = hexdata*16 + lowhexdata;i++;senddata[hexdatalen] = (char)hexdata;hexdatalen++;}senddata.SetSize(hexdatalen);return hexdatalen;
}

函数(第二个)

函数名在.h文件中声明Public:char ConvertHexChar(char ch);

函数体如下:

char CSerialModbus331Dlg::ConvertHexChar(char ch)
{  if((ch>='0')&&(ch<='9')) return ch-0x30;  else if((ch>='A')&&(ch<='F')) return ch-'A'+10;  else if((ch>='a')&&(ch<='f')) return ch-'a'+10; else return (-1);
}

最后修改发送函数(使用按钮click事件)

void CSerialModbus331Dlg::OnBnClickedButtonSendhex()
{// TODO: 在此添加控件通知处理程序代码UpdateData(TRUE); //读取编辑框内容 CByteArray hexdata;  int len = String2Hex(m_strTXData,hexdata); //此处返回的len可以用于计算发送了多少个十六进制数  m_ctrlComm.put_Output(COleVariant(hexdata)); //发送十六进制数据}

注意一个问题

网络复制的代码常出现    error C3872: "0xa0": 此字符不允许在标识符中使用

参考:http://blog.csdn.net/qqyuanhao163/article/details/40785983

原因是存在中文的空格,解决方法是把提示区的空格全部替换成英文空格。

2.16进制方式显示

在OnComm事件中修改一句代码如下:

   //         strtemp.Format(_T("%c"),bt);//将字符送入临时变量strtemp中存放    strtemp.Format(_T("%02X"),bt);//将字符送入临时变量strtemp中存放 

VC2012/VS2012 MFC串口通讯上位机程序教程笔记相关推荐

  1. VC2012/VS2012 MFC串口通讯上位机程序教程笔记(转)

    使用MFC来编写串口程序,需要有一定的c++语言功底,要清楚MFC代码的组织方式. 鉴于绝大多数的教程还停留在vc6.0这个骨灰级的环境,特在此说明一下VC2012下的代码组织方式,和大家一起交流下~ ...

  2. matlab制作以太网数据接收上位机_Python制作串口通讯上位机

    串口通讯具有简单易用的特点广泛应用于测试设备的通讯和数据传递.单片机与计算机的通讯等,本案例基于Python语言制作一个用于接收燃油质量流量计的串口通讯上位机,实现数据的读取和保存. 1. 相关知识点 ...

  3. python 串口_如何使用Python开发串口通讯上位机(一)

    用Python开发串口通讯型上位机,其实并非最优解,本系列更新只为个人学习与总结.如果有C语言底子,嵌入式层面的上位机开发,C++ Builder,C#才是更加好用的利器. 1 什么是上位机 从事过嵌 ...

  4. python编程与下位机通讯_如何使用Python开发串口通讯上位机(一)

    用Python开发串口通讯型上位机,其实并非最优解,本系列更新只为个人学习与总结.如果有C语言底子,嵌入式层面的上位机开发,C++ Builder,C#才是更加好用的利器.1 什么是上位机 从事过嵌入 ...

  5. stm32f103上位机程序编写笔记

    CSDN话题挑战赛第2期 参赛话题:学习笔记 学习之路,长路漫漫,写学习笔记的过程就是把知识讲给自己听的过程.这个过程中,我们去记录思考的过程,便于日后复习,梳理自己的思路.学习之乐,独乐乐,不如众乐 ...

  6. python 串口上位机_如何使用Python开发串口通讯上位机(二)

    黑色的dos窗口对于大部分来说,页面极为不友好,且操作不方便,因此本篇主要讲讲如何结合QtDesigner创建一个UI并初步与串口Api链接.1 QtDesigner进行上位机页面设计 Python下 ...

  7. python做上位机好不_如何使用Python开发串口通讯上位机(完结)

    2021的第一份更新,比以往时候来得早一点! 前面两期讲了如何使用pyserial和做好了基本的上位机界面以及与API的联动,今天我们接着完善下代码.1 编码规范的使用 前面两期只是做基础展示用,所以 ...

  8. MFC串口通信上位机(采用静态库编译生成的)不能在其他电脑运行的问题

    导致这个问题的原因是因为其他电脑系统没有加载mscomm的控件,所以可以通过手动加载的办法来解决 1.建一个.bat文件 ,输入如下内容 @echo off copy .\MSCOMM32.OCX % ...

  9. C#写的控制三菱FX5U PLC(三菱任何系列都通用,网口,串口都行)的上位机程序

    自己用C#写的控制三菱FX5U PLC(三菱任何系列都通用,网口,串口都行)的上位机程序,PLC源程序也附上,是学习C#和三菱PLC通信的好例子,有对辅助继电器M,对单字,双子D的读写,IO的监控,报 ...

  10. FX5U项目程序,用的三菱FX5U的PLC,里面有CC- LINK通讯机器人.自由口通讯仪表.以太网套接字通讯上位机

    FX5U项目程序,用的三菱FX5U的PLC,里面有CC- LINK通讯机器人.自由口通讯仪表.以太网套接字通讯上位机,脉冲控制3个步进,还有配方. PLC程序有完整的注释,结构清晰,PROFACE的触 ...

最新文章

  1. 三十八,反射的应用:工厂模式
  2. python的random函数_关于random()的详细介绍
  3. 将SAP订单以XML格式输出
  4. python如何进行大到小排序_Python3基础 list sort 从小(大)到大(小)排序
  5. catia齿轮宏程序_Catia宏程序
  6. 他们和机器人啪啪啪,并计划共度一生
  7. Nacos(十二)之Java SDK
  8. 构建贝叶斯深度学习分类器
  9. BZOJ4435 : [Cerc2015]Juice Junctions
  10. 黑马程序员前端微信小程序开发教程,微信小程序从基础到发布全流程_企业级商城实战(含uni-app项目多端部署---b站视频跟学
  11. 等保二级和等保三级的三大区别讲解
  12. 知到网课中国戏曲剧种鉴赏考试试题|真题演练|题库(含答案)
  13. 使用栈进行括号匹配的判断
  14. 不刷机,京东云路由进openwrt后台
  15. Ubuntu 18 永久设置分辨率1920x1080
  16. 田纳西大学计算机科学,田纳西大学_田纳西大学(University of Tennessee)
  17. 苍蓝钢铁Android界面,苍蓝钢铁战舰 Re:Birth
  18. Python年利率计算器【N日年化收益率】
  19. Oracle同义词总结归纳
  20. 从输入网址到页面呈现的详细过程

热门文章

  1. UNIX编程艺术学习笔记-1
  2. 用VC++自制王码五笔输入法安装包(转)
  3. 数据结构试卷三(含答案)
  4. 高等数学(上)思维导图
  5. JAVA制作简单的查询身份证号信息小程序
  6. Java后端编程技术微信群和QQ群
  7. 基于大数据的高校贴吧舆情数据分析系统
  8. Linux新手快速入门(万字超详细)
  9. 最新老韩泰牛PHP基础班+大牛班+大牛班高级课程
  10. 微信小程序授权登录(获取微信头像并显示)