Qtmodbus之TCP模式写操作

Posted 沧海一笑-dj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qtmodbus之TCP模式写操作相关的知识,希望对你有一定的参考价值。

00. 目录

01. 概述

Qt中几个常用的串口modbus类

QModbusRtuSerialSlave       //modbus串口通信方式下的服务器类
QModbusRtuSerialMaster      //串口通信方式下的客户端类
QModbusServer               // QModbusServer类接收和处理modbus的请求。
QModbusDataUnit             //存储接收和发送数据的类,数据类型为1bit和16bit
QModbusReply                //客户端访问服务器后得到的回复(如客户端读服务器数据时包含数据信息)

02. 开发环境

Windows系统:Windows10

Qt版本:Qt5.15或者Qt6

Pro配置文件如下

QT       += core gui serialbus serialport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \\
    main.cpp \\
    widget.cpp

HEADERS += \\
    widget.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

03. 读Coils程序示例

widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

//前向声明
class QModbusClient;
class QModbusReply;


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;

    QModbusClient *modbusDevice = nullptr;


private slots:
    void onReadReady();
    void onModbusStateChanged(int state);
    void on_btnConnect_clicked();
    void on_btnCoil_clicked();
    void on_btnDiscreteInputs_clicked();
    void on_btnInputRegisters_clicked();
    void on_btnHoldingRegisters_clicked();
    void on_btnCoil_2_clicked();
    void on_btnHoldingRegisters_2_clicked();
};
#endif // WIDGET_H

widget.cpp文件

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QModbusTcpClient>


//构造函数
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //1. 创建QModbusDevice对象
    modbusDevice = new QModbusTcpClient(this);

    //禁用所有的读操作
    ui->btnCoil->setEnabled(false);
    ui->btnDiscreteInputs->setEnabled(false);
    ui->btnHoldingRegisters->setEnabled(false);
    ui->btnInputRegisters->setEnabled(false);

    //禁用所有的写操作
    ui->btnCoil_2->setEnabled(false);
    ui->btnHoldingRegisters_2->setEnabled(false);

    connect(modbusDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
        qDebug() << "new Error: " << modbusDevice->errorString();
    });

    if (nullptr == modbusDevice)
    {
        qDebug() << "Cannot Create Modbus Client";
    }
    else
    {
        connect(modbusDevice, &QModbusClient::stateChanged,
                this, &Widget::onModbusStateChanged);
    }


}

//析构函数
Widget::~Widget()
{
    if (modbusDevice)
    {
        modbusDevice->disconnectDevice();
    }

    delete modbusDevice;

    delete ui;
}


void Widget::onReadReady()
{
    auto reply = qobject_cast<QModbusReply*>(sender());
    if (nullptr == reply)
    {
        return;
    }

    //判断是否出错
    if (reply->error() == QModbusDevice::NoError)
    {
        //读取响应数据
        const QModbusDataUnit responseData = reply->result();

        qDebug() << "读到数据为:" << responseData.values();

    }
    else if (reply->error() == QModbusDevice::ProtocolError)
    {
        qDebug() << "Read response Protocol error: " << reply->errorString();
    }
    else
    {
        qDebug() << "Read response Error: " << reply->errorString();
    }


    //删除reply
    reply->deleteLater();
}


void Widget::onModbusStateChanged(int state)
{
    //判断Modbus设备连接是否处于连接状态
    if (state == QModbusDevice::UnconnectedState)
    {
        qDebug() << "TCP Client连接到Server 未连接";
        ui->btnConnect->setText(tr("连接"));

        ui->btnCoil->setEnabled(false);
        ui->btnDiscreteInputs->setEnabled(false);
        ui->btnHoldingRegisters->setEnabled(false);
        ui->btnInputRegisters->setEnabled(false);

        ui->btnCoil_2->setEnabled(false);
        ui->btnHoldingRegisters_2->setEnabled(false);

    }
    else if (state == QModbusDevice::ConnectingState)
    {
        qDebug() << "TCP Client正在连接Server";
    }
    else if (state == QModbusDevice::ConnectedState)
    {
        qDebug() << "TCP Client已经连接到Server";
        ui->btnConnect->setText(tr("断开连接"));

        ui->btnCoil->setEnabled(true);
        ui->btnDiscreteInputs->setEnabled(true);
        ui->btnHoldingRegisters->setEnabled(true);
        ui->btnInputRegisters->setEnabled(true);

        ui->btnCoil_2->setEnabled(true);
        ui->btnHoldingRegisters_2->setEnabled(true);


    }
    else if (state == QModbusDevice::ClosingState)
    {
        qDebug() << "设备已经被关闭";
    }
}

//连接按钮槽函数
void Widget::on_btnConnect_clicked()
{
    if (!modbusDevice)
    {
        return;
    }

    if (modbusDevice->state() != QModbusDevice::ConnectedState)
    {
        modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "127.0.0.1");
        modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, 10086);

        //设置超时时间
        modbusDevice->setTimeout(1000); //1秒
        //设置失败重试次数
        modbusDevice->setNumberOfRetries(3);

        //连接到服务端
        bool ok = modbusDevice->connectDevice();
        if (!ok)
        {
            qDebug() << "modbusDevice->connectDevice failed";
        }
    }
    else
    {
        //断开连接
        modbusDevice->disconnectDevice();
        ui->btnConnect->setText(tr("连接"));

        ui->btnCoil->setEnabled(false);
        ui->btnDiscreteInputs->setEnabled(false);
        ui->btnHoldingRegisters->setEnabled(false);
        ui->btnInputRegisters->setEnabled(false);
        ui->btnCoil_2->setEnabled(false);
        ui->btnHoldingRegisters_2->setEnabled(false);
    }

}

//读线圈
void Widget::on_btnCoil_clicked()
{
    //QModbusDataUnit::Coils 从地址0开始读取10个线圈值
    QModbusDataUnit data(QModbusDataUnit::Coils, 0, 10);

    auto reply = modbusDevice->sendReadRequest(data, 0x1);
    if (nullptr == reply)
    {
        qDebug() << "发送请求数据失败: " << modbusDevice->errorString();
    }
    else
    {
        if (!reply->isFinished())
        {
            connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);
        }
        else
        {
            //broadcast replies return immediately
            delete reply;
        }
    }
}

//读离散输入
void Widget::on_btnDiscreteInputs_clicked()
{
    //QModbusDataUnit::DiscreteInputs 从地址0开始读取10个离散输入值
    QModbusDataUnit data(QModbusDataUnit::DiscreteInputs, 0, 10);

    auto reply = modbusDevice->sendReadRequest(data, 0x1);
    if (nullptr == reply)
    {
        qDebug() << "发送请求数据失败: " << modbusDevice->errorString();
    }
    else
    {
        if (!reply->isFinished())
        {
            connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);
        }
        else
        {
            //broadcast replies return immediately
            delete reply;
        }
    }
}

//读输入寄存器
void Widget::on_btnInputRegisters_clicked()
{
    //QModbusDataUnit::InputRegisters 从地址0开始读取10个输入寄存器的值
    QModbusDataUnit data(QModbusDataUnit::InputRegisters, 0, 10);

    auto reply = modbusDevice->sendReadRequest(data, 0x1);
    if (nullptr == reply)
    {
        qDebug() << "发送请求数据失败: " << modbusDevice->errorString();
    }
    else
    {
        if (!reply->isFinished())
        {
            connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);
        }
        else
        {
            //broadcast replies return immediately
            delete reply;
        }
    }
}

//读保持寄存器
void Widget::on_btnHoldingRegisters_clicked()
{
    //从地址0开始读取10个保持寄存器的值
    QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, 0, 10);

    auto reply = modbusDevice->sendReadRequest(data, 0x1);
    if (nullptr == reply)
    {
        qDebug() << "发送请求数据失败: " << modbusDevice->errorString();
    }
    else
    {
        if (!reply->isFinished())
        {
            connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);
        }
        else
        {
            //broadcast replies return immediately
            delete reply;
        }
    }
}

//写线圈
void Widget::on_btnCoil_2_clicked()
{
    //从地址0开始写10个线圈的值
    QModbusDataUnit writeData(QModbusDataUnit::Coils, 0, 10);
    for (int i = 0; i < writeData.valueCount(); i++)
    {
        writeData.setValue(i, (i * i) % 2);
    }

    qDebug() << "发送的数据为: " << writeData.values();

    QModbusReply* reply = modbusDevice->sendWriteRequest(writeData, 1);
    if (reply)
    {
        if (!reply->isFinished())
        {
            //接收响应信息
            connect(reply, &QModbusReply::finished, this, [this, reply](){
                if (reply->error() == QModbusDevice::ProtocolError)
                {
                    //接收到的响应信息是协议错误
                    qDebug() << "写入数据错误:" << reply->errorString();
                }
                else if (reply->error() != QModbusDevice::NoError)
                {
                    //接收到的响应消息是其它错误
                    qDebug() << "写入数据错误: " << reply->errorString();
                }
                else
                {
                    //接收到的消息没有错误 一般没有必要解析响应消息
                    const QModbusDataUnit data = reply->result();

                    qDebug() << "消息数据个数:" << data.valueCount() << " :" << data.values();

                }

                reply->deleteLater();
            });
        }
        else
        {
            //发送没有响应数据
            //broadcast replies return immediately
            reply->deleteLater();
        }
    }
    else
    {
        qDebug() << "sendWriteRequest Error: " << reply->errorString();
    }
}


//写保持寄存器
void Widget::on_btnHoldingRegisters_2_clicked()
{


}

执行结果

16:02:56: Starting D:\\ProgramData\\Qt\\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\\debug\\Test1.exe ...
TCP Client正在连接Server
TCP Client已经连接到Server
发送的数据为:  QVector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
消息数据个数: 10  : QVector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
设备已经被关闭
TCP Client连接到Server 未连接
16:03:17: D:\\ProgramData\\Qt\\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\\debug\\Test1.exe exited with code 0

04. 读HoldingRegisters程序示例

widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

//前向声明
class QModbusClient;
class QModbusReply;


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;

    QModbusClient *modbusDevice = nullptr;


private slots:
    void onReadReady();
    void onModbusStateChanged(int state);
    void on_btnConnect_clicked();
    void on_btnCoil_clicked();
    void on_btnDiscreteInputs_clicked();
    void on_btnInputRegisters_clicked();
    void on_btnHoldingRegisters_clicked();
    void on_btnCoil_2_clicked();
    void on_btnHoldingRegisters_2_clicked();
};
#endif // WIDGET_H

widget.cpp文件

//写保持寄存器
void Widget::on_btnHoldingRegisters_2_clicked()
{
    QModbusDataUnit writeData(QModbusDataUnit::HoldingRegisters, 0, 10);
    for (int i = 0; i < writeData.valueCount(); i++)
    {
        writeData.setValue(i, i * i);
    }

    qDebug() << "发送的数据为: " << writeData.values()以上是关于Qtmodbus之TCP模式写操作的主要内容,如果未能解决你的问题,请参考以下文章

Qtmodbus之串口模式写操作

Qtmodbus之串口模式读操作

Python 之 Socket编程(TCP/UDP)

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

我是如何学习写一个操作系统:操作系统的启动之保护模式

网络骇客入门之TCP并发网页服务器