当前位置:   article > 正文

利用Qt5已有QModbus相关类实现ModbusTcpServer总结_qmodbustcpserver

qmodbustcpserver

利用Qt5已有QModbus相关类实现ModbusTcpServer总结



在疫情环境下催生出了很多的无人或者减少人员接触的项目,比如无人智慧餐厅项目中的无人送餐项目,主要是由送餐小车和一个中控屏和部分协助发餐的设备组成,由于餐厅一般的范围不会很大,考虑到Wi-Fi通信可能比较麻烦,我们前期组网协议使用的是 zigbee,这样的话小车可以无网络运行且待电能力较高,zigbee无线通信方案也比较较成熟,有一些现成的zigbee串口通信芯片,硬件和软件实现都方便一些。随着版本的迭代,有一些新的需求,我们需要接入一些第三方的设备,这些设备可能是 PLC设备,而和这些设备通信的时候可能需要用到 Modbus协议,而中控屏恰好是使用Qt开发的,因此我们借助于Qt5自带的一些功能来实现Modbus-TCP服务端和客户端做一下实验。

1、Modbus/TCP协议简单了解

可以查看这篇文章:https://blog.csdn.net/weixin_39510813/article/details/115027911?spm=1001.2014.3001.5501

2、Qt5 Modbus客户机(master主)服务器(slave从)实现示例分析学习

(1)、搜索Modbus

打开Qt creator后在示例中搜索Modbus,可以看到Modbus主/从的两个示例。

在这里插入图片描述

(2)、运行后结果

我们将master和slave都运行起来,可以看到Modbus\TCP协议的Port是502,本地使用的127.0.0.1的IP地址,然后我们点击connect开始server,下面的勾选是输入和接收输出的回调,右侧客户端的Holding Registers输入要发送的值,左侧服务端我们将各个字节勾选上,然后左侧Input Registers的各个字节输入要发送的内容,之后点击客户端的Read-Write进行读写测试即可:

在这里插入图片描述

(3)、slave代码分析

我们通过tree /f查看文件树:

C:\Qt\Qt5.9.1\Examples\Qt-5.9.1\serialbus\modbus\slave>tree /f
文件夹 PATH 列表
卷序列号为 00000087 0856:6C30
C:.
│  main.cpp
│  mainwindow.cpp
│  mainwindow.h
│  mainwindow.ui
│  settingsdialog.cpp
│  settingsdialog.h
│  settingsdialog.ui
│  slave.pro
│  slave.pro.user
│  slave.qrc
│
├─doc
│  ├─images
│  │      modbusserver.png
│  │
│  └─src
│          modbusslave.qdoc
│
└─images
        application-exit.png
        connect.png
        disconnect.png
        settings.png
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

可以看出来基本就是main、mainwindow、settingsdialog(settingdialog是对串口属性的设置,所以这里也不用看了)相关的内容,所以我们只需要看两个cpp文件就差不多可以掌握Qt5关于Modbus/TCP的接口使用了,此外可能就是检查一下.pro里面如何添加modbus相关的模块到我们的项目中。

main.cpp(注意一下如何获取modbus的日志即可,其它的没有啥特别的):

#include "mainwindow.h"

#include <QApplication>
#include <QLoggingCategory>

int main(int argc, char *argv[])
{
    // TODO uncomment this line before release
    // right now we always need it
    QLoggingCategory::setFilterRules(QStringLiteral("qt.modbus* = true"));
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

mainwindow.cpp:

初始化->建立连接:通看的话基本上就是initActions->on_connectButton_clicked来确认进行modbus类型选择以及判断是否已连接,如果是modbus/tcp的话则设置端口和url即可,一般来说端口就是502,url则需要根据我们局域网配置的url来定。

读写:setRegister、updateWidgets两个槽函数中有读写的接口,在on_connectType_currentIndexChanged方法中我们点击connect建立连接后就可以对server设置读取的信号槽连接。

#include "mainwindow.h"
#include "settingsdialog.h"
#include "ui_mainwindow.h"

#include <QModbusRtuSerialSlave>
#include <QModbusTcpServer>
#include <QRegularExpression>
#include <QStatusBar>
#include <QUrl>

enum ModbusConnection {
    Serial,
    Tcp
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , modbusDevice(nullptr)
{
    ui->setupUi(this);
    setupWidgetContainers();

    ui->connectType->setCurrentIndex(0);
    on_connectType_currentIndexChanged(0);

    m_settingsDialog = new SettingsDialog(this);
    initActions();
}

MainWindow::~MainWindow()
{
    if (modbusDevice)
        modbusDevice->disconnectDevice();
    delete modbusDevice;

    delete ui;
}

void MainWindow::initActions()
{
    ui->actionConnect->setEnabled(true);
    ui->actionDisconnect->setEnabled(false);
    ui->actionExit->setEnabled(true);
    ui->actionOptions->setEnabled(true);

    connect(ui->actionConnect, &QAction::triggered,
            this, &MainWindow::on_connectButton_clicked);
    connect(ui->actionDisconnect, &QAction::triggered,
            this, &MainWindow::on_connectButton_clicked);

    connect(ui->actionExit, &QAction::triggered, this, &QMainWindow::close);
    connect(ui->actionOptions, &QAction::triggered, m_settingsDialog, &QDialog::show);
}

void MainWindow::on_connectType_currentIndexChanged(int index)
{
    if (modbusDevice) {
        modbusDevice->disconnect();
        delete modbusDevice;
        modbusDevice = nullptr;
    }

    ModbusConnection type = static_cast<ModbusConnection> (index);
    if (type == Serial) {
        modbusDevice = new QModbusRtuSerialSlave(this);
    } else if (type == Tcp) {
        modbusDevice = new QModbusTcpServer(this);
        if (ui->portEdit->text().isEmpty())
            ui->portEdit->setText(QLatin1Literal("127.0.0.1:502"));
    }
    ui->listenOnlyBox->setEnabled(type == Serial);

    if (!modbusDevice) {
        ui->connectButton->setDisabled(true);
        if (type == Serial)
            statusBar()->showMessage(tr("Could not create Modbus slave."), 5000);
        else
            statusBar()->showMessage(tr("Could not create Modbus server."), 5000);
    } else {
        QModbusDataUnitMap reg;
        reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
        reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
        reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
        reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });

        modbusDevice->setMap(reg);

        connect(modbusDevice, &QModbusServer::dataWritten,
                this, &MainWindow::updateWidgets);
        connect(modbusDevice, &QModbusServer::stateChanged,
                this, &MainWindow::onStateChanged);
        connect(modbusDevice, &QModbusServer::errorOccurred,
                this, &MainWindow::handleDeviceError);

        connect(ui->listenOnlyBox, &QCheckBox::toggled, this, [this](bool toggled) {
            if (modbusDevice)
                modbusDevice->setValue(QModbusServer::ListenOnlyMode, toggled);
        });
        emit ui->listenOnlyBox->toggled(ui->listenOnlyBox->isChecked());
        connect(ui->setBusyBox, &QCheckBox::toggled, this, [this](bool toggled) {
            if (modbusDevice)
                modbusDevice->setValue(QModbusServer::DeviceBusy, toggled ? 0xffff : 0x0000);
        });
        emit ui->setBusyBox->toggled(ui->setBusyBox->isChecked());

        setupDeviceData();
    }
}

void MainWindow::handleDeviceError(QModbusDevice::Error newError)
{
    if (newError == QModbusDevice::NoError || !modbusDevice)
        return;

    statusBar()->showMessage(modbusDevice->errorString(), 5000);
}

void MainWindow::on_connectButton_clicked()
{
    bool intendToConnect = (modbusDevice->state() == QModbusDevice::UnconnectedState);

    statusBar()->clearMessage();

    if (intendToConnect) {
        if (static_cast<ModbusConnection> (ui->connectType->currentIndex()) == Serial) {
            modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
                ui->portEdit->text());
            modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
                m_settingsDialog->settings().parity);
            modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
                m_settingsDialog->settings().baud);
            modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
                m_settingsDialog->settings().dataBits);
            modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
                m_settingsDialog->settings().stopBits);
        } else {
            const QUrl url = QUrl::fromUserInput(ui->portEdit->text());
            modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
            modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());
        }
        modbusDevice->setServerAddress(ui->serverEdit->text().toInt());
        if (!modbusDevice->connectDevice()) {
            statusBar()->showMessage(tr("Connect failed: ") + modbusDevice->errorString(), 5000);
        } else {
            ui->actionConnect->setEnabled(false);
            ui->actionDisconnect->setEnabled(true);
        }
    } else {
        modbusDevice->disconnectDevice();
        ui->actionConnect->setEnabled(true);
        ui->actionDisconnect->setEnabled(false);
    }
}

void MainWindow::onStateChanged(int state)
{
    bool connected = (state != QModbusDevice::UnconnectedState);
    ui->actionConnect->setEnabled(!connected);
    ui->actionDisconnect->setEnabled(connected);

    if (state == QModbusDevice::UnconnectedState)
        ui->connectButton->setText(tr("Connect"));
    else if (state == QModbusDevice::ConnectedState)
        ui->connectButton->setText(tr("Disconnect"));
}

void MainWindow::coilChanged(int id)
{
    QAbstractButton *button = coilButtons.button(id);
    bitChanged(id, QModbusDataUnit::Coils, button->isChecked());
}

void MainWindow::discreteInputChanged(int id)
{
    QAbstractButton *button = discreteButtons.button(id);
    bitChanged(id, QModbusDataUnit::DiscreteInputs, button->isChecked());
}

void MainWindow::bitChanged(int id, QModbusDataUnit::RegisterType table, bool value)
{
    if (!modbusDevice)
        return;

    if (!modbusDevice->setData(table, id, value))
        statusBar()->showMessage(tr("Could not set data: ") + modbusDevice->errorString(), 5000);
}

void MainWindow::setRegister(const QString &value)
{
    if (!modbusDevice)
        return;

    const QString objectName = QObject::sender()->objectName();
    if (registers.contains(objectName)) {
        bool ok = true;
        const int id = QObject::sender()->property("ID").toInt();
        if (objectName.startsWith(QStringLiteral("inReg")))
            ok = modbusDevice->setData(QModbusDataUnit::InputRegisters, id, value.toInt(&ok, 16));
        else if (objectName.startsWith(QStringLiteral("holdReg")))
            ok = modbusDevice->setData(QModbusDataUnit::HoldingRegisters, id, value.toInt(&ok, 16));

        if (!ok)
            statusBar()->showMessage(tr("Could not set register: ") + modbusDevice->errorString(),
                                     5000);
    }
}

void MainWindow::updateWidgets(QModbusDataUnit::RegisterType table, int address, int size)
{
    for (int i = 0; i < size; ++i) {
        quint16 value;
        QString text;
        switch (table) {
        case QModbusDataUnit::Coils:
            modbusDevice->data(QModbusDataUnit::Coils, address + i, &value);
            coilButtons.button(address + i)->setChecked(value);
            break;
        case QModbusDataUnit::HoldingRegisters:
            modbusDevice->data(QModbusDataUnit::HoldingRegisters, address + i, &value);
            registers.value(QStringLiteral("holdReg_%1").arg(address + i))->setText(text
                .setNum(value, 16));
            break;
        default:
            break;
        }
    }
}

// -- private

void MainWindow::setupDeviceData()
{
    if (!modbusDevice)
        return;

    for (int i = 0; i < coilButtons.buttons().count(); ++i)
        modbusDevice->setData(QModbusDataUnit::Coils, i, coilButtons.button(i)->isChecked());

    for (int i = 0; i < discreteButtons.buttons().count(); ++i) {
        modbusDevice->setData(QModbusDataUnit::DiscreteInputs, i,
            discreteButtons.button(i)->isChecked());
    }

    bool ok;
    for (QLineEdit *widget : qAsConst(registers)) {
        if (widget->objectName().startsWith(QStringLiteral("inReg"))) {
            modbusDevice->setData(QModbusDataUnit::InputRegisters, widget->property("ID").toInt(),
                widget->text().toInt(&ok, 16));
        } else if (widget->objectName().startsWith(QStringLiteral("holdReg"))) {
            modbusDevice->setData(QModbusDataUnit::HoldingRegisters, widget->property("ID").toInt(),
                widget->text().toInt(&ok, 16));
        }
    }
}

void MainWindow::setupWidgetContainers()
{
    coilButtons.setExclusive(false);
    discreteButtons.setExclusive(false);

    QRegularExpression regexp(QStringLiteral("coils_(?<ID>\\d+)"));
    const QList<QCheckBox *> coils = findChildren<QCheckBox *>(regexp);
    for (QCheckBox *cbx : coils)
        coilButtons.addButton(cbx, regexp.match(cbx->objectName()).captured("ID").toInt());
    connect(&coilButtons, SIGNAL(buttonClicked(int)), this, SLOT(coilChanged(int)));

    regexp.setPattern(QStringLiteral("disc_(?<ID>\\d+)"));
    const QList<QCheckBox *> discs = findChildren<QCheckBox *>(regexp);
    for (QCheckBox *cbx : discs)
        discreteButtons.addButton(cbx, regexp.match(cbx->objectName()).captured("ID").toInt());
    connect(&discreteButtons, SIGNAL(buttonClicked(int)), this, SLOT(discreteInputChanged(int)));

    regexp.setPattern(QLatin1String("(in|hold)Reg_(?<ID>\\d+)"));
    const QList<QLineEdit *> qle = findChildren<QLineEdit *>(regexp);
    for (QLineEdit *lineEdit : qle) {
        registers.insert(lineEdit->objectName(), lineEdit);
        lineEdit->setProperty("ID", regexp.match(lineEdit->objectName()).captured("ID").toInt());
        lineEdit->setValidator(new QRegExpValidator(QRegExp(QStringLiteral("[0-9a-f]{0,4}"),
            Qt::CaseInsensitive), this));
        connect(lineEdit, &QLineEdit::textChanged, this, &MainWindow::setRegister);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
(4)、master代码分析

同样我们先查看文件树:

C:\Qt\Qt5.9.1\Examples\Qt-5.9.1\serialbus\modbus\master>tree /f
文件夹 PATH 列表
卷序列号为 000000E4 0856:6C30
C:.
│  main.cpp
│  mainwindow.cpp
│  mainwindow.h
│  mainwindow.ui
│  master.pro
│  master.pro.user
│  master.qrc
│  settingsdialog.cpp
│  settingsdialog.h
│  settingsdialog.ui
│  writeregistermodel.cpp
│  writeregistermodel.h
│
├─doc
│  ├─images
│  │      modbusmaster.png
│  │
│  └─src
│          modbusmaster.qdoc
│
└─images
        application-exit.png
        connect.png
        disconnect.png
        settings.png
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

基本和slave的接口类似,主要modbus\tcp相关的操作都是在mainwindow下,settingsdialog还是对串口的设置,writeregistermodel是对QAbstractTableModel的继承和部分接口重写,完成双击输入内容的功能。

建立连接:

modbusDevice = new QModbusTcpClient(this);
if (ui->portEdit->text().isEmpty())
		ui->portEdit->setText(QLatin1Literal("127.0.0.1:502"));

modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());

void MainWindow::on_readWriteButton_clicked()
{
    if (!modbusDevice)
        return;
    ui->readValue->clear();
    statusBar()->clearMessage();

    QModbusDataUnit writeUnit = writeRequest();
    QModbusDataUnit::RegisterType table = writeUnit.registerType();
    for (uint i = 0; i < writeUnit.valueCount(); i++) {
        if (table == QModbusDataUnit::Coils)
            writeUnit.setValue(i, writeModel->m_coils[i + writeUnit.startAddress()]);
        else
            writeUnit.setValue(i, writeModel->m_holdingRegisters[i + writeUnit.startAddress()]);
    }

    if (auto *reply = modbusDevice->sendReadWriteRequest(readRequest(), writeUnit,
        ui->serverEdit->value())) {
        if (!reply->isFinished())
            connect(reply, &QModbusReply::finished, this, &MainWindow::readReady);
        else
            delete reply; // broadcast replies return immediately
    } else {
        statusBar()->showMessage(tr("Read error: ") + modbusDevice->errorString(), 5000);
    }
}

if (modbusDevice)
		modbusDevice->disconnectDevice();
delete modbusDevice;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
(5)、QModbusServer和QModbusClient类了解

打开Assistant,搜索QModbusTcp来查看QModbusTcpClient和QModbusTcpServer相关的内容(首先可以确定的是从Qt 5.8开始支持的):

在这里插入图片描述

下面是所有的实现的方法:

This is the complete list of members for QModbusTcpServer, including inherited members.

enum ConnectionParameter
enum Error
enum Option
enum State
QModbusTcpServer(QObject *)
~QModbusTcpServer()
blockSignals(bool )
childEvent(QChildEvent *)
children() const
close()
close()
connect(const QObject *, const char *, const QObject *, const char *, Qt::ConnectionType )
connect(const QObject *, const QMetaMethod &, const QObject *, const QMetaMethod &, Qt::ConnectionType )
connect(const QObject *, const char *, const char *, Qt::ConnectionType ) const
connect(const QObject *, PointerToMemberFunction , const QObject *, PointerToMemberFunction , Qt::ConnectionType )
connect(const QObject *, PointerToMemberFunction , Functor )
connect(const QObject *, PointerToMemberFunction , const QObject *, Functor , Qt::ConnectionType )
connectDevice() : bool
connectNotify(const QMetaMethod &)
connectionParameter(int ) const : QVariant
customEvent(QEvent *)
d_ptr : 
data(QModbusDataUnit *) const : bool
data(QModbusDataUnit::RegisterType , quint16 , quint16 *) const : bool
dataWritten(QModbusDataUnit::RegisterType , int , int )
deleteLater()
destroyed(QObject *)
disconnect(const QObject *, const char *, const QObject *, const char *)
disconnect(const QObject *, const QMetaMethod &, const QObject *, const QMetaMethod &)
disconnect(const QMetaObject::Connection &)
disconnect(const char *, const QObject *, const char *) const
disconnect(const QObject *, const char *) const
disconnect(const QObject *, PointerToMemberFunction , const QObject *, PointerToMemberFunction )
disconnectDevice()
disconnectNotify(const QMetaMethod &)
dumpObjectInfo() const
dumpObjectTree() const
dynamicPropertyNames() const
error() const : Error
errorOccurred(QModbusDevice::Error )
errorString() const : QString
event(QEvent *)
eventFilter(QObject *, QEvent *)
findChild(const QString &, Qt::FindChildOptions ) const
findChildren(const QString &, Qt::FindChildOptions ) const
findChildren(const QRegExp &, Qt::FindChildOptions ) const
findChildren(const QRegularExpression &, Qt::FindChildOptions ) const
inherits(const char *) const
installEventFilter(QObject *)
isSignalConnected(const QMetaMethod &) const
isWidgetType() const
isWindowType() const
killTimer(int )
metaObject() const
moveToThread(QThread *)
objectName() const
objectNameChanged(const QString &)
open() : bool
open() : bool
parent() const
processPrivateRequest(const QModbusPdu &) : QModbusResponse
processRequest(const QModbusPdu &) : QModbusResponse
processRequest(const QModbusPdu &) : QModbusResponse
processesBroadcast() const : bool
property(const char *) const
readData(QModbusDataUnit *) const : bool
receivers(const char *) const
removeEventFilter(QObject *)
sender() const
senderSignalIndex() const
serverAddress() const : int
setConnectionParameter(int , const QVariant &)
setData(const QModbusDataUnit &) : bool
setData(QModbusDataUnit::RegisterType , quint16 , quint16 ) : bool
setError(const QString &, QModbusDevice::Error )
setMap(const QModbusDataUnitMap &) : bool
setObjectName(const QString &)
setParent(QObject *)
setProperty(const char *, const QVariant &)
setServerAddress(int )
setState(QModbusDevice::State )
setValue(int , const QVariant &) : bool
signalsBlocked() const
startTimer(int , Qt::TimerType )
startTimer(std::chrono::milliseconds , Qt::TimerType )
state() const : State
stateChanged(QModbusDevice::State )
staticMetaObject : 
staticQtMetaObject : 
thread() const
timerEvent(QTimerEvent *)
tr(const char *, const char *, int )
value(int ) const : QVariant
writeData(const QModbusDataUnit &) : bool
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

可以针对性的了解一些方法。

3、实现一个modbus/tcp服务进行测试

基本上对于上位机来说作为modbus/tcp服务器的情况比较多。

.pro中添加:

QT       += core gui sql serialport serialbus
  • 1

主要创建内容和读写操作(结合example和这里的例子):

#ifndef MODBUSSERVER_H
#define MODBUSSERVER_H

#include <QObject>
#include <QModbusServer>
#include <QModbusRtuSerialSlave>
#include <QModbusTcpServer>
#include <QSerialPort>

/*
*
*
*       modbus slave 从站
*
*       modbusSlove_* m_slave = new modbusSlove_(this);
*
*       initModbusSerialSlove()
*
*       connectDevice()
*
*       //寄存器值发生改变,连接这个信号
        void registerData_signal(int address,int value);
*
*/
class ModbusServer : public QObject
{
    Q_OBJECT
public:
    explicit ModbusServer(QObject *parent = nullptr);

    /**
* @projectName   testMyClass
* @brief         初始化串口modbusSlave
* 其他参数 波特率 数据位 校验位 停止位
* @author        SMY
* @date          2019-03-27
*/
    bool initModbusSerialServer(QString portName, qint32 baudRate, QSerialPort::DataBits dataBits,
                         QSerialPort::Parity parity, QSerialPort::StopBits stopBits);
    /**
* @projectName   testMyClass
* @brief         初始化网口modbusSlave
* ip地址,端口号
* @author        SMY
* @date          2019-03-27
*/
    bool initModbusNetworkServer(QString address,int port);

    /**
* @projectName   testMyClass
* @brief         连接设备
* @author        SMY
* @date          2019-03-27
*/
    bool connectDevice();
    /**
* @projectName   testMyClass
* @brief         网口还是串口连接
* @author        SMY
* @date          2019-03-26
*/
    enum modbusConnection
    {
        Serial,
        Tcp
    };

signals:
    //寄存器值发生改变
    void registerData_signal(int address,int value);
    //发生错误
    void error_signal(QString errorString);
    /*state :1 connect ,0:unconnect
    *状态发生改变
    */
    void stateChanged_signal(int state);
public slots:
private slots:
    /**
* @projectName   testMyClass
* @brief         更新寄存器数据
* @author        SMY
* @date          2019-03-26
*/
    void updateData(QModbusDataUnit::RegisterType table, int address, int size);
    /**
* @projectName   testMyClass
* @brief         device error
* @author        SMY
* @date          2019-03-27
*/
    void handleDeviceError(QModbusDevice::Error newError);
    /**
* @projectName   testMyClass
* @brief         连接状态改变
* @author        SMY
* @date          2019-03-27
*/
    void onStateChanged(int state);
private:
    modbusConnection m_mode;
    QModbusServer* modbusServer;
};

#endif // MODBUSSERVER__H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
#include "modbusserver.h"
#include <QDebug>

ModbusServer::ModbusServer(QObject *parent) : QObject(parent)
{

}

bool ModbusServer::initModbusSerialServer(QString portName, qint32 baudRate, QSerialPort::DataBits dataBits,
                                   QSerialPort::Parity parity,
                                   QSerialPort::StopBits stopBits)
{
    //串口

    modbusServer = new QModbusRtuSerialSlave(this);

    m_mode = Serial;

    if(!modbusServer)
    {
        qDebug()<<"could not create modbus slave";
        return 0;
    }

    QModbusDataUnitMap reg;
    reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
    reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
    reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
    reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });

    modbusServer->setMap(reg);

    modbusServer->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
                                    portName);
    modbusServer->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
                                    baudRate);
    modbusServer->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
                                    dataBits);
    modbusServer->setConnectionParameter(QModbusDevice::SerialParityParameter,
                                    parity);
    modbusServer->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
                                    stopBits);


    //更新寄存器值
    connect(modbusServer,&QModbusServer::dataWritten,this,
            &ModbusServer::updateData);
    //更新连接状态
    connect(modbusServer, &QModbusServer::stateChanged,
            this, &ModbusServer::onStateChanged);
    //错误发生
    connect(modbusServer, &QModbusServer::errorOccurred,
            this, &ModbusServer::handleDeviceError);
    return  1;

}

bool ModbusServer::initModbusNetworkServer(QString address, int port)
{
//    if(modbusServer)
//    {
//        modbusServer->disconnect();
//        delete modbusServer;
//        modbusServer = nullptr;
//    }

    //网口
    modbusServer = new QModbusTcpServer(this);

    m_mode = Tcp;

    if(!modbusServer)
    {
        qDebug()<<"could not create modbus slave";
        return false;
    }

    QModbusDataUnitMap reg;
    reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
    reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
    reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
    reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });

    modbusServer->setMap(reg);

    modbusServer->setConnectionParameter(QModbusDevice::NetworkAddressParameter,address);
    modbusServer->setConnectionParameter(QModbusDevice::NetworkPortParameter,port);

    //更新寄存器值
    connect(modbusServer,&QModbusServer::dataWritten,this,
            &ModbusServer::updateData);
    //更新连接状态
    connect(modbusServer, &QModbusServer::stateChanged,
            this, &ModbusServer::onStateChanged);
    //错误发生
    connect(modbusServer, &QModbusServer::errorOccurred,
            this, &ModbusServer::handleDeviceError);

    return true;
}

bool ModbusServer::connectDevice()
{
	//设置modbusServer的modbus地址固定为1
	modbusServer->setServerAddress(1);
    return modbusServer->connectDevice();
}

void ModbusServer::updateData(QModbusDataUnit::RegisterType table, int address, int size)
{
    for (int i = 0; i < size; ++i) {
        quint16 value;
        QString text;
        switch (table) {
        case QModbusDataUnit::Coils:
            modbusServer->data(QModbusDataUnit::Coils, address + i, &value);

            break;
        case QModbusDataUnit::HoldingRegisters:
            modbusServer->data(QModbusDataUnit::HoldingRegisters, address + i, &value);

            break;
        default:
            break;
        }

        emit registerData_signal(address+i,value);

    }
}

void ModbusServer::handleDeviceError(QModbusDevice::Error newError)
{
    if(newError == QModbusDevice::NoError || !modbusServer)
        return;
    emit error_signal(modbusServer->errorString());
}

void ModbusServer::onStateChanged(int state)
{
    if(state == QModbusDevice::UnconnectedState)
        emit stateChanged_signal(0);
    else if(state == QModbusDevice::ConnectedState)
        emit stateChanged_signal(1);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146

main.cpp中添加modbus协议调试(参考示例):

QLoggingCategory::setFilterRules(QStringLiteral("qt.modbus* = true"));
  • 1

调用我们封装的modbusServer类:

ModbusServer *modbusServer = new ModbusServer(this);

modbusServer->initModbusNetworkServer("127.0.0.1", 502);
modbusServer->connectDevice();
  • 1
  • 2
  • 3
  • 4

其实还应该添加析构方法断开连接释放资源,自己加一下哦~

接收成功了,我们可以根据需求再进行一些修改:
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/187329
推荐阅读
相关标签
  

闽ICP备14008679号