【教程】从零开始用QT简易实现modbus通信

前言:本文旨在让读者了解在qt6中实现modbus通信主要使用哪些函数,需要引用哪些库和头文件,不对modbus协议进行介绍,仅在代码层面简单实现一个modbus通信案例

实现效果:点击读取按钮可以读取从机中的十个寄存器,点击写入按钮可以将从机0x02地址的寄存器写入数值3

开发环境:QT6        

工程源码:链接:https://pan.baidu.com/s/1GFO7qe0GcjCUG9G_oojtsA?pwd=6b10 
提取码:6b10

本文学习目标:实现由主机通过modbus RTU协议向从机发送读取/写入命令

第一步:下载相关软件:从机模拟软件ModbusSlave,虚拟串口配置器VSPD

链接:https://pan.baidu.com/s/1F4bHn1sO_dAvcn2xjq8Cjg?pwd=tudu 
提取码:tudu

第二步:创建一个qt工程,这里起名modbus_example

创建工程的其他参数使用默认值即可

第三步:绘制ui

双击mainwindow.ui打开ui设计界面,添加4个push button和1个plain text edit,然后对QWidget点击栅格布局

把四个按钮的objectName依次改为btn_open,btn_close,btn_read,btn_write

第四步:添加库和头文件

1、在pro文件中添加serialport和serialbus库

2、在.h文件中添加相关的头文件

#include <QSerialPort>
#include <QtSerialBus>
#include <QModbusDataUnit>
#include <QModbusClient>

第五步:添加数据成员

在mainwindow.h中添加private成员modbus Device;

第六步:编写【打开串口】按钮的槽函数

1、在ui界面右键【打开串口】按钮,选择转到槽,再选择clicked(),确认

2、在槽函数中设置串口的各项参数

void MainWindow::on_btn_open_clicked()
{// 设置modbus串口参数 modbusDevice.setConnectionParameter(QModbusDevice::SerialPortNameParameter, QStringLiteral("COM1"));    //串口名:COM1modbusDevice.setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud9600);     //波特率:9600modbusDevice.setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);        //数据位:8位modbusDevice.setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);      //停止位:1位modbusDevice.setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);       //校验位:无校验 

3、在槽函数中添加以下代码,其中connectDevice()函数实现连接串口

    //打开串口if (!modbusDevice.connectDevice()){ui->plainTextEdit->insertPlainText("串口连接失败!");return;}else{ui->plainTextEdit->insertPlainText("串口连接成功!");}

4、编译运行工程文件,检查有无问题,点击打开串口后,文本框中应出现“串口连接成功”

第七步:添加【关闭串口】按钮的槽函数

1、添加按钮的槽函数,与第六步步骤相同

2、输入以下代码

void MainWindow::on_btn_close_clicked()
{modbusDevice.disconnectDevice();ui->plainTextEdit->insertPlainText("串口已关闭!");
}

3、运行工程进行检查

第八步:编写【读取寄存器】按钮的槽函数

1、给按钮添加槽函数

2、输入以下代码

void MainWindow::on_btn_read_clicked()
{//定义"读请求"对象QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0, 10);    //0是所要读取的寄存器起始地址,10是所要读取的寄存器个数//发送请求auto *reply = modbusDevice.sendReadRequest(readUnit, 1);//连接信号与槽    connect(reply, &QModbusReply::finished, this,&MainWindow::onReadyRead); 
}

在这里,我们还没有定义onReadyRead函数,所以会报错

3、声明与定义onReadyRead函数:

在Mainwindow.h的private slots一栏输入void onReadyRead(),声明onReadyRead函数,右键->重构->在mainwindow.cpp中添加定义

在onReadyRead()函数中添加代码

void MainWindow::onReadyRead()
{auto reply=qobject_cast<QModbusReply *>(sender());  //接收信号,并将信号发送者强制转换成QModbusReply类的对象//检测回复是否正常if (reply->error() == QModbusDevice::NoError)       //从机回复无异常{ui->plainTextEdit->insertPlainText("读取成功!");reply->deleteLater();   //稍后卸载reply}else                                                //从机回复异常{ui->plainTextEdit->insertPlainText("读取失败!");reply->deleteLater();   //稍后卸载replyreturn;}// 从reply中获取数据单元const QModbusDataUnit unit = reply->result();// 将数据值转换为字符串QString dataStr;for (int i = 0; i < unit.valueCount(); ++i) {dataStr += QString::number(unit.value(i)) + " ";}// 输出到plainTextEdit控件中ui->plainTextEdit->insertPlainText("数据值:" + dataStr);
}

4、运行文件检验

先打开VSPD虚拟串口配置器,点击Add Pair

打开modbusSlave,双击改变寄存器中的值

点击上方工具栏中的Connection,按照图中参数设置,然后点击OK

回到QT,编译运行工程项目,先点击【打开串口】,再点击【读取寄存器】,成功读取从0x00地址开始的10个寄存器中的值

看到以上内容即为成功

第九步:添加【写入寄存器】的槽函数

1、给按钮添加槽函数

2、输入代码

void MainWindow::on_btn_write_clicked()
{// 检查modbusDevice的连接状态if (modbusDevice.state() != QModbusDevice::ConnectedState) {ui->plainTextEdit->insertPlainText("写入失败!");return;}// 创建QModbusDataUnit对象,用于写入寄存器QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, 0x02, 1); // 写入寄存器起始地址0x02,写入寄存器数量1// 设置要写入的数据值为0writeUnit.setValue(0, 3); //参数1:寄存器索引的偏移量,参数2:写入的值// 发送写入请求modbusDevice.sendWriteRequest(writeUnit, 1);  //写入请求,写入从机IDui->plainTextEdit->insertPlainText("写入成功");
}

3、运行检查

点击写入寄存器后,观察到从机中地址为0x02的寄存器值被修改为了3,写入成功

结语:

本文仅展示了实现modbus通信实现读取和写入功能有哪些需要使用的函数、库、头文件,为了使代码简洁,没有实现对通信异常情况的处理,读者学习后可以自行修改相关参数,或自行定义函数提供用户交互界面去变更这些参数,实现更加复杂的功能

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

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

相关文章

【QT】鼠标按键事件 - QMouseEvent QKeyEvent

qt 事件 事件1. 事件概念2. 事件的处理3. 按键事件&#xff08;1&#xff09;单个按键&#xff08;2&#xff09;组合按键 4. 鼠标事件&#xff08;1&#xff09;鼠标单击事件&#xff08;2&#xff09;鼠标释放事件&#xff08;3&#xff09;鼠标双击事件&#xff08;4&#x…

【数据分析】统计学基础及Python具体实现

各位大佬好 &#xff0c;这里是阿川的博客&#xff0c;祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 Python 初阶 Python–语言基础与由来介绍 Python–…

【Python】已解决:ERROR: Could not install packages due to an OSError: [WinError 5] 拒绝访问。: ‘e:\anaconda\in

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;ERROR: Could not install packages due to an OSError: [WinError 5] 拒绝访问。: ‘e:\anaconda\install_root\scripts\pip.exe’ Consider using the --user o…

C语言详解(结构体)

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸各位能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎~~ &#x1f4a5;个人主页&#xff1a;小羊在奋斗 &#x1f4a5;所属专栏&#xff1a;C语言 本系列文章为个人学习笔记&#xff0c;在这里撰写成文一…

【MAVEN】如何解决“Error unmarshaling return header; nested exception is: java.io.EOFException“?

目录标题 异常现场分析解决Chat GPT出场一下增大【Build process heap size (Mbytes) 】试试&#x1f64f;增大【Maven->importing->VM options for importer】试试✅Idea的所有配置说明 异常现场 Error unmarshaling return header; nested exception is: java.io.EOFEx…

C++内存管理(区别C语言)深度对比

欢迎来到我的Blog&#xff0c;点击关注哦&#x1f495; 前言 前面已经介绍了类和对象&#xff0c;对C面向对象编程已经有了全面认识&#xff0c;接下来要学习对语言学习比较重要的是对内存的管理。 一、内存的分区 代码区&#xff1a;存放程序的机器指令&#xff0c;通常是可…

IntelliJ IDEA安装教程(超详细)

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a; IDEA的使用 IDEA的简单介绍IDEA的主要优势IDEA的卸载IDEA的安装第一个程序&#xff1a;HelloWorld结束语 IDEA的简单介绍…

JAVA (Springboot) i18n国际化语言配置

JAVA i18n国际化语言配置 一、简介二、功能三、Java配置国际化步骤四、Java国际化配置工具类五、Spring Boot配置六、测试 一、简介 在Java中&#xff0c;国际化&#xff08;Internationalization&#xff0c;通常简称为i18n&#xff09;是一个过程&#xff0c;它允许应用程序…

【C语言项目】实现一个通讯录,一步一步详细讲解,小白也能看

目录 设计思路 代码实现 代码改造1 代码改造2 完整代码 代码仓库 设计思路 1. 通讯录存放的信息 这个通讯录保存的信息包括&#xff1a;名字&#xff0c;年龄&#xff0c;性别&#xff0c;电话&#xff0c;住址。 2. 通讯录的功能 1. 通讯录可以存放100个人的信息。 2…

2024年 Java 面试八股文(20w字)

> &#x1f345;我是小宋&#xff0c; 一个只熬夜但不秃头的Java程序员。 > &#x1f345;关注我&#xff0c;带你**过面试,读源码**。提升简历亮点&#xff08;14个demo&#xff09; > &#x1f345;我的面试集已有12W 浏览量。 > &#x1f30f;号…

[C++] 深度剖析C_C++内存管理机制

文章目录 内存分布内存分布图解 C语言中动态内存管理方式malloc:callocrealloc C内存管理方式内置类型**自定义类型** operator new & operator deleteoperator new & operator delete函数operator newoperator delete **new T[N]** 与**delete[]** **定位new表达式(pl…

【C语言】指针由浅入深全方位详解!!!

目录 指针 野指针 二级指针 指针数组 字符指针 数组指针 数组参数&#xff0c;指针参数 函数指针 函数指针数组 回调函数 练习题 代码仓库 指针 1. 指针定义 1. 指针是内存中一个最小单元的编号&#xff0c;也就是地址。 2. 平时口语中说的指针&#xff…

【C++】如何巧妙运用C++命名空间:初学者必备指南

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01; 本篇将带领大家走进C的旅途&#xff0c;为了更好地学习C这门语言&#xff0c;我们需要了解它的前世今生。在了解完C如何诞生后&#xff0c;将开始我们C之旅第一站"命名空间"。(老早说是C/C博主&…

Java 集合框架:HashMap 的介绍、使用、原理与源码解析

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 020 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

零基础入门转录组数据分析——GO+KEGG富集分析

零基础入门转录组数据分析——GOKEGG富集分析 目录 零基础入门转录组数据分析——GOKEGG富集分析1. 富集分析基础知识2. GO富集分析&#xff08;Rstudio&#xff09;——代码实操3. KEGG富集分析&#xff08;Rstudio&#xff09;——代码实操注&#xff1a;配套资源只要改个路径…

PyQt5| 界面设计 |利用Qt Designer实现简单界面交互

目录 1 QtDesigner简单界面设计2 代码部分2.1 ui文件转py文件2.2 界面文件代码2.3 主文件代码2.3.1 主体框架代码2.3.2 实现交互代码 3结果展示 准备工作&#xff1a; 配置好PyQt5相关的库、QtDesigner、pyuic 1 QtDesigner简单界面设计 点击“工具"——>“外部工具&a…

Matlab实现最小二乘法的几种方法

最小二乘法&#xff08;又称最小平方法&#xff09;是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。 按照图中所提出的问题&#xff08;如图1&#xff09;&#xff0c;要求已知多组解&#xff08;自变量和因变量&#xff09;&#xff0c;求出最佳和最恰…

【C++/STL深度剖析】priority_queue 最全解析(什么是priority_queue? priority_queue的常用接口有哪些?)

目录 一、前言 二、如何区分【优先级队列】与【队列】&#xff1f; 三、priority_queue的介绍 四、priority_queue 的构造 五、priority_queue 的常用接口 &#x1f4a7;push &#x1f4a7;pop &#x1f4a7;size &#x1f4a7;top &#x1f4a7;empty &…

C语言贪吃蛇课程设计实验报告(包含贪吃蛇项目源码)

文末有贪吃蛇代码全览,代码有十分细致的注释!!!文末有贪吃蛇代码全览,代码有十分细致的注释!!!文末有贪吃蛇代码全览,代码有十分细致的注释!!! 码文不易&#xff0c;给个免费的小星星和免费的赞吧&#xff0c;关注也行呀(⑅•͈ᴗ•͈).:*♡ 不要白嫖哇(⁍̥̥̥᷄д⁍̥̥…

【C++/STL】:vector容器的底层剖析迭代器失效隐藏的浅拷贝

目录 &#x1f4a1;前言一&#xff0c;构造函数1 . 强制编译器生成默认构造2 . 拷贝构造3. 用迭代器区间初始化4. 用n个val值构造5. initializer_list 的构造 二&#xff0c;析构函数三&#xff0c;关于迭代器四&#xff0c;有关数据个数与容量五&#xff0c;交换函数swap六&am…