C++MFC 串口通信 上位机

news2024/11/19 13:42:38

本节介绍

        在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信。串口通信方便易行,应用广泛。
        一般情况下,工控机和各智能仪表通过RS485总线进行通信。RS485的通信方式是半双工的,只能由作为主节点的工控PC机依次轮询网络.上的各智能控制单元子节点。每次通信都是由PC机通过串口向智能控制单元发布命令,智能控制单元在接收到正确的命令后作出应答。
        在Win32下,可以使用两种编程方式实现串口通信,其一是使用ActiveX控件,这种方法程序单,但欠灵活。其二是调用Windows的API函数,这种方法可以清楚地掌握串口通信的机制,并且自由灵活。本文我们只介绍API串口通信部分。
        接下来我们来实现一个串口调试助手!

ADO访问数据库
        ➢1、 安装串口虚拟软件
        ➢2、 打开串口
        ➢3、设置串口属性(波特率、奇偶校验等)
        ➢4、 读写串口
        ➢5、 校验(求和校验、CRC校验 )
        ➢6、 通信协议

建立工程

项目是在visual studio2005编译器内创建,点击“文件”->“新建”->“项目”

 按照图标提示选择,点击下一步。

 单击下一步,下一步,完成。

 点击完成后:

 接下来开始构建项目:

编辑如图所示的窗口:

 在WinDemoDlg.h中声明初始化函数

public:
	void InitComboBox();

 在WinDemoDlg.cpp中实现改函数:

void CWinDemoDlg::InitComboBox(){
	CComboBox* pComboComm=(CComboBox*)GetDlgItem(IDC_COMBO_COMM);
	ASSERT(pComboComm);
	for(int i=1;i<=8;i++){
		CString strComm;
		strComm.Format(_T("COM%d"),i);
		pComboComm->AddString(strComm);
	}
	pComboComm->SetCurSel(0);

	//波特率
	CComboBox* pComboBaudrate=(CComboBox*)GetDlgItem(IDC_COMBO_BAUDRATE);
	ASSERT(pComboBaudrate);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("300")),300);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("600")),600);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("1200")),1200);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("2400")),2400);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("4800")),4800);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("9600")),9600);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("19200")),19200);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("43000")),43000);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("56000")),56000);
	pComboBaudrate->SetItemData(pComboBaudrate->AddString(_T("1152000")),1152000);
	pComboBaudrate->SetCurSel(5);
	
	//校验位
	CComboBox* pComboCheckBit=(CComboBox*)GetDlgItem(IDC_COMBO_CHECKBIT);
	ASSERT(pComboCheckBit);
	pComboCheckBit->SetItemData(pComboCheckBit->AddString(_T("无None")),NOPARITY);
	pComboCheckBit->SetItemData(pComboCheckBit->AddString(_T("奇ODD")),ODDPARITY);
	//pComboCheckBit->SetItemData(pComboCheckBit->AddString(_T("偶EUEN")),EUENPARITY);
	pComboCheckBit->SetCurSel(0);

	//数据位
	CComboBox* pComboDateBit=(CComboBox*)GetDlgItem(IDC_COMBO_DATABIT);
	ASSERT(pComboDateBit);
	pComboDateBit->SetItemData(pComboDateBit->AddString(_T("6")),6);
	pComboDateBit->SetItemData(pComboDateBit->AddString(_T("7")),7);
	pComboDateBit->SetItemData(pComboDateBit->AddString(_T("8")),8);
	pComboDateBit->SetCurSel(0);

	//停止位
	CComboBox* pComboStopBit=(CComboBox*)GetDlgItem(IDC_COMBO_STOPBIT);
	ASSERT(pComboStopBit);
	pComboStopBit->SetItemData(pComboStopBit->AddString(_T("1")),ONESTOPBIT);
	pComboStopBit->SetItemData(pComboStopBit->AddString(_T("2")),TWOSTOPBITS);
	pComboStopBit->SetCurSel(0);


}

 并将初始化函数放入OnInitDialog()函数中:

 添加一个串口类,这个串口类用来实现具体的串口通信:

        点击“项目”->“添加类”

         添加一般的C++类即可

         将类名设置为:CSerialPort

 其中CSerialPort.h代码如下:

#pragma once

class CSerialPort
{
public:
	CSerialPort(void);
public:
	~CSerialPort(void);
public:
	BOOL OpenComm(CString strComm);
	BOOL SetCommState(DWORD dwBaudrate,BYTE byParity,BYTE byByteSize,BYTE byStopBits);
	BOOL SetupComm(DWORD dwInQueue,DWORD dwOutQueue);
	BOOL PurgeComm(DWORD dwFlags);
	BOOL SetCommMask(DWORD dwEvtMask);
	BOOL WriteFile(IN LPCVOID lpBuffer,IN DWORD nNumberOfBytesToWrite,OUT LPDWORD lpNumberOfBytesWritten,IN LPOVERLAPPED lpOverlapped);
	BOOL ReadFile(OUT LPVOID lpBuffer,IN DWORD nNumberOfBytesToRead,OUT LPDWORD lpNumberOfBytesRead,IN LPOVERLAPPED lpOverlapped);
	BOOL ClearCommError(OUT LPDWORD lpErrors,OUT LPCOMSTAT lpStat);
	BOOL GetOverlappedResult(IN LPOVERLAPPED lpoverlapped,OUT LPDWORD lpNumberOfByterTransferred,IN BOOL bWait);
	void CloseComm();	//关闭窗口

public:
	HANDLE m_hComm;

};

CSerialPort.cpp代码如下:

#include "StdAfx.h"
#include "SerialPort.h"

CSerialPort::CSerialPort(void)
{
	m_hComm=NULL;
}

CSerialPort::~CSerialPort(void)
{
}
BOOL CSerialPort::OpenComm(CString strComm){
	if(NULL==m_hComm){
		m_hComm=CreateFile((TCHAR*)(LPCTSTR)strComm,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,0);
		if(INVALID_HANDLE_VALUE==m_hComm){
			int nError=GetLastError();
			m_hComm=NULL;
			return FALSE;
		}
		return TRUE;
	}
	return FALSE;

}
BOOL CSerialPort::SetCommState(DWORD dwBaudrate,BYTE byParity,BYTE byByteSize,BYTE byStopBits){
	if(NULL==m_hComm) return FALSE; 
	DCB dcb;
	BOOL bRet= ::GetCommState(m_hComm,&dcb);
	if(!bRet){
		if(m_hComm){

			//CloseHandle(m_hComm);
			m_hComm=NULL;
		}
		return FALSE;
	}
	dcb.BaudRate=dwBaudrate;
	dcb.ByteSize=byByteSize;
	dcb.Parity=byParity;
	dcb.StopBits=byStopBits;
	bRet=::SetCommState(m_hComm,&dcb);
	if(!bRet){
		if(m_hComm){

			CloseHandle(m_hComm);
			m_hComm=NULL;
		}
		return FALSE;
	}
	return TRUE;
}
BOOL CSerialPort::SetupComm(DWORD dwInQueue,DWORD dwOutQueue){
	if(NULL==m_hComm) return FALSE; 
	return ::SetupComm(m_hComm,dwInQueue,dwOutQueue);
}
BOOL CSerialPort::PurgeComm(DWORD dwFlags){
	if(NULL==m_hComm) return FALSE; 

	return ::PurgeComm(m_hComm,dwFlags);
}
BOOL CSerialPort::SetCommMask(DWORD dwEvtMask){
	if(NULL==m_hComm) return FALSE; 

	return ::SetCommMask(m_hComm,dwEvtMask);
}
BOOL CSerialPort::WriteFile(IN LPCVOID lpBuffer,IN DWORD nNumberOfBytesToWrite,OUT LPDWORD lpNumberOfBytesWritten,IN LPOVERLAPPED lpOverlappe)
{
	if(NULL==m_hComm) return FALSE; 

	return ::WriteFile(m_hComm,lpBuffer,nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlappe);
}
BOOL CSerialPort::ReadFile(OUT LPVOID lpBuffer,IN DWORD nNumberOfBytesToRead,OUT LPDWORD lpNumberOfBytesRead,IN LPOVERLAPPED lpOverlapped)
{
	if(NULL==m_hComm) return FALSE; 

	return ::ReadFile(m_hComm,lpBuffer,nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
}
BOOL CSerialPort::ClearCommError(OUT LPDWORD lpErrors,OUT LPCOMSTAT lpStat)
{
	if(NULL==m_hComm) return FALSE; 

	return ::ClearCommError(m_hComm,lpErrors,lpStat);
}
BOOL CSerialPort::GetOverlappedResult(IN LPOVERLAPPED lpoverlapped,OUT LPDWORD lpNumberOfByterTransferred,IN BOOL bWait)
{
	if(NULL==m_hComm) return FALSE; 

	return ::GetOverlappedResult(m_hComm,lpoverlapped,lpNumberOfByterTransferred,bWait);
}
//关闭窗口
void CSerialPort::CloseComm(){
	if(m_hComm){
		CloseHandle(m_hComm);
		m_hComm=NULL;
	}
}	

        这时就封装好了一个串口类,一旦串口开始工作的时候,需要一个线程,用这个线程来进行收发数据;线程运行时通过ReadFile()函数从串口中读出数据,如果有数据需要将数据放到接受框中显示出来。

        下面创建一个线程,一个串口对应一个线程对象,创建C++类,类名为:CThread。

 CThread.h代码:

#pragma once

class CThread
{
public:
	CThread(void);
public:
	~CThread(void);
public:
	void Start();
	void Stop();
public:
	virtual void SetThreadData(DWORD dwParam);
	virtual DWORD GetThreadData();

public:
	virtual void run();
public:
	static DWORD ThreadProc(LPVOID pParam);
public:
	HANDLE m_hThread;
	bool m_bExit;
	DWORD m_dwParam;

};

CThread.cpp代码:

#include "StdAfx.h"
#include "Thread.h"

CThread::CThread(void)
{

	m_bExit=FALSE;
	m_dwParam=0;
	m_hThread=NULL;
}

CThread::~CThread(void)
{
	if(!m_bExit){
		Stop();
	}
}
void CThread::Start()
{
	DWORD dwThreadID;	//获取的线程ID
	HANDLE hThread=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadProc,this,0,&dwThreadID);
	ASSERT(hThread);
	m_hThread=hThread;
}
DWORD CThread::ThreadProc(LPVOID pParam)
{
	CThread* pThis=(CThread*)pParam;
	ASSERT(pThis);

	while(!pThis->m_bExit)
	{
		pThis->run();
	}
	return TRUE;
}
void CThread::Stop()
{
	if(m_hThread)
	{
		m_bExit=true;
		::WaitForSingleObject(m_hThread,INFINITE);
		::CloseHandle(m_hThread);
		m_hThread=NULL;
	}
}
void CThread::run()
{
	Sleep(100);
}
void CThread::SetThreadData(DWORD dwParam)
{
	if(m_dwParam!=dwParam)
	{
		m_dwParam=dwParam;
	}
}
DWORD CThread::GetThreadData()
{
	return m_dwParam;
}

接下来需要从这个线程派生出一个基类,创建C++类,类名为:CThreadComm; CThreadComm用来处理串口数据的收发线程。

CThreadComm.h代码:

CThreadComm.cpp代码:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件测试知识库+1,5款顶级自动化测试工具推荐和使用分析

“工欲善其事必先利其器”&#xff0c;在自动化测试领域&#xff0c;自动化测试工具的核心地位不容置疑的。目前市面上有很多可以支持接口测试的工具&#xff0c;在网上随便一搜就可以出来很多&#xff0c;利用自动化测试工具进行接口测试&#xff0c;可以很好的提高测试效率&a…

Web3创新者之夜,与其他开发者一同畅谈波卡生态

Token2049在即&#xff0c;许多开发者都将在9月中齐聚新加坡&#xff0c;一同讨论区块链生态发展及未来。届时将会有超过1万名与会者&#xff0c;并有超过300个赞助商和项目协助支持本次大会。波卡作为跨链互操作性的龙头生态也将参与至本次盛会之中。 为了让波卡社区的成员、贡…

uniapp微信小程序消息订阅快速上手

一、微信公众平台小程序开通消息订阅并设置模板 这边的模板id和详细内容后续前后端需要使用 二、uniapp前端 需要是一个button触发 js&#xff1a; wx.getSetting({success(res){console.log(res)if(res.authSetting[scope.subscribeMessage]){// 业务逻辑}else{uni.request…

Python+Selenium自动化测试环境搭建步骤(selenium环境搭建)

一、自动化简介 1.自动化测试概念&#xff1a; 是把以人为驱动的测试转化为机器执行的一种过程&#xff0c;它是一种以程序测试程序的过程 2.自动化测试分类&#xff1a; 一般IT上所说的自动化测试是指功能自动化测试&#xff0c;通过编码的方式用一段程序来测试一个软件的功…

Ctfshow web入门 命令执行RCE篇 web29-web77 与 web118-web124 详细题解 持续更新中(预计8.18完成)~

Ctfshow 命令执行 web29 pregmatch是正则匹配函数&#xff0c;匹配是否包含flag&#xff0c;if(!preg_match("/flag/i", $c))&#xff0c;/i忽略大小写 可以利用system来间接执行系统命令 flag采用f*绕过&#xff0c;或者mv fl?g.php 1.txt修改文件名&#xff0c…

初识Visual Basic编辑器并建立一段简单的代码(下)

【分享成果&#xff0c;随喜正能量】时间宝贵&#xff0c;切莫贪睡。学习诸大菩萨的精神&#xff0c;勇猛精进不懈怠&#xff1b;随缘进取不疲厌。单是说不行&#xff0c;要紧的是做。 《VBA之Excel应用》&#xff08;10178983&#xff09;是非常经典的&#xff0c;是我推出的…

【运维】linkis1.3.2添加jdbc引擎(添加mysql、greenplum、starrocks、doris数据源查询)与配合多数据源管理提交任务初探

文章目录 一. 引擎的安装1. 前置工作2. 获取引擎插件3. 上传和加载4. 引擎刷新4.1. 重启刷新4.2. 检查引擎是否刷新成功 二. 测试mysql、starrocks与doris数据库1. 通过shell提交任务2. 通过(IDE)shell进行提交3. 通过接口提交 三. 添加greenplum四. 通过linkis的数据源管理提交…

【java毕业设计】基于SSM+MySql的人才公寓管理系统设计与实现(程序源码)--人才公寓管理系统

基于SSMMySql的人才公寓管理系统设计与实现&#xff08;程序源码毕业论文&#xff09; 大家好&#xff0c;今天给大家介绍基于SSMMySql的人才公寓管理系统设计与实现&#xff0c;本论文只截取部分文章重点&#xff0c;文章末尾附有本毕业设计完整源码及论文的获取方式。更多毕业…

VGG简单学习

VGG简单学习 简单介绍 在AlexNet网络的基础上&#xff0c;为了设计深层神经网络&#xff0c;牛津大学设计了VGG网络,采用块的设计理念&#xff0c;将AlexNet中多个重复的卷积层和池化层组成一个块 论文中&#xff0c;使用3x3卷积核&#xff0c;padding1的卷积层 和带有2x2的汇…

网工内推 | 网络工程师专场,CCNP证书优先,多次晋升机会

01 上海正诺信息科技有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责公司办公内网内网需求对接、实施和方案的标准化&#xff1b; 2、负责办公网络、机房的网络设备&#xff08;接入层&#xff09;的运维、变更、故障解决&#xff1b; 3、负责公司网…

网络通信原理ARP协议(第四十六课)

ARP/RARP报文 ARP(Address Resolution Protocol,地址解析协议)是用来将IP地址解析为MAC地址的协议。RARP(Reverse Address Resolution Protocol,反向地址解析协议)是用来将MAC地址解析为IP地址的协议。 字段长度(bit)含义Ethernet Address of Destination48比特目的…

【GitHub】Pycharm本地项目打包上传到Github仓库的操作步骤

文章目录 1、Pycharm端的设置操作2、Github端的设置操作3、Pycharm上配置Github4、Git本地项目至GitHub仓库5、前往Github中查看确认6、常见报错 1、Pycharm端的设置操作 通过CtrlAltS快捷组合键的方式&#xff0c;打开设置&#xff0c;导航到版本控制一栏中的Git&#xff0c;…

【视频笔记】2023年上半年最耀眼的AI创业公司

大模型赛道&#xff1a; OpenAI&#xff08;估值270-290亿美元&#xff09;&#xff1a;继续融资3亿美元 Anthropic&#xff08;估值50亿美元&#xff09;&#xff1a;绑定谷歌、免费开放Claude2 Adept&#xff08;估值10亿美元&#xff09;&#xff1a;推出ACT-1模型&#xf…

Navicat Premium连接sqlserve数据库失败?你需要注意这几点看看配置对了么?

新建数据库连接的时候这么填的信息 报错 原因1&#xff1a;sqlserver数据库的端口和IP地址之间不是&#xff1a;连接而是用&#xff0c;连接 改成如下样式用逗号连接端口和IP地址就好了 原因2&#xff1a;在Navicat Premium中需要安装一个sqlserver的插件 找到安装路径的根目…

2023年Android性能优化常见30道面试题解

在Android开发领域&#xff0c;性能优化是一个关键而广泛讨论的话题。对于任何一位Android开发者而言&#xff0c;了解和掌握性能优化的技巧是至关重要的。无论是在开发过程中还是在面试环节中&#xff0c;掌握Android性能优化的知识都能展示出你作为一名优秀开发者的能力。 本…

机器学习需要面对的两大问题:泛化性和可信性

随着人工智能的迅速发展&#xff0c;机器学习成为了炙手可热的领域&#xff0c;它让计算机能够从数据中学习并做出智能决策。然而&#xff0c;机器学习在取得巨大成功的同时&#xff0c;也面临着两个重大挑战&#xff1a;泛化性和可信性。这两大问题的解决关系到机器学习应用的…

驱动开发day3

#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include<linux/io.h> #include <linux/device.h> #include "led.h"int major; char kbuf[256] {0};//定义指针接收映射…

【HarmonyOS北向开发】-01 HarmonyOS概述

飞书原文链接-【HarmonyOS北向开发】-01 HarmonyOS概述https://fvcs2dhq8qs.feishu.cn/docx/TDf2d2KMaoPSUUxnvg2cASDdnCe?fromfrom_copylink

k8s 自身原理之高可用

说到高可用&#xff0c;咱们在使用主机环境的时候&#xff08;非 k8s&#xff09;&#xff0c;咱做高可用有使用过这样的方式&#xff1a; 服务器做主备部署&#xff0c;当主节点和备节点同时存活的时候&#xff0c;只有主节点对外提供服务&#xff0c;备节点就等着主节点挂了…

Typora上传文件到Gitee

工作内容,不对外开放 一、Typora上传笔记到CSDN 一、安装node.js 官网链接:Node.js (nodejs.org) 下载后得到一个.msi文件,双击即可。 win + R 打开CMD,基于node -v 和npm -v,验证是否安装成功: 二、配置Gitee 1、新建仓库 2、开源此仓库 2.1、初始化readme文件