QT编写串口MODBUS实时接收深入--实际项目应用

Modbus--->使用ModbusPoll、ModbusSlave、虚拟串口分析MODBUS-RTU数据帧格式、报文实例帧结构,和Modbus协议格式 文章目录使用Modbus poll&Modbus slave模拟Modbus主从通信虚拟串口基础知识积累MODBUS-RTU报文模型主机对从机写数据操作主机对从机写数据操作后,从机的返回内容主机对从机读数据操作主机对从机读数据操作后,从机对主机返回内容Modbus-RTU常用功能码寄存器起始地址(起始数据地址) 使用Modbus poll&Modbus slave模拟Modbus主从通信  下载和破解搜一下都很方便,使用的时候Modbus Poll作为Master,Modbus slave作 阅读详情

一、前言

        前面有文章写过modbus的串口和TCP的数据写与读的使用方法,本文着重讲解下在串口中modbus数据接收的实时接收。在做项目的时候数据接收往往是很重要的一环,数据发送很简单,自行查找资料,实时数据接收,监听数据是每一个产品必备的功能,接下来分享下我自己写的一个实时监听的例子。

        由于以前不是写QT的,用的多的是单片机,单片机里面数据接收往往使用中断,轮巡会导致出现一些问题,我在以前的批量项目中遇到过一次,轮巡的数据与实际应用存在冲突的情况,所以一般推荐使用中断的形式。刚接触QT还不太熟悉QT的机制,就目前了解,QT不存在单片机那种中断的机制,但是提供了信号与槽,达到相似功能。信号与槽的知识分享可以查阅我的前面文章有一篇专门讲解我对它的浅薄理解。而且数据缓冲区也没有写,等后续如果有需要再写数据缓冲。

        然后就是数据一直监听刷新的话,我使用了简单的定时器来处理,还有其他方法,但是我觉得定时器容易上手一些。本来想做一个组态软件那样可以自己设置全局变量,其他地方拖拽组件自己设置参数的,但是写着写着发现有点难,暂时还完成不了,有很多疑惑,需要后续一一去攻克。所以就先写了个页面监控的方法,先能用起来,后续再优化。

二、代码讲解

头文件

#ifndef PERSON_H
#define PERSON_H

#include <QMainWindow>
#include <QTimer>
#include <QModbusRtuSerialMaster>
#include <QModbusDevice>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QModbusResponse>

namespace Ui {
class Person;
}

class Person : public QMainWindow
{
    Q_OBJECT

public:
    explicit Person(QWidget *parent = nullptr);
    ~Person();

private slots:
    void on_pushButton_home_clicked();

    void on_pushButton_user_clicked();

    void on_pushButton_auto_clicked();

    void on_pushButton_setting_clicked();

    void on_pushButton_monitor_clicked();

    void on_pushButton_formula_clicked();

    void on_pushButton_history_clicked();

private:
    Ui::Person *ui;
    QTimer *m_timer;


    QModbusRtuSerialMaster *m_modbusrtumaster;
};

#endif // PERSON_H

头文件添加相应的类,这个写到哪添加到哪就行,把定时器定义一下后续方便使用。

cpp

#include "person.h"
#include "ui_person.h"

#include "mainwindow.h"
#include "user.h"
//#include "person.h"
#include "auto.h"
#include "setting.h"
#include "monitor.h"
#include "history.h"
#include "formula.h"

#include <qmessagebox.h>

Person::Person(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Person)
{
    ui->setupUi(this);
    //串口连接
    m_modbusrtumaster = new QModbusRtuSerialMaster(this);
    m_modbusrtumaster->setConnectionParameter(QModbusDevice::SerialPortNameParameter, "COM3");
    m_modbusrtumaster->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::EvenParity);
    m_modbusrtumaster->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, 115200);
    m_modbusrtumaster->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);
    m_modbusrtumaster->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);
    /**************************ModBus数据接收*********************************/
    //数据刷新
    m_timer = new QTimer(this);
    m_timer->start(100);//100ms
    connect(m_timer,&QTimer::timeout,this,[=]()
    {
        //链接设备
        if(m_modbusrtumaster->state() != QModbusRtuSerialMaster::ConnectedState)
        {
            if(m_modbusrtumaster->connectDevice())
            {
                qDebug() << "串口驱动链接成功";
            }
            else
            {
                qDebug() << "串口驱动链接失败";
            }
        }

        //起始位
        /*****Q线圈输入*******/
        QModbusDataUnit unit_Q(QModbusDataUnit::Coils, 0, 8);//读8个位
        /*****I离散输入*******/
        QModbusDataUnit unit_I(QModbusDataUnit::DiscreteInputs, 0, 8);//读8个位
        /*****MW输入寄存器*******/
        QModbusDataUnit unit_MW(QModbusDataUnit::InputRegisters, 0, 8);//读8个位
        /*****VW保持寄存器*******/
        QModbusDataUnit unit_VW(QModbusDataUnit::HoldingRegisters, 0, 8);//读8个位


        //发送请求响应
        QModbusReply *reply_Q = m_modbusrtumaster->sendReadRequest(unit_Q, 1);
        QModbusReply *reply_I = m_modbusrtumaster->sendReadRequest(unit_I, 1);
        QModbusReply *reply_MW = m_modbusrtumaster->sendReadRequest(unit_MW, 1);
        QModbusReply *reply_VW = m_modbusrtumaster->sendReadRequest(unit_VW, 1);
        if(reply_Q || reply_I || reply_MW || reply_VW)
        {
            if((!reply_Q->isFinished())||(!reply_I->isFinished())||(!reply_MW->isFinished())||(!reply_VW->isFinished()))
            {
                connect(reply_Q, &QModbusReply::finished, this, [=]()
                {
                    if(reply_Q->result().valueCount()>0)
                    {
                        ui->lineEdit_Q00->setText(QString::number(reply_Q->result().value(0)));
                        ui->lineEdit_Q01->setText(QString::number(reply_Q->result().value(1)));
                        ui->lineEdit_Q02->setText(QString::number(reply_Q->result().value(2)));
                        ui->lineEdit_Q03->setText(QString::number(reply_Q->result().value(3)));
                        ui->lineEdit_Q04->setText(QString::number(reply_Q->result().value(4)));
                        ui->lineEdit_Q05->setText(QString::number(reply_Q->result().value(5)));
                        ui->lineEdit_Q06->setText(QString::number(reply_Q->result().value(6)));
                        ui->lineEdit_Q07->setText(QString::number(reply_Q->result().value(7)));
                    }
                });
                connect(reply_I, &QModbusReply::finished, this, [=]()
                {
                    if(reply_I->result().valueCount()>0)
                    {
                        ui->lineEdit_I00->setText(QString::number(reply_I->result().value(0)));
                        ui->lineEdit_I01->setText(QString::number(reply_I->result().value(1)));
                        ui->lineEdit_I02->setText(QString::number(reply_I->result().value(2)));
                        ui->lineEdit_I03->setText(QString::number(reply_I->result().value(3)));
                        ui->lineEdit_I04->setText(QString::number(reply_I->result().value(4)));
                        ui->lineEdit_I05->setText(QString::number(reply_I->result().value(5)));
                        ui->lineEdit_I06->setText(QString::number(reply_I->result().value(6)));
                        ui->lineEdit_I07->setText(QString::number(reply_I->result().value(7)));
                    }
                });
                connect(reply_MW, &QModbusReply::finished, this, [=]()
                {
                    if(reply_MW->result().valueCount()>0)
                    {
                        ui->lineEdit_MW00->setText(QString::number(reply_MW->result().value(0)));
                        ui->lineEdit_MW01->setText(QString::number(reply_MW->result().value(1)));
                        ui->lineEdit_MW02->setText(QString::number(reply_MW->result().value(2)));
                        ui->lineEdit_MW03->setText(QString::number(reply_MW->result().value(3)));
                        ui->lineEdit_MW04->setText(QString::number(reply_MW->result().value(4)));
                        ui->lineEdit_MW05->setText(QString::number(reply_MW->result().value(5)));
                        ui->lineEdit_MW06->setText(QString::number(reply_MW->result().value(6)));
                        ui->lineEdit_MW07->setText(QString::number(reply_MW->result().value(7)));
                    }
                });
                connect(reply_VW, &QModbusReply::finished, this, [=]()
                {
                    if(reply_VW->result().valueCount()>0)
                    {
                        ui->lineEdit_VW00->setText(QString::number(reply_VW->result().value(0)));
                        ui->lineEdit_VW01->setText(QString::number(reply_VW->result().value(1)));
                        ui->lineEdit_VW02->setText(QString::number(reply_VW->result().value(2)));
                        ui->lineEdit_VW03->setText(QString::number(reply_VW->result().value(3)));
                        ui->lineEdit_VW04->setText(QString::number(reply_VW->result().value(4)));
                        ui->lineEdit_VW05->setText(QString::number(reply_VW->result().value(5)));
                        ui->lineEdit_VW06->setText(QString::number(reply_VW->result().value(6)));
                        ui->lineEdit_VW07->setText(QString::number(reply_VW->result().value(7)));
                    }
                });
                return;
            }
            reply_Q->deleteLater();
            reply_I->deleteLater();
            reply_MW->deleteLater();
            reply_VW->deleteLater();
        }
    });
    /***********************************************************************/
}

Person::~Person()
{
    delete ui;
}

void Person::on_pushButton_home_clicked()
{
    MainWindow *manage = new MainWindow;
    manage->show();
    deleteLater();
}

void Person::on_pushButton_user_clicked()
{
    if (m_limits == 1)//管理员可进
    {
        User *u = new User;
        u->show();
        deleteLater();
    }
    else
    {
        QMessageBox::warning(this, "警告", "权限不足");
    }
}

void Person::on_pushButton_auto_clicked()
{
    Auto *aut = new Auto;
    aut->show();
    deleteLater();
}

void Person::on_pushButton_setting_clicked()
{
    Setting *st = new Setting;
    st->show();
    deleteLater();
}

void Person::on_pushButton_monitor_clicked()
{
    Monitor *mr = new Monitor;
    mr->show();
    deleteLater();
}

void Person::on_pushButton_formula_clicked()
{
    Formula *fa = new Formula;
    fa->show();
    deleteLater();
}

void Person::on_pushButton_history_clicked()
{
    History *his = new History;
    his->show();
    deleteLater();
}

cpp的思路主要是创建一个定时器,定时100ms,时间可以根据情况自己设置,但是要调试下,看下时间设置太小会不会出现数据为读取完成的情况。然后就是有个问题,串口只有一个口,不同modbus数据类型只能通过一个口监控,当然富裕仗除外。刚开始我在这里思维有点困住了,一直在分情况写,但是调试的时候发现,口被第一个占用了,剩下的没法使用,换了好多种方法都不行,后面就想到为什么要分开写,一起监控就好了,毕竟数据是一起的。所以就把Q、I、MW、VW一起监控了,再用connect去相应收到的数据类型,比如我收到了Q类型数据,以它为信号对应的Q类型数据写槽动作读取数据。写的时候有不知道的类可以查阅帮助文件,或者使用AI解读,但是AI帮助还是没那么大,可以弥补基础,他生成的代码还是有很多不能用,也有很多不符合自己的想法。

三、测试视频

ModBus串口数据接收

ModBus协议部分功能码设计与实现方法(QT环境) QT环境下实现ModbusRTU以及ModBusTCP。支持功能码:0x01、0x03、0x0f、0x10 阅读详情

相关推荐

QT 篇 QT上位机串口编程

QT 篇 QT上位机串口编程 最近因为项目需要,需要用到上位机,通过串口与上位机进行通讯,来上传和下发一些数据以及控制指令,所以用QT写了一个上位机,并记录下来,免得到时候要用又到处翻资料。 QT版本:QT Creater 4.80 默认安装好QT了 1.新建工程 选择Qt Widgets 然后下一步 自己填一个项目名字和项目路径 我只安装了这一个,我就选了这个 这里主要是一些基类的选择 这里我选择QMainWindow 类名,文件名什么的,你们看看要不要改名 项目管理这里版本控制选择无 然后就完

Cheng0717的博客 2万+

Qt 上位机串口编程 Modbus编程

      Qt是由Qt Company开发的主流跨平台C++图形用户界面应用程序开发框架。  Qt是面向对象的框架,容易扩展,并且允许真正地组件编程,既可以开发GUI程序,也可用于控制台工具和服务器。     串口(Serial Port),也称串行通讯接口(通常指COM口), 串口通信是指将数据一个比特一个比特地逐位进行传输的通信模式。其特点是通信线路简单,传送速度较慢。Qt串口通信是借助一个QSerialPort的对象来方便的对串口进行读写。   Modbus是一种串行通信协议,是施耐德电气发表工业标准协议。Qt Modbus通讯 采用QModbusRtuSerialMaster 、QModbusRtuSerialSlave等类来实现Modbus通讯相关的功能    本课程主要帮助学员熟练掌握 Qt 5框架串口编程,Modbus协议编程,并且通过两个实战工具项目,为学习Qt 上位机编程 串口、Modbus编程打下坚固的基础! 

【Qt Modbus通信】QModbus实现modbus的主机功能 源码分享

modbus在上下位机数据交互时被广泛使用,因此写了这篇笔记和大家一起学习。【QtModbus通信】libmodbus实现modbus的主机功能/从机功能源码分享之前使用libmodbus实现了modbus的主从功能,但发现主机查询从机的从机ID不能大于200+,因此参考QT5的modbusDEMO重新写了一份基于QModbus实现的modbus主机功能。.........

qq_37373742的博客 1万+

ModbusRTU协议帧详解

ModbusRTU协议帧详解一.协议帧表格二.读取发送帧和返回帧格式三.写数据发送帧和返回帧格式四.功能码定义五.注意事项,必看 一.协议帧表格 二.读取发送帧和返回帧格式 读取帧格式: 地址 功能码 起始地址高字节 起始地址低字节 读取寄存个数高字节 读取寄存个数低字节 CRC低字节 CRC高字节 读取帧格式: 0X01 0x03 0x00 0x00 0x00 0x02 xx xx 返回帧格式: 地址 功能码 数据长度(读取寄存器个数乘以2) 数据部分 CRC低字节 CRC高

qq_41340733的博客 4741

【QT】串口调试助手(串口编程代码详解)

串口助手最终效果图 QT布局设计 serial.ui 项目框架结构 工程配置文件serial.pro QT += core gui serialport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 # The following define makes your compiler emit warnings if you use # any Qt feature that has .

风浪云HH的博客 2万+

QT中的Modbus

类在Qt的Modbus模块中是用来表示Modbus协议中不同类型数据单元的。找不到就向父类找,这里是qmodbusdevice有一个定义链接参数的函数,自行查阅手册看下详细。有串口的名字、校验位、波特率、数据位、停止位;还有网口的端口号与IP地址。如果是用来与PLC通信的话,一般用的最多的是。这里我们做测试选个持续的寄存器。

MasterPJ的博客 3145

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

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

year599168784的博客 1万+

基于QT的Modbus RTU主站

Modbus RTU主站应用很常见,有一些是通用的,有一些是专用的。而这里我们希望实现一个主要针对我们的产品调试的Modbus RTU主站工具。在开始软件设计之前,我们先来简略地分析一下,实现这样一个Modbus RTU主站工具包含的主要内容有哪些。

qq_40170041的博客 1047

【Qt】modbus之串口模式读操作

00. 目录 文章目录00. 目录01. 概述02. 开发环境03. 读DiscreteInputs程序示例04. 读Coils程序示例05. 读InputRegisters程序示例06. 读HoldingRegisters程序示例07. 综合示例08. 程序下载09. 附录 01. 概述 Qt中几个常用的串口modbus类 QModbusRtuSerialSlave //modbus串口通信方式下的服务器类 QModbusRtuSerialMaster //串口通信方式下的客户端类

C/C++软件工程师、嵌入式软件工程师、物联网研发工程师、C/C++讲师、物联网讲师、嵌入式讲师、鸿蒙讲师---欢迎大家一起交流(私信添加博主微信) 6353

QT 串口通信详解

1、前言

lml521lml927的博客 7032

PySide6 vs PyQt6:新手如何根据Python版本选择GUI库?附版本兼容性测试

本文针对Python GUI开发新手,详细对比了PySide6与PyQt6的核心差异,并提供了基于Python 3.8至3.12等不同版本的兼容性实测数据与选择建议。文章重点分析了版本选择策略,帮助开发者根据自身Python环境、项目需求(如与matplotlib集成)及许可证考量,做出最合适的决策,并附有安装验证与避坑指南。

weixin_29094539的博客 703

Qt modbus使用详解

不讲理论,只讲应用。看完这篇就能用起来,爽不爽!!! 一、Modbus协议通信过程 1.1 主机对从机写数据操作(0x06) 这个功能的目的是:实现主机对从机 寄存器 的写入操作。 注意:是 主机 对 从机 发送数据的示例: 01 06 00 01 00 17 9804 相应字节的意义: 从机地址 功能号 数据地址 数据 ...

kissgoodbye2012的博客 1万+

计组头哥实验 实验三 MIPS寄存器实验

了解 MIPS 寄存器文件基本概念,进一步熟悉多路选择器、译码器、解复用器等 Logisim 组件的使用,并利用相关组件构建 MIPS 寄存器文件。

gdz0007的博客 1万+

【Qt】modbus之串口模式写操作

00. 目录 文章目录00. 目录01. 概述02. 开发环境03. 写Coils程序示例04. 写HoldingRegisters程序示例05. 综合示例(未实现)06. 程序下载07. 附录 01. 概述 Qt中几个常用的串口modbus类 QModbusRtuSerialSlave //modbus串口通信方式下的服务器类 QModbusRtuSerialMaster //串口通信方式下的客户端类 QModbusServer // QModbusSer

C/C++软件工程师、嵌入式软件工程师、物联网研发工程师、C/C++讲师、物联网讲师、嵌入式讲师、鸿蒙讲师---欢迎大家一起交流(私信添加博主微信) 4855

黑猫带你学eMMC协议第1篇:全网最全emmc协议中文详讲,这份学习框架图,你值得拥有!!!(持续更新中...)

黑猫带你学eMMC协议第7篇:全网最全emmc写保护详解(write protect) 黑猫带你学eMMC协议第8篇:emmc可靠写详解(Write Reliability) 黑猫带你学eMMC协议第9篇:emmc的分区配置(partitioning) 黑猫带你学eMMC协议第10篇:eMMC命令队列详解(CMDQ) 黑猫带你学eMMC协议第11篇:eMMC擦除详解(erase/trim/discard/sanitize/secure erase/secure trim…) 黑猫带你学eMMC协议第12篇:

黑猫奥利奥的博客 2万+

生成EtherCAT从站XML图片信息方法

详细介绍了EtherCAT从站XML文件中图片元素的生成方法。

kevin1499的博客 2130

Qt6教程之三(15) Modbus通信

本篇博客主要介绍Modbus通信!

让每一个想学习编程的人,都能学会,都能看懂,看了都有收获! 1万+

【WRF模拟】如何查看 WPS 的输入静态地理数据(二进制格式)?

如何查看 WPS 的输入静态地理数据(二进制格式)?

WW、forever的博客 633

【Qt Modbus通信】libmodbus实现modbus的主机功能/从机功能 源码分享

【Qt Modbus通信】基于libmodbus库实现的运行在子线程中的modbus主从机 (RTU模式) 项目源码分享 modbus调试工具分享 QModbus 项目源码

qq_37373742的博客 1万+

【100%通过率】华为OD机试真题 Python 实现【最多组合直角三角形个数】【2023 Q1 | 100分】

有N条线段,长度分别为a[1]-a[n]。 现要求你计算这N条线段最多可以组合成几个直角三角形。 每条线段只能使用一次,每个三角形包含三条线段。

MISAYAONE的博客 1万+

PCIe协议之 Equalization篇 之 谈谈几种模式

对于两端有能力最高支持 32 GT/s 及以上速率的设备,如果把目标速度设置为 8 GT/s 或 16 GT/s 速率,是不建议采用 Bypass-Equalization-to-Highest-Rate 模式的,即便采用了,也不会针对 8 GT/s 或 16 GT/s 的目标速率进行 EQ。对于支持 32 GT/s 及以上速率的设备,其可能根本无需工作在 8 GT/s 或 16 GT/s 速率,这时再针对 8 GT/s 或 16 GT/s 速率进行 EQ,多少有点浪费。

那么菜的博客 567

QT modbus类简介及串口modbus例程源码分析

1.Qt中几个常用的串口modbus类 QModbusRtuSerialSlave         //modbus串口通信方式下的服务器类 QModbusRtuSerialMaster      //串口通信方式下的客户端类 QModbusServer                     // QModbusServer类接收和处理modbus的请求。 QModbusDataUnit

maowendi的专栏 5万+

【Unity实战篇】| 游戏轮播图效果,多种实现思路及完整教程

在众多游戏的主界面、商城、图鉴或关卡选择界面中,我们常常能看到轮播图的身影。 它以动态、直观的方式展示游戏角色、皮肤、成就或场景,不仅极大地提升了界面的美观度和交互性,还能高效地引导玩家聚焦于核心内容。 本篇文章将从零开始,一步步在Unity中构建一个功能完备、性能优良的游戏轮播图。 使用UGUI系统,通过代码驱动,实现包括自动轮播、手动拖拽、分页指示器、无限循环等核心功能。 无论是UI新手还是希望优化现有方案的开发者,这篇文章都将为你提供清晰的思路和完整的解决方案。

努力前行,总会成为自己心中的那道光 4万+

Qt编写Modbus从机程序

上一个网文我们使用MODSCAN32软件和串口助手调试了Modbus协议,我们之前还分享过使用Qt编写自己的串口助手,今天我们在上次分享的串口助手的源码基础上,使用Qt编写一个Modbus从机程序,让其与MODSCAN32软件实现数据交互。 实现目标 熟悉Modbus协议0x03和0x06功能码 熟悉QTableView控件的使用 Qt编写的Modbus从设备与ModScan32软件进行数据交互 结果展示 改变QTableView控件中某一个单元格的值 MODSCAN32软件实时获得

程序员小哈的专栏 4169

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: QT中的多线程使用
下一篇: JSON格式讲解
PJ...
博客等级 码龄5年 412粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值