基于MFC的串口通信

1、串口通信的概述:

串口是一种重要的通信资源,例如鼠标口、USB接口都是串口。串行端口是CPU和串行设备间的编码转换器。当数据从CPU经过端口发送出去的时候,字节数据会被转为串行的位,在接收数据时,串行的位被转换为字节数据。

(1)、串口通信的特点:

数据通信多采用串口技术,主要因为串口可以在现有的电话网络上进行数据传输。串口通信是按照数据一位一位的依次传输,所以一根传输线就可以完成数据交换,降低了通信成本。

(2)、串口通信的传输方式

串口通信按照数据流可以分为三种传输方式:单工通信、半双工通信、全双工通信。

单工通信:使用一根导线,数据只能从A发送到B

半双工通信:是用一根导线,数据可以从A发送到B,也可以从B发送到A。但是不能同时进行

全双工通信:俩根导线。允许通信双方在俩个方向同时进行数据传输。

(3)、通信方式

同步通信:接收方不必对每个字节进行起始和停止的操作,传输效率高。传输设备复杂,双方时钟允许误差小。可用于点对点之间的数据传输。

异步通信:以字符为单位进行数据传输,并且每个字符都有起始位和停止位的标记。允许各个字符之间有间隙,俩个字符之间的间隔不固定。异步通信的传输效率低,传输设备简单,并且只适用于点对点的数据传输。

2、利用Mscomm进行串口通信:

(1)、字符格式收发:

1)、初始化框架的ICON和发送EDIT的文本

初始化框架上的内容,应该位于框架类的构造函数中

CComDlg::CComDlg(CWnd* pParent /*=NULL*/)

初始化ICON:m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON_EARTH); // 图标改成地球
    

  初始化发送EIDT的文本:  m_strSend = "My first SerialPortTool!";

2)、初始化下拉列表

初始化下拉列表位于入口函数中

入口函数:

CComDlg::OnInitDialog

初始化串口号,波特率,校验位,数据位,停止位 

    m_cboPort.SetCurSel(0);
    m_cboBaudRate.SetCurSel(4);
    m_cboCheck.SetCurSel(0);
    m_cboDataBit.SetCurSel(3);
    m_cboStopBit.SetCurSel(0);

3)、获取我们界面中的设置到CMscomm类中的对象中

UI的串口设置中的打开按钮,添加打开按钮事件。

UpdateData(TRUE); //将控件中的内容同步到变量中,我们操作控件就相当于操作变量。

    CString strOpen;//strOpen来获得按钮上面的文字内容。
    GetDlgItemText(IDC_BUTTON_OPEN, strOpen);
    
    if(strOpen == "打开")
    {    //1、执行打开串口操作

        m_mscomm.put_InBufferSize(1024); //接收缓冲区  
        m_mscomm.put_OutBufferSize(1024);//发送缓冲区   
        m_mscomm.put_InputLen(0);//设置当前接收区数据长度为0,表示全部读取  
        m_mscomm.put_InputMode(CMscomm::comInputModeBinary);//以二进制方式读写数据   
        m_mscomm.put_RThreshold(1);//接收缓冲区有1个及1个以上字符时,将引发接收数据的OnComm事件
        
        //2、获取我们界面中的设置到CMscomm类中的对象中
        //校验位,犹豫我们拼接字符串,但是校验位比较特殊,很多设备没有校验位所以我们不能直接使用value类型变量
        CString strCheck = getCheck();

        CString strSettings = m_strBaudRate + strCheck + m_strDataBit + m_strStopBit;
        //MessageBox(strSettings);
        //"9600,n,8,1" 和 "9600n81" 均对
        //m_mscomm.put_Settings(_T("9600,n,8,1"));//波特率9600,无检验位,8个数据位,1个停止位  
        m_mscomm.put_Settings(strSettings);

        //端口号
        //put_CommPort参数直接代表串口号为1,m_cboPort.GetCurSel() + 1目的增加了复用性。
        m_mscomm.put_CommPort(m_cboPort.GetCurSel() + 1);//索引从0开始

getCheck()获取当前的校验位

//步骤2、获取校验位
CString CComDlg::getCheck(void)
{CString strCheck;switch(m_cboCheck.GetCurSel()){case 0: strCheck = "n"; break;//无校验case 1:  strCheck = "o"; break;//基校验case 2: strCheck = "e"; break;//偶校验case 3: strCheck = "m"; break;case 4:strCheck = "s"; break;default:break;}return strCheck;
}

 

4)、真正打开串口的操作

我们点击打开串口的时候,调用put_PortOpen打开串口,并且要做一个异常捕获。

打击打开串口的操作,我们的打开按钮得更换文本内容为关闭

同时有一个bmp的资源图片也会随着串口的打开和关闭改变图片

try
        {
            m_mscomm.put_PortOpen(TRUE);//put_PortOpen(TRUE),参数为TRUE则打开串口,为FALSE则关闭串口
        }
        catch (CException* e)
        {
            MessageBox("端口不存在!", "打开串口", MB_ICONERROR);
            return;
        }
        
        SetDlgItemText(IDC_BUTTON_OPEN, _T("关闭")); //串口打开之后,设置按钮为“关闭”

        CBitmap bitmap;  // CBitmap对象,用于加载位图    
        HBITMAP hBmp;    // 保存CBitmap加载的位图的句柄   
  
        bitmap.LoadBitmap(IDB_BITMAP_GREEN);  // 将位图IDB_BITMAP1加载到bitmap   
        hBmp = (HBITMAP)bitmap.GetSafeHandle();  // 获取bitmap加载位图的句柄   
        m_picIndicator.SetBitmap(hBmp);    // 设置图片控件m_picIndicator的位图图片为IDB_BITMAP_RED 
    }
    else // 4、此时串口已经处于打开状态 执行关闭串口
    {
        m_mscomm.put_PortOpen(FALSE);//put_PortOpen(TRUE),参数为TRUE则打开串口,为FALSE则关闭串口  
        SetDlgItemText(IDC_BUTTON_OPEN, _T("打开")); //串口打开之后,设置按钮为“关闭”

        CBitmap bitmap;  // CBitmap对象,用于加载位图    
        HBITMAP hBmp;    // 保存CBitmap加载的位图的句柄   
  
        bitmap.LoadBitmap(IDB_BITMAP_RED);  // 将位图IDB_BITMAP1加载到bitmap   
        hBmp = (HBITMAP)bitmap.GetSafeHandle();  // 获取bitmap加载位图的句柄   
        m_picIndicator.SetBitmap(hBmp);    // 设置图片控件m_picIndicator的位图图片为IDB_BITMAP_RED  
    }

5)、发送2进制或者16进制数据

首先当我们点击发送按钮的时候,进行一个异常捕获,如果串口没有打开之间弹出对话框串口未打开,然后我们进行一个勾选框的判断,判断发送的是2进制还是十六进制数据,最后进行数据处理和发送

UpdateData(TRUE); //1、读取编辑框内容 ,内容写到控件中,然后同步到变量中//2、什么时候发送,发送的条件就是文本内容是“发送”CString strSend;GetDlgItemText(IDC_BUTTON_SEND, strSend);if(strSend == "发送"){	//3、执行串口发送操作try{CString strOrdered = "";if(1 == m_chkHexSend.GetCheck())//当勾选框被选中的时候{	//以十六进制发送hexToSend.RemoveAll();//清空数组//十六进制 41 42 43 41空格为一组,42空格为一组....。strOrdered = GetOrderedStr();//MessageBox(strOrdered);for(int i = 0; i< strOrdered.GetLength(); i += 2){CString strTemp = strOrdered.Mid(i, 2);char *p = strTemp.GetBuffer(2);hexToSend.Add(strtol(p, NULL, 16));}m_mscomm.put_Output(COleVariant(hexToSend));//发送的二进制转换成16进制//4、这里如果串口没有打开直接写数据程序会崩溃,可能有异常直接try catch}else{//没有选中以字符格式发送strToSend = m_strSend;m_mscomm.put_Output(COleVariant(strToSend));//发送数据}

这里我们如果发送的是十六进制数据进行一个消息处理

CString CComDlg::GetOrderedStr()
{
    CString str;

    int i = 0;
    int length = m_strSend.GetLength();
    for(i = 0; i < length - 1; i++)//"31 32 33 回车 34"   "34 31 327"    "34 31 32 7"    "32 33 3 34"
    {
        if(m_strSend.Mid(i, 1) != " " && m_strSend.Mid(i, 1) != "\r")
        {
            if(m_strSend.Mid(i+1, 1) !=  " " && m_strSend.Mid(i+1, 1) !=  "\r")
            {
                CString strTemp;
                strTemp = m_strSend.Mid(i, 2);
                str = str + strTemp;
                i++;
            }
            else
            {
                str = str + "0" + m_strSend.Mid(i, 1);
            }
        }

        if(m_strSend.Mid(i, 1) == "\r" && m_strSend.Mid(i+1, 1) == "\n") //碰到回车,也就是\n\r,则直接跳过\n\r这两个字符! 
            i++;     
    }    

    if(i == m_strSend.GetLength()-1 && m_strSend.Mid(i, 1) != " ")
        str = str + "0" + m_strSend.Mid(i, 1);  //该行防止"34 31 32 7"中7丢失
    //至此, "31323334"      "34313207"      "34313207"     "32330334"

    //MessageBox(str);

    return str;
}

6)、接收十六进制或者二进制数据

void CComDlg::OnCommMscomm()
{// TODO: 在此处添加消息处理程序代码UpdateData(TRUE); static unsigned int cnt=0;  VARIANT variant_inp;    COleSafeArray safearray_inp;   long len,k;    byte rxdata[1024]; //设置 BYTE 数组   CString strtemp; //通过声明这样一个字节数组,您可以在后续的代码中使用rxdata来存储从串口读取的二进制数据switch(m_mscomm.get_CommEvent())  //1、如果我们读取到事件{case CMscomm::comEvReceive: //值为 2 表示接收缓冲区内有字符  //2、从串口缓冲区读取数据m_mscomm.put_InputMode(CMscomm::comInputModeBinary);//规定二进制方式读取数据cnt++;   variant_inp = m_mscomm.get_Input();   //  variant_inp = m_mscomm.get_Input()这行代码用于从串口读取数据,并将读取的数据存储在variant_inp变量中safearray_inp = variant_inp;   //variant_inp中的数据转换为SAFEARRAY类型,并存储在safearray_inp变量中。len = safearray_inp.GetOneDimSize(); //得到有效的数据长度   //状态栏显示接收到的字符个数CString strReceiveNum;m_ulReceiveNum += len;strReceiveNum.Format("%d", m_ulReceiveNum);strReceiveNum = "接收:" + strReceiveNum;m_StatusBar.SetText(strReceiveNum, 2, 0);//SBT_POPOUT, SBT_NOBORDERS//3、接收数据for(k = 0; k < len; k++)    {   safearray_inp.GetElement(&k, rxdata + k);if(1 == m_chkHexReceive.GetCheck()) //接收到的数据以十六进制显示{//safearray_inp.GetElement(&k, rxdata + k);  CString strtemp = "";strtemp.Format(_T("%02X"),rxdata[k]);//rxdata[k] 的值以十六进制格式添加到 strtemp 字符串中m_strReceive = m_strReceive + strtemp + " "; }else	//接收到的数据以字符格式显示{CString strtemp = "";//safearray_inp.GetElement(&k, rxdata + k);    strtemp.Format("%c",rxdata[k]); //将字符送入临时变量strtemp存放m_strReceive = m_strReceive + strtemp;//m_strReceive接收EDIT的变量}	}if (1 == m_chkHexReceive.GetCheck()) // 如果以十六进制显示,最后再加上一个换行{m_strReceive += "\r\n";}else{m_strReceive += "\n";}break;}UpdateData(FALSE); //更新编辑框内容//注意:在更新完编辑框的内容之后,还要设置接收编辑框定位到最后一行int nLineCount = m_editReceive.GetLineCount();int nLineLength = m_editReceive.LineLength(nLineCount);m_editReceive.LineScroll(nLineCount, nLineLength);//TRACE("%d", nLineCount);
}

7)、点击十六进制发送的时候,EDIT的内容变成十六进制

//将发送的文本内容直接从二进制编程变成16进制
void CComDlg::OnBnClickedCheckSendHex()
{	// TODO: 在此添加控件通知处理程序代码UpdateData(TRUE);if (1 == m_chkHexSend.GetCheck()) //此时要把字符格式转换成十六进制{char *p = m_strSend.GetBuffer(m_strSend.GetLength());m_strSend.ReleaseBuffer();CString str = "";int length = m_strSend.GetLength();for(int i = 0; i < length; i++){CString strTemp;strTemp.Format("%02X", p[i]);str = str + strTemp + " ";}m_strSend = str.TrimRight(" ");}else	//此时要把十六进制转换成字符格式{int length = m_strSend.GetLength();CString str;for(int i = 0; i< length; i += 3){CString strTemp = m_strSend.Mid(i, 2);char *p = strTemp.GetBuffer(2);int num = strtol(p, NULL, 16);strTemp.Format("%c", num);str = str + strTemp;}m_strSend = str;}UpdateData(FALSE);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/171782.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

听GPT 讲Rust源代码--library/std(5)

File: rust/library/std/src/sys/unsupported/time.rs 在Rust源代码中&#xff0c;rust/library/std/src/sys/unsupported/time.rs文件的作用是提供对于时间的支持&#xff0c;特别是在不支持的操作系统上。 该文件中包含了两个结构体定义&#xff0c;分别是Instant和SystemTim…

竞赛 深度学习大数据物流平台 python

文章目录 0 前言1 课题背景2 物流大数据平台的架构与设计3 智能车货匹配推荐算法的实现**1\. 问题陈述****2\. 算法模型**3\. 模型构建总览 **4 司机标签体系的搭建及算法****1\. 冷启动**2\. LSTM多标签模型算法 5 货运价格预测6 总结7 部分核心代码8 最后 0 前言 &#x1f5…

SpringMVC Day 04 : 数据绑定

前言 SpringMVC是一个非常流行的Java Web框架&#xff0c;它提供了很多方便的功能和工具来帮助我们构建高效、灵活的Web应用程序。其中&#xff0c;数据绑定就是SpringMVC中非常重要的一部分&#xff0c;它可以帮助我们方便地将请求参数绑定到Java对象上&#xff0c;从而简化了…

LLM在text2sql上的应用 | 京东云技术团队

一、前言&#xff1a; 目前&#xff0c;大模型的一个热门应用方向text2sql它可以帮助用户快速生成想要查询的SQL语句。那对于用户来说&#xff0c;大部分简单的sql都是正确的&#xff0c;但对于一些复杂逻辑来说&#xff0c;需要用户在产出SQL的基础上进行简单修改&#xff0c…

16 用于NOMA IoT网络上行链路安全速率最大化的HAP和UAV协作框架

文章目录 摘要相关模型仿真实验仿真结果 摘要 优化无人机到HAP的信道分配、用户功率和无人机三维位置来研究上行安全传输解决非凸问题&#xff0c;采用K-means聚类算法&#xff0c;将成对的用户划分成不同的组&#xff0c;每个簇可以有相应的无人机服务&#xff0c;然后将构造…

实验六:DHCP、DNS、Apache、FTP服务器的安装和配置

1. (其它) 掌握Linux下DHCP、DNS、Apache、FTP服务器的安装和配置&#xff0c;在Linux服务器上部署JavaWeb应用 完成单元八的实训内容。 1、安装 JDK 2、安装 MySQL 3、部署JavaWeb应用 安装jdk 教程连接&#xff1a;linux安装jdk8详细步骤-CSDN博客 Jdk来源&#xff1a;linu…

鱼眼图像去畸变python / c++

#鱼眼模型参考链接 本文假设去畸变后的图像与原图大小一样大。由于去畸变后的图像符合针孔投影模型&#xff0c;因此不同的去畸变焦距得到不同的视场大小&#xff0c;且物体的分辨率也不同。可以见上图&#xff0c;当焦距缩小为一半时&#xff0c;相同大小的图像&#xff08;横…

Prompt设计与大语言模型微调

本文主要介绍了Prompt设计、大语言模型SFT和LLM在手机天猫AI导购助理项目应用。 ChatGPT基本原理 “会说话的AI”&#xff0c;“智能体” 简单概括成以下几个步骤&#xff1a; 预处理文本&#xff1a;ChatGPT的输入文本需要进行预处理。输入编码&#xff1a;ChatGPT将经过预处理…

matlab simulink ADRC控制样例

1、内容简介 略 3-可以交流、咨询、答疑 2、内容说明 用adrc控制传递函数&#xff0c;保证输出达到预期 ADRC控制器、传递函数 3、仿真分析 4、参考论文 略

《ATTCK视角下的红蓝对抗实战指南》一本书构建完整攻防知识体系

一. 网络安全现状趋势分析 根据中国互联网络信息中心&#xff08;CNNIC&#xff09;发布的第51次《中国互联网络发展状况统计报告》&#xff0c;截至2022年12月&#xff0c;我国网民规模为10.67亿&#xff0c;互联网普及率达75.6%。我国有潜力建设全球规模最大、应用渗透最强的…

.\missyou-0.0.1-SNAPSHOT.jar中没有主清单属性

引用&#xff1a;https://blog.csdn.net/marypiglwy/article/details/132016171 配置的时候 <skip>true</skip> skip设置为true&#xff0c;跳过了执行插件&#xff0c;&#xff0c; <plugin><groupId>org.springframework.boot</groupId><a…

C++前缀和算法的应用:预算内的最多机器人数目

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 单调双向队列 滑动窗口 题目 你有 n 个机器人&#xff0c;给你两个下标从 0 开始的整数数组 chargeTimes 和 runningCosts &#xff0c;两者长度都为 n 。第 i 个机器…

编程实例:眼镜店顾客档案管理系统软件,可以登记顾客信息查询历史记录,视力检查登记查询,配镜销售单开单打印

编程实例&#xff1a;眼镜店顾客档案管理系统软件&#xff0c;可以登记顾客信息查询历史记录&#xff0c;视力检查登记查询&#xff0c;配镜销售单开单打印 编程系统化课程总目录及明细&#xff0c;点击进入了解详情。 https://blog.csdn.net/qq_29129627/article/details/1340…

【@EnableWebMvc的原理】

用途 启用SpringMvc 的 Java 配置类&#xff0c;代替 xml 格式的配置文件。 一、查看运用&#xff08;注解 EnableWebMvc &#xff0c;实现 WebMvcConfigurer &#xff09; Component("com.ibicd") EnableWebMvc public class AppConfig implements WebMvcConfigu…

Unity的unity_ObjectToWorld里的每一列分别代表什么意思?换个方向反向理解-更简单

官方关键UnityObjectToWorldNormal&#xff08;&#xff09; 代码 从乐乐姐的书中得知&#xff0c;当我们在shader想获得法线&#xff0c;大概会这么些 o.wordDir UnityObjectToWorldNormal(i.normal) &#xff08;这行代码就包含了官方对“unity_ObjectToWorld”的终极理解…

在 Windows 用 Chrome System Settings 设置代理

在 Windows 用 Chrome System Settings 设置代理 贴心提示&#xff1a;在设置代理之前&#xff0c;请确保您已经安装了 浏览器。 &#x1f527; 设置代理的详细步骤如下&#xff1a; 打开 浏览器&#xff0c;输入 //settings/system 并回车。 在「系统和网络设置」页面中&am…

matlab Spongent算法

1、内容简介 略 5-可以交流、咨询、答疑 2、内容说明 Spongent 是一种轻量级 Hash 算法&#xff0c;其原理与“海绵”类似&#xff0c;分为“吸收” 和“榨取”两个阶段&#xff0c;所以又可以称之为“海绵结构”算法。 Hash 函数之所以有广泛的应用&#xff0c;是因为它具…

MySQL数据库#6

Python操作mysql 在使用Python连接mysql之前我们需要先下载一个第三方的模块 pymysql的模块&#xff0c;导入后再进行操作。 操作步骤&#xff1a;1. 先连接mysql host&#xff0c;port&#xff0c;charset&#xff0c;username password 库&#xff0c;等等。 import pymysql…

如何恢复u盘删除文件?2023最新分享四种方法恢复文件

U盘上删除的文件怎么恢复&#xff1f;使用U盘存储文件是非常方便的&#xff0c;例如&#xff1a;在办公的时候&#xff0c;会使用U盘来存储网络上查找到的资料、产品说明等。在学习的时候&#xff0c;会使用U盘来存储教育机构分享的教学视频、重点知识等。而随着U盘存储文件的概…