【问题标题】:Why QModbusClient does not read data after open statement?为什么 QModbusClient 在 open 语句后不读取数据?
【发布时间】:2020-11-25 18:21:30
【问题描述】:

我正在尝试运行一个简单的 Modbus,但我遇到了命令序列问题。

我首先想到的是,我不能在一个函数中运行多个函数。如果我这样做,那么它看起来像是建立了连接,但它失败了。如果我创建 2 个按钮(“连接”、“读取”)并单击第一个连接然后读取,则连接成功并且我能够读取响应。

那么如何更改代码,使其连接到 TCP Modbus,读取一些数据,然后使用一个功能/按钮关闭连接?

这是我的代码示例:

在 modbusmaster.hpp 文件中:

#ifndef MODBUSMASTER_HPP
#define MODBUSMASTER_HPP
#include <QMainWindow>
#include <QModbusTcpClient>
#include <QModbusDevice>
#include <QModbusDataUnit>
#include <QDebug>
#include <QUrl>

class QModbusClient;

class ModbusMaster : public QMainWindow
{
    Q_OBJECT
public:
    explicit ModbusMaster(QWidget *parent = nullptr);

    QModbusClient *_modbus = nullptr;
    QModbusClient *modbusDevice = nullptr;
    bool open(QString host, int port);
    bool read(QModbusDataUnit::RegisterType type, int startAddress, quint16 count);
    void readReady();

signals:

};

#endif // MODBUSMASTER_HPP

在 modbusmaster.cpp 文件中:

#include "modbusmaster.hpp"

ModbusMaster::ModbusMaster(QWidget *parent) : QMainWindow(parent)
{
}

bool ModbusMaster::open(QString host, int port)
{
    if (_modbus) {
        _modbus->disconnectDevice();
        delete _modbus;
        _modbus = nullptr;
    }
    _modbus = new QModbusTcpClient(this);

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

    if(!_modbus) {
        qDebug() << "Could not create Modbus Client.";
    } else {
        qDebug() << "Modbus Client is created.";
    }

    if (_modbus->state() != QModbusDevice::ConnectedState) {
        _modbus->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
        _modbus->setConnectionParameter(QModbusDevice::NetworkAddressParameter, host);
        _modbus->setTimeout(1000);
        _modbus->setNumberOfRetries(3);

        if (!_modbus->connectDevice()) {
            qDebug() << "Connect failed: " << _modbus->errorString();
        } else {
            qDebug() << "Modbus Client is Connected";
            return true;
        }
    }
    return false;
}

bool ModbusMaster::read(QModbusDataUnit::RegisterType type, int startAddress, quint16 count)
{
    if (!_modbus) {
        qDebug() << "!_modbus";
        return false;
    }

    if (_modbus->state() != QModbusDevice::ConnectedState){
        qDebug() << "Modbus Client is not Connected in read section";
        return false;
    }

    QModbusDataUnit req(type, startAddress, count);
    if (auto *reply = _modbus->sendReadRequest(req, 1))
    {
        qDebug() << "auto *reply = _modbus->sendReadRequest(req, 1)";
        if (!reply->isFinished())
            connect(reply, &QModbusReply::finished, this, &ModbusMaster::readReady);
        else
            delete reply;
        return true;
    }
    return false;
}

void ModbusMaster::readReady()
{
    auto reply = qobject_cast<QModbusReply *>(sender());
    if (!reply) return;
    reply->deleteLater();

    if (reply->error() == QModbusDevice::NoError)
    {
        qDebug() << reply;
    }
    else if (reply->error() == QModbusDevice::ProtocolError)
    {
        qDebug() << QString("Read response error: %1 (Mobus exception: 0x%2)").
                                    arg(reply->errorString()).
                                    arg(reply->rawResult().exceptionCode(), -1, 16);
    } else {
        qDebug() << QString("Read response error: %1 (code: 0x%2)").
                                    arg(reply->errorString()).
                                    arg(reply->error(), -1, 16);
    }
}

在 mainwindow.cpp 文件中:

#include "modbusmaster.hpp"
.......
void mainwindow::on_button_clicked()
{
    ModbusMaster test;
    test.open("172.19.1.54", 54);
    test.read(QModbusDataUnit::HoldingRegisters, 0, 10);

}
.......

“on_button_clicked”不起作用。它只显示 qDebug() 结果:

Modbus Client is created.
Modbus Client is Connected
Modbus Client is not Connected in read section

如果我使用 2 个按钮,一个用于 test.open,另一个用于 test.read,那么没关系。

那么我在这里错过了什么?

【问题讨论】:

  • 应更新问题以包含所需行为、特定问题或错误以及重现问题所需的最短代码。
  • 这里的问题是:如何连接到Modbus,读取一些数据并一键关闭连接?上面的代码已经非常简短,以显示我正在尝试做的事情,但足以重现问题。我真的希望有人能够帮助我。在搜索和了解更多关于 Modbus 和 Qt ist 之后,我可能会遇到线程问题?
  • 上面的代码已经很短了你在任何地方都使用modbusDevice吗?
  • 您可能还想使用QModbusDevice::stateChanged
  • @scopchanov 你的意思是这一行:QModbusClient *modbusDevice = nullptr; ??没有,忘记删了。将检查 stateChanged 部分。我真的很想念一个很好的文档,里面有简单的例子和​​ QModbus TCP 东西的声明......而不仅仅是 Qt-Welcome 区域中的一个“巨大”示例

标签: c++ qt modbus-tcp


【解决方案1】:

原因

许多人没有意识到,沟通需要时间。因此,在您的情况下,您打开设备并立即发起读取请求,但该请求失败,因为设备尚未打开(因为它需要时间,就像其他任何事情一样)。

解决方案

在 GUI 应用程序中,当代码对事件做出反应时,这可能是最好的,而不是尝试线性执行所有内容。这就是信号和槽发挥作用的地方。

考虑以下工作流程:

创建QModbusDevice 时,您还将其信号(例如stateChangederrorOccurred)连接到代码中的插槽(例如MainWindow::onModbusStateChangedMainWindow::onModbusErrorOccurred)。这些应该被认为是回调函数,当相应的事件发生时执行:连接状态改变,接收数据,发送数据,发生错误。

通过这种方式,您将确切地知道什么时候该做什么。

示例

这是我为您准备的示例代码,向您展示如何解决该问题:

MainWindow.h

...
private:
    QModbusClient *m_modbus;
...
private slots:
    void onModbusStateChanged(QModbusDevice::State state);
...

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    m_modbus(new QModbusClient(this))
{
    ...
    connect(m_modbus, &QModbusClient::stateChanged, this, MainWindow::onModbusStateChanged);
    ...
}

要在设备连接后立即读取数据,插槽可能如下所示:

void MainWindow::onModbusStateChanged(QModbusDevice::State state)
{
    switch (state) {
        ...
        case QModbusDevice::ConnectedState:
            m_modbus->read(QModbusDataUnit::HoldingRegisters, 0, 10);
        break;
        ...
    }
}

单击按钮即可启动连接。在你的情况下:

void MainWindow::on_button_clicked()
{
    m_modbus->connectDevice();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-06
    • 1970-01-01
    • 2022-01-02
    相关资源
    最近更新 更多