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

一、前言

        前面有文章写过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串口数据接收

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值