原文作者:aircraft

原文地址:https://www.cnblogs.com/DOMLX/p/9490616.html

本文用的是VS2013MFC写串口数据接收:

第一步:首先建立一个MFC工程,成功后会跳出一个对话框,直接在对话框上点击右键-》点击插入ACTIVAE控件-》选择MicrosoftCommunications Control, version 6.0

成功后会显示一个电话的图标在对话框上,运行起来不会显示的 不用担心这个美观问题。如果没有这个插件的话,可能是版本太低  可以自己下载一个补上

第二步:大概的窗体搞好:   那个显示图片的大框是PICTURE控件变量

然后就要项目->类向导中定义变量了  如果你们是英文版就找英文字符对应的就行了。(英文不会比我还差吧 哈哈哈哈哈哈哈)

定义的变量大概如上图所示 ,那个小电话就是串口通信最重要的    变量ID是   IDC_MSCOMM1    变量名如上图:

这时候简单的绑定变量后 要开始写第一个小函数了  ,直接双击那个对话框上 BUTTON1这个按钮

这时候就会生成一个关联函数:代码如下:

void CMFCApplication2Dlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
if (m_ctrlComm.get_PortOpen())
m_ctrlComm.put_PortOpen(FALSE); m_ctrlComm.put_CommPort(); //注意了 这里因为我硬件端接我电脑的口是com4 所以我打开一样的 你们不知道自己是哪个的话 就打开硬件经常用的串口调试助手先找找 不过 测试的时候一定要关闭其他串口 不然会打开失败的
if (!m_ctrlComm.get_PortOpen())
{
m_ctrlComm.put_PortOpen(TRUE);//打开串口
AfxMessageBox(L" open serial port successfully");
}
else
AfxMessageBox(L"cannot open serial port"); m_ctrlComm.put_Settings(L"9600,n,8,1"); //波特率9600,无校验,8个数据位,1个停止位
m_ctrlComm.put_InputMode(); //1:表示以二进制方式检取数据
m_ctrlComm.put_RThreshold();
//参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
m_ctrlComm.put_InputLen(); //设置当前接收区数据长度为0
m_ctrlComm.get_Input();//先预读缓冲区以清除残留数据
}

好这是打开串口的函数 ,既然打开的串口那么硬件就要给我们发数据了 ,而mFC也要有接收的能力 所以这时候我们要添加一个 串口数据的响应函数:

可以双击那个消息函数改名字在点  添加处理程序应用:

然后插入代码:

void CMFCApplication2Dlg::onComm()
{
// TODO: 在此处添加消息处理程序代码
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len, k;
//BYTE rxdata[1000480];//设置BYTE数组 An 8-bit integerthat is not signed.
unsigned char * data = m_COMBits + m_COMIndex;
CString strtemp;
//m_COMIndex = 0;
if (m_ctrlComm.get_CommEvent() == ) //事件值为2表示接收缓冲区内有字符
{ ////////以下你可以根据自己的通信协议加入处理代码
variant_inp = m_ctrlComm.get_Input(); //读缓冲区
safearray_inp = variant_inp; //VARIANT型变量转换为ColeSafeArray型变量
len = safearray_inp.GetOneDimSize(); //得到有效数据长度 注意了这里数据是一段一段接收的
for (k = ; k < len; ++k, ++m_COMIndex)
{
if (m_COMIndex > * - )
break;
safearray_inp.GetElement(&k, data + k);//转换为BYTE型数组
}
if (m_COMIndex > * - )
{
m_COMIndex = ;
m_hasCOMImage = true;
LoadImageData(m_COMImage, m_COMBits);
OnPaint();
}
}
//UpdateData(FALSE); //更新编辑框内容
}

这里是我的图片大小 240*320的:

你们的自己看    至于为什么要大于后马上跳出循环呢   因为 接收数据是一段一段接收的从缓冲区  所以我们一次性接收够了我们就跳出来  要是一直接收肯定会炸的  不信可以自己试试哈哈哈哈哈哈

还有这里有时候会出现一个问题,就是  串口传输数据的时候回丢包     有时候单步调试的时候却不会丢包 丢字节   STM32   单片机51都有可能出现这种情况  (串口调试助手收发大量数据时是怎样处理的,新手求教,写了一个串口调试助手,接收数据会丢帧,串口通讯,丢包严重是什么问题,为什么串口单步调试正常,全速会丢包)这是因为因为CPU处理速度太快导致FIFO中数据早就被读完了,RBR为空,而后续的数据不能及时到达被MCU抛弃掉了。我加了一个延时就OK了   这里加延时 可以硬件端发送加  也可以MFC 中加  都可以反正  串口发送数据会丢包说白就是电脑跟不上  电脑垃圾    这时候我们就辅助一个延时函数 然程序停一下  慢点接  让缓冲区有点东西在接收

下面是绘制图片调用的函数:

第一个是 位图的数据操作辅助用的    第二是将图片数据LOAD

bool CMFCApplication2Dlg::InitalImage(CImage &image, int width, int height)
{
if (image.IsNull())
image.Create(width, height, );
else
{
if (width <= || height <= )
return false;
else if (image.GetHeight() == width && image.GetWidth() == height)
return true;
else
{
image.Destroy();
image.Create(width, height, );
}
}
//写入调色板
RGBQUAD ColorTable[];
image.GetColorTable(, , ColorTable);
for (int i = ; i < ; i++)
{
ColorTable[i].rgbBlue = (BYTE)i;
ColorTable[i].rgbGreen = (BYTE)i;
ColorTable[i].rgbRed = (BYTE)i;
}
image.SetColorTable(, , ColorTable);
return true;
}
void CMFCApplication2Dlg::LoadImageData(CImage &image, unsigned char * data)
{
if (data == nullptr)
return;
byte *pS;
byte *pImg = (byte *)image.GetBits();
int step = image.GetPitch();
int height = image.GetHeight();
int width = image.GetWidth();
for (int i = ; i < image.GetHeight(); ++i)
{
pS = data + i * width;
for (int j = ; j < image.GetWidth(); ++j)
{
*(pImg + i*step + j) = pS[j];
}
}
}

同样的 在Dlg头文件中药加上这两个函数的声明和用到变量的定义:

//位图函数
void CMFCApplication2Dlg::LoadImageData(CImage &image, unsigned char * data);
bool CMFCApplication2Dlg::InitalImage(CImage &image, int width, int height);
//位图数据
unsigned char m_COMBits[ * ];
int m_COMIndex;
bool m_hasCOMImage;
CImage m_COMImage;

然后在看Dlg.cpp文件  我们还需要几个函数:

第一  在Dlg::OnInitDialog()初始中 我们要先给图片变量分配内存 不然程序会中断:

InitalImage(m_COMImage, , );
m_COMIndex = ;

第二 要将图片绘制 就要绘制函数中操作Dlg::OnPaint():

首先定义下面要用到的变量

    int cx, cy;
CRect rect;
CWnd *pWnd = NULL;

然后加入调用的代码:

else
{
if (m_hasCOMImage && !m_COMImage.IsNull())
{
//获取图片的宽 高度
cx = m_COMImage.GetWidth();
cy = m_COMImage.GetHeight();
//ResizeWindow(cx, cy);
//获取IDC_PIC1的窗口指针
pWnd = GetDlgItem(IDC_PICCOM);
//获取Picture Control控件的大小
pWnd->GetWindowRect(&rect);
//将客户区选中到控件表示的矩形区域内
ScreenToClient(&rect);
//窗口移动到控件表示的区域
pWnd->MoveWindow(rect.left, rect.top, cx, cy, TRUE);
pWnd->GetClientRect(&rect);//获取句柄指向控件区域的大小
CDC *pDc = NULL;
pDc = pWnd->GetDC();//获取picture的DC
m_COMImage.Draw(pDc->m_hDC, rect);//将图片绘制到picture表示的区域内
ReleaseDC(pDc);
}

是在那个 onpaint():函数中的 else部分里面添加噢    给你们看看总体的  不要抄下面这个   用上面的就行了  复制下面这个也没用 因为对话框有不同:

void CMFCApplication2Dlg::OnPaint()
{
int cx, cy;
CRect rect;
CWnd *pWnd = NULL;
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), ); // 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + ) / ;
int y = (rect.Height() - cyIcon + ) / ; // 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
if (m_hasCOMImage && !m_COMImage.IsNull())
{
//获取图片的宽 高度
cx = m_COMImage.GetWidth();
cy = m_COMImage.GetHeight();
//ResizeWindow(cx, cy);
//获取IDC_PIC1的窗口指针
pWnd = GetDlgItem(IDC_PICCOM);
//获取Picture Control控件的大小
pWnd->GetWindowRect(&rect);
//将客户区选中到控件表示的矩形区域内
ScreenToClient(&rect);
//窗口移动到控件表示的区域
pWnd->MoveWindow(rect.left, rect.top, cx, cy, TRUE);
pWnd->GetClientRect(&rect);//获取句柄指向控件区域的大小
CDC *pDc = NULL;
pDc = pWnd->GetDC();//获取picture的DC
m_COMImage.Draw(pDc->m_hDC, rect);//将图片绘制到picture表示的区域内
ReleaseDC(pDc);
}
//确认对话框数据中是否有一张完整的图像
/*
if (m_hasFileImage && !m_FileImage.IsNull())
{
//获取图片的宽 高度
cx = m_FileImage.GetWidth();
cy = m_FileImage.GetHeight();
//ResizeWindow(cx, cy);
//获取IDC_PIC1的窗口指针
pWnd = GetDlgItem(IDC_PICFILE);
//获取Picture Control控件的大小
pWnd->GetWindowRect(&rect);
//将客户区选中到控件表示的矩形区域内
ScreenToClient(&rect);
//窗口移动到控件表示的区域
pWnd->MoveWindow(rect.left, rect.top, cx, cy, TRUE);
pWnd->GetClientRect(&rect);//获取句柄指向控件区域的大小
CDC *pDc = NULL;
pDc = pWnd->GetDC();//获取picture的DC
m_FileImage.Draw(pDc->m_hDC, rect);//将图片绘制到picture表示的区域内
ReleaseDC(pDc);
}
*/
CDialogEx::OnPaint();
}
}

要   清空缓冲 的数据的话    就这样双击那个按钮 加这个:

void CMFCApplication2Dlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
m_COMIndex = ;
}

好了这就是所有的代码了 ,语文不好可能需要一点MFC基础才能听得懂哈哈哈哈哈:

不过给你们准备了福利嘿嘿嘿,我测试的项目代码:

MFC做上位机与USB串口连接传输数据显示图像:链接:https://pan.baidu.com/s/1iQyeu50-2joZgp4xedGzpg 密码:bed9

若有兴趣交流分享技术,可关注本人公众号,里面会不定期的分享各种编程教程,和共享源码,诸如研究分享关于c/c++,python,前端,后端,opencv,halcon,opengl,机器学习深度学习之类有关于基础编程,图像处理和机器视觉开发的知识

2018最新mfc作为上位机接收硬件端USB或串口数据显示成图片 解决串口接收数据丢字节丢包问题的更多相关文章

  1. vc++MFC开发上位机程序

    用vc++MFC开发过不少跟单片机通讯的上位机程序了.搞懂了MFC架构,开发还是很快的,与底层单片机程序通讯,可以用串口.usb.网络.短信形式.串口现在用的越来越少了,一般电脑跟单片机在一块,使用串 ...

  2. MFC开发上位机到底用Dialog结构还是文档结构?

    最近要跟着导师一起开发一款大型上位机.MFC新人在考虑用对话框结构还是文档结构. 虽然说书上说大型结构的软件都需要文档结构,但是目前来看,对话框可以实现功能,并且对话框的程序更小一些,节省资源加载速度 ...

  3. USBCAN的使用和上位机开发(MFC)

    USBCAN使用手册 参见:https://blog.51cto.com/12572800/2062839 1. USB CAN软件安装与硬件接线 USB CAN是常用的CAN测试工具.它的软件资料存 ...

  4. VC++编写简单串口上位机程序

    VC++编写简单串口上位机程序   转载: http://blog.sina.com.cn/s/articlelist_1809084904_0_1.html VC++编写简单串口上位机程序 串口通信 ...

  5. 物联网框架ServerSuperIO.Core(.netcore)跨平台,一套设备驱动通吃嵌入式、上位机、云服务

    1.      概述... 2 2.      ServerSuperIO.Core跨平台开发环境... 2 3.      ServerSuperIO.Core特点... 2 4.      Ser ...

  6. 我编写的EEPROM 上位机软件

    进入模式: 上位机发送 消息 上位机EEPROM 按下进入模式 消息的ID号是:0x08111111 数据是: 00 01 ff 00 00 00 00 00 上位机显示 运行状态 :为进入模式 当我 ...

  7. 2-关于单片机通信数据传输(中断接收,大小端,IEEE754浮点型格式,共用体,空闲中断,环形队列)

    上一篇链接 http://www.cnblogs.com/yangfengwu/p/8628219.html 先说明一点这种方式,不光对于单片机类的,,对于上位机接收数据同样适用----不骗人的,自己 ...

  8. C++ MFC实现基于RFID读写器的上位机软件

    C++ MFC实现基于RFID读写器的上位机软件 该博客涉及的完整工程托管在https://github.com/Wsine/UpperMonitor,觉得好请给个Star (/▽\=) 运行和测试环 ...

  9. VS2015编写的MFC上位机,波特率可调,可动态显示曲线,可显示三维

    VS2015编写的MFC上位机,波特率可调,可动态显示曲线,可显示三维 2016年01月14日 11:40:28 博博有个大大大的Dream 阅读数:9375   版权声明:本文为博主原创文章,未经博 ...

随机推荐

  1. [.net 多线程]Mutex

    Mutex是可以进程间同步的同步基元.   名称 说明 Mutex() 使用默认属性初始化 Mutex 类的新实例. Mutex(Boolean) 使用 Boolean 值(指示调用线程是否应具有互斥 ...

  2. session相关

    判断session是否已失效: HttpSession session=request.getSession(false); getSession(boolean)相比于getSession()更安全 ...

  3. php代码审计6审计xss漏洞

    跨站脚本攻击(Cross Site Scripting)是指攻击者利用网站程序对用户输入过滤不足,输入可以显示在页面上对其他用户造成影响的html代码,从而盗取用户资料,利用用户身份进行某种动作或者对 ...

  4. 图层锁定vlisp函数高版本图元自动淡色显示

    (defun c:tt(/ obj) (sk_layerLock (getvar "clayer") nil) (princ) ) ;;;name:sk_layerLock ;;; ...

  5. 【智能算法】迭代局部搜索(Iterated Local Search, ILS)详解

    迭代局部搜索(Iterated Local Search, ILS) 源代码下载请关注微信公众号[程序猿声],在后台回复:[ILS],不包括[]即可下载. 00 目录 局部搜索算法 简单局部搜索 迭代 ...

  6. javascript jquery console调试方法说明

    控制台(Console)是Firebug的第一个面板,也是最重要的面板,主要作用是显示网页加载过程中产生各类信息. 一.显示信息的命令 Firebug内置一个console对象,提供5种方法,用来显示 ...

  7. SQLServer如何清除缓存?

    --1. 将当前数据库的全部脏页写入磁盘.“脏页”是已输入缓存区高速缓存且已修改但尚未写入磁盘的数据页. -- CHECKPOINT 可创建一个检查点,在该点保证全部脏页都已写入磁盘,从而在以后的恢复 ...

  8. WinForm中如何实现在容器控件中嵌入form窗体(panel与子窗体)

    今天在做项目时候遇到一个问题,窗体分为左右两部分,要求在左边栏点击按钮时,右边动态加载窗体最后想到用panel实现,经历几次失败,并查找资料后,终于搞定 说明:如果多次切换需加入 panel.clea ...

  9. Xilinx FPGA使用——ROM初始化文件

    在调用ROM的IP Core时,需要对其进行初始化,利用MATLAB生成其初始化数据文件. 工具:ISE 14.7.MATLAB.notepad++ 废话不多说,直接上MATLAB代码,生成了一个10 ...

  10. python 并发之多进程实现

    一.multipricessing模块的介绍 python中的多线程无法利用多核优势,如果想要充分的使用多核CPU资源,在python中大部分情况下需要用多线程,python提供了multiproce ...