首页 > 其他分享 >Qt QModbus相关类实现ModbusTcpServer总结

Qt QModbus相关类实现ModbusTcpServer总结

时间:2024-03-01 11:36:14浏览次数:440  
标签:modbusDevice QModbusDataUnit const Qt int QModbus ui ModbusTcpServer modbusServe

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

1、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查看文件树:

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

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

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

 1 #include "mainwindow.h"
 2 
 3 #include <QApplication>
 4 #include <QLoggingCategory>
 5 
 6 int main(int argc, char *argv[])
 7 {
 8     // TODO uncomment this line before release
 9     // right now we always need it
10     QLoggingCategory::setFilterRules(QStringLiteral("qt.modbus* = true"));
11     QApplication a(argc, argv);
12     MainWindow w;
13     w.show();
14 
15     return a.exec();
16 }

  mainwindow.cpp:

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

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

  1 #include "mainwindow.h"
  2 #include "settingsdialog.h"
  3 #include "ui_mainwindow.h"
  4 
  5 #include <QModbusRtuSerialSlave>
  6 #include <QModbusTcpServer>
  7 #include <QRegularExpression>
  8 #include <QStatusBar>
  9 #include <QUrl>
 10 
 11 enum ModbusConnection {
 12     Serial,
 13     Tcp
 14 };
 15 
 16 MainWindow::MainWindow(QWidget *parent)
 17     : QMainWindow(parent)
 18     , ui(new Ui::MainWindow)
 19     , modbusDevice(nullptr)
 20 {
 21     ui->setupUi(this);
 22     setupWidgetContainers();
 23 
 24     ui->connectType->setCurrentIndex(0);
 25     on_connectType_currentIndexChanged(0);
 26 
 27     m_settingsDialog = new SettingsDialog(this);
 28     initActions();
 29 }
 30 
 31 MainWindow::~MainWindow()
 32 {
 33     if (modbusDevice)
 34         modbusDevice->disconnectDevice();
 35     delete modbusDevice;
 36 
 37     delete ui;
 38 }
 39 
 40 void MainWindow::initActions()
 41 {
 42     ui->actionConnect->setEnabled(true);
 43     ui->actionDisconnect->setEnabled(false);
 44     ui->actionExit->setEnabled(true);
 45     ui->actionOptions->setEnabled(true);
 46 
 47     connect(ui->actionConnect, &QAction::triggered,
 48             this, &MainWindow::on_connectButton_clicked);
 49     connect(ui->actionDisconnect, &QAction::triggered,
 50             this, &MainWindow::on_connectButton_clicked);
 51 
 52     connect(ui->actionExit, &QAction::triggered, this, &QMainWindow::close);
 53     connect(ui->actionOptions, &QAction::triggered, m_settingsDialog, &QDialog::show);
 54 }
 55 
 56 void MainWindow::on_connectType_currentIndexChanged(int index)
 57 {
 58     if (modbusDevice) {
 59         modbusDevice->disconnect();
 60         delete modbusDevice;
 61         modbusDevice = nullptr;
 62     }
 63 
 64     ModbusConnection type = static_cast<ModbusConnection> (index);
 65     if (type == Serial) {
 66         modbusDevice = new QModbusRtuSerialSlave(this);
 67     } else if (type == Tcp) {
 68         modbusDevice = new QModbusTcpServer(this);
 69         if (ui->portEdit->text().isEmpty())
 70             ui->portEdit->setText(QLatin1Literal("127.0.0.1:502"));
 71     }
 72     ui->listenOnlyBox->setEnabled(type == Serial);
 73 
 74     if (!modbusDevice) {
 75         ui->connectButton->setDisabled(true);
 76         if (type == Serial)
 77             statusBar()->showMessage(tr("Could not create Modbus slave."), 5000);
 78         else
 79             statusBar()->showMessage(tr("Could not create Modbus server."), 5000);
 80     } else {
 81         QModbusDataUnitMap reg;
 82         reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
 83         reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
 84         reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
 85         reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });
 86 
 87         modbusDevice->setMap(reg);
 88 
 89         connect(modbusDevice, &QModbusServer::dataWritten,
 90                 this, &MainWindow::updateWidgets);
 91         connect(modbusDevice, &QModbusServer::stateChanged,
 92                 this, &MainWindow::onStateChanged);
 93         connect(modbusDevice, &QModbusServer::errorOccurred,
 94                 this, &MainWindow::handleDeviceError);
 95 
 96         connect(ui->listenOnlyBox, &QCheckBox::toggled, this, [this](bool toggled) {
 97             if (modbusDevice)
 98                 modbusDevice->setValue(QModbusServer::ListenOnlyMode, toggled);
 99         });
100         emit ui->listenOnlyBox->toggled(ui->listenOnlyBox->isChecked());
101         connect(ui->setBusyBox, &QCheckBox::toggled, this, [this](bool toggled) {
102             if (modbusDevice)
103                 modbusDevice->setValue(QModbusServer::DeviceBusy, toggled ? 0xffff : 0x0000);
104         });
105         emit ui->setBusyBox->toggled(ui->setBusyBox->isChecked());
106 
107         setupDeviceData();
108     }
109 }
110 
111 void MainWindow::handleDeviceError(QModbusDevice::Error newError)
112 {
113     if (newError == QModbusDevice::NoError || !modbusDevice)
114         return;
115 
116     statusBar()->showMessage(modbusDevice->errorString(), 5000);
117 }
118 
119 void MainWindow::on_connectButton_clicked()
120 {
121     bool intendToConnect = (modbusDevice->state() == QModbusDevice::UnconnectedState);
122 
123     statusBar()->clearMessage();
124 
125     if (intendToConnect) {
126         if (static_cast<ModbusConnection> (ui->connectType->currentIndex()) == Serial) {
127             modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
128                 ui->portEdit->text());
129             modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
130                 m_settingsDialog->settings().parity);
131             modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
132                 m_settingsDialog->settings().baud);
133             modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
134                 m_settingsDialog->settings().dataBits);
135             modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
136                 m_settingsDialog->settings().stopBits);
137         } else {
138             const QUrl url = QUrl::fromUserInput(ui->portEdit->text());
139             modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
140             modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());
141         }
142         modbusDevice->setServerAddress(ui->serverEdit->text().toInt());
143         if (!modbusDevice->connectDevice()) {
144             statusBar()->showMessage(tr("Connect failed: ") + modbusDevice->errorString(), 5000);
145         } else {
146             ui->actionConnect->setEnabled(false);
147             ui->actionDisconnect->setEnabled(true);
148         }
149     } else {
150         modbusDevice->disconnectDevice();
151         ui->actionConnect->setEnabled(true);
152         ui->actionDisconnect->setEnabled(false);
153     }
154 }
155 
156 void MainWindow::onStateChanged(int state)
157 {
158     bool connected = (state != QModbusDevice::UnconnectedState);
159     ui->actionConnect->setEnabled(!connected);
160     ui->actionDisconnect->setEnabled(connected);
161 
162     if (state == QModbusDevice::UnconnectedState)
163         ui->connectButton->setText(tr("Connect"));
164     else if (state == QModbusDevice::ConnectedState)
165         ui->connectButton->setText(tr("Disconnect"));
166 }
167 
168 void MainWindow::coilChanged(int id)
169 {
170     QAbstractButton *button = coilButtons.button(id);
171     bitChanged(id, QModbusDataUnit::Coils, button->isChecked());
172 }
173 
174 void MainWindow::discreteInputChanged(int id)
175 {
176     QAbstractButton *button = discreteButtons.button(id);
177     bitChanged(id, QModbusDataUnit::DiscreteInputs, button->isChecked());
178 }
179 
180 void MainWindow::bitChanged(int id, QModbusDataUnit::RegisterType table, bool value)
181 {
182     if (!modbusDevice)
183         return;
184 
185     if (!modbusDevice->setData(table, id, value))
186         statusBar()->showMessage(tr("Could not set data: ") + modbusDevice->errorString(), 5000);
187 }
188 
189 void MainWindow::setRegister(const QString &value)
190 {
191     if (!modbusDevice)
192         return;
193 
194     const QString objectName = QObject::sender()->objectName();
195     if (registers.contains(objectName)) {
196         bool ok = true;
197         const int id = QObject::sender()->property("ID").toInt();
198         if (objectName.startsWith(QStringLiteral("inReg")))
199             ok = modbusDevice->setData(QModbusDataUnit::InputRegisters, id, value.toInt(&ok, 16));
200         else if (objectName.startsWith(QStringLiteral("holdReg")))
201             ok = modbusDevice->setData(QModbusDataUnit::HoldingRegisters, id, value.toInt(&ok, 16));
202 
203         if (!ok)
204             statusBar()->showMessage(tr("Could not set register: ") + modbusDevice->errorString(),
205                                      5000);
206     }
207 }
208 
209 void MainWindow::updateWidgets(QModbusDataUnit::RegisterType table, int address, int size)
210 {
211     for (int i = 0; i < size; ++i) {
212         quint16 value;
213         QString text;
214         switch (table) {
215         case QModbusDataUnit::Coils:
216             modbusDevice->data(QModbusDataUnit::Coils, address + i, &value);
217             coilButtons.button(address + i)->setChecked(value);
218             break;
219         case QModbusDataUnit::HoldingRegisters:
220             modbusDevice->data(QModbusDataUnit::HoldingRegisters, address + i, &value);
221             registers.value(QStringLiteral("holdReg_%1").arg(address + i))->setText(text
222                 .setNum(value, 16));
223             break;
224         default:
225             break;
226         }
227     }
228 }
229 
230 // -- private
231 
232 void MainWindow::setupDeviceData()
233 {
234     if (!modbusDevice)
235         return;
236 
237     for (int i = 0; i < coilButtons.buttons().count(); ++i)
238         modbusDevice->setData(QModbusDataUnit::Coils, i, coilButtons.button(i)->isChecked());
239 
240     for (int i = 0; i < discreteButtons.buttons().count(); ++i) {
241         modbusDevice->setData(QModbusDataUnit::DiscreteInputs, i,
242             discreteButtons.button(i)->isChecked());
243     }
244 
245     bool ok;
246     for (QLineEdit *widget : qAsConst(registers)) {
247         if (widget->objectName().startsWith(QStringLiteral("inReg"))) {
248             modbusDevice->setData(QModbusDataUnit::InputRegisters, widget->property("ID").toInt(),
249                 widget->text().toInt(&ok, 16));
250         } else if (widget->objectName().startsWith(QStringLiteral("holdReg"))) {
251             modbusDevice->setData(QModbusDataUnit::HoldingRegisters, widget->property("ID").toInt(),
252                 widget->text().toInt(&ok, 16));
253         }
254     }
255 }
256 
257 void MainWindow::setupWidgetContainers()
258 {
259     coilButtons.setExclusive(false);
260     discreteButtons.setExclusive(false);
261 
262     QRegularExpression regexp(QStringLiteral("coils_(?<ID>\\d+)"));
263     const QList<QCheckBox *> coils = findChildren<QCheckBox *>(regexp);
264     for (QCheckBox *cbx : coils)
265         coilButtons.addButton(cbx, regexp.match(cbx->objectName()).captured("ID").toInt());
266     connect(&coilButtons, SIGNAL(buttonClicked(int)), this, SLOT(coilChanged(int)));
267 
268     regexp.setPattern(QStringLiteral("disc_(?<ID>\\d+)"));
269     const QList<QCheckBox *> discs = findChildren<QCheckBox *>(regexp);
270     for (QCheckBox *cbx : discs)
271         discreteButtons.addButton(cbx, regexp.match(cbx->objectName()).captured("ID").toInt());
272     connect(&discreteButtons, SIGNAL(buttonClicked(int)), this, SLOT(discreteInputChanged(int)));
273 
274     regexp.setPattern(QLatin1String("(in|hold)Reg_(?<ID>\\d+)"));
275     const QList<QLineEdit *> qle = findChildren<QLineEdit *>(regexp);
276     for (QLineEdit *lineEdit : qle) {
277         registers.insert(lineEdit->objectName(), lineEdit);
278         lineEdit->setProperty("ID", regexp.match(lineEdit->objectName()).captured("ID").toInt());
279         lineEdit->setValidator(new QRegExpValidator(QRegExp(QStringLiteral("[0-9a-f]{0,4}"),
280             Qt::CaseInsensitive), this));
281         connect(lineEdit, &QLineEdit::textChanged, this, &MainWindow::setRegister);
282     }
283 }
(4)、master代码分析

  同样我们先查看文件树:

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

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

  建立连接:

 1 modbusDevice = new QModbusTcpClient(this);
 2 if (ui->portEdit->text().isEmpty())
 3         ui->portEdit->setText(QLatin1Literal("127.0.0.1:502"));
 4 
 5 modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, url.port());
 6 modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, url.host());
 7 
 8 void MainWindow::on_readWriteButton_clicked()
 9 {
10     if (!modbusDevice)
11         return;
12     ui->readValue->clear();
13     statusBar()->clearMessage();
14 
15     QModbusDataUnit writeUnit = writeRequest();
16     QModbusDataUnit::RegisterType table = writeUnit.registerType();
17     for (uint i = 0; i < writeUnit.valueCount(); i++) {
18         if (table == QModbusDataUnit::Coils)
19             writeUnit.setValue(i, writeModel->m_coils[i + writeUnit.startAddress()]);
20         else
21             writeUnit.setValue(i, writeModel->m_holdingRegisters[i + writeUnit.startAddress()]);
22     }
23 
24     if (auto *reply = modbusDevice->sendReadWriteRequest(readRequest(), writeUnit,
25         ui->serverEdit->value())) {
26         if (!reply->isFinished())
27             connect(reply, &QModbusReply::finished, this, &MainWindow::readReady);
28         else
29             delete reply; // broadcast replies return immediately
30     } else {
31         statusBar()->showMessage(tr("Read error: ") + modbusDevice->errorString(), 5000);
32     }
33 }
34 
35 if (modbusDevice)
36         modbusDevice->disconnectDevice();
37 delete modbusDevice;
(5)、QModbusServer和QModbusClient类了解

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

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

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

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

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

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

  .pro中添加:

QT       += core gui sql serialport serialbus

  主要创建内容和读写操作

  1 #ifndef MODBUSSERVER_H
  2 #define MODBUSSERVER_H
  3 
  4 #include <QObject>
  5 #include <QModbusServer>
  6 #include <QModbusRtuSerialSlave>
  7 #include <QModbusTcpServer>
  8 #include <QSerialPort>
  9 
 10 /*
 11 *
 12 *
 13 *       modbus slave 从站
 14 *
 15 *       modbusSlove_* m_slave = new modbusSlove_(this);
 16 *
 17 *       initModbusSerialSlove()
 18 *
 19 *       connectDevice()
 20 *
 21 *       //寄存器值发生改变,连接这个信号
 22         void registerData_signal(int address,int value);
 23 *
 24 */
 25 class ModbusServer : public QObject
 26 {
 27     Q_OBJECT
 28 public:
 29     explicit ModbusServer(QObject *parent = nullptr);
 30 
 31     /**
 32 * @projectName   testMyClass
 33 * @brief         初始化串口modbusSlave
 34 * 其他参数 波特率 数据位 校验位 停止位
 35 * @author        SMY
 36 * @date          2019-03-27
 37 */
 38     bool initModbusSerialServer(QString portName, qint32 baudRate, QSerialPort::DataBits dataBits,
 39                          QSerialPort::Parity parity, QSerialPort::StopBits stopBits);
 40     /**
 41 * @projectName   testMyClass
 42 * @brief         初始化网口modbusSlave
 43 * ip地址,端口号
 44 * @author        SMY
 45 * @date          2019-03-27
 46 */
 47     bool initModbusNetworkServer(QString address,int port);
 48 
 49     /**
 50 * @projectName   testMyClass
 51 * @brief         连接设备
 52 * @author        SMY
 53 * @date          2019-03-27
 54 */
 55     bool connectDevice();
 56     /**
 57 * @projectName   testMyClass
 58 * @brief         网口还是串口连接
 59 * @author        SMY
 60 * @date          2019-03-26
 61 */
 62     enum modbusConnection
 63     {
 64         Serial,
 65         Tcp
 66     };
 67 
 68 signals:
 69     //寄存器值发生改变
 70     void registerData_signal(int address,int value);
 71     //发生错误
 72     void error_signal(QString errorString);
 73     /*state :1 connect ,0:unconnect
 74     *状态发生改变
 75     */
 76     void stateChanged_signal(int state);
 77 public slots:
 78 private slots:
 79     /**
 80 * @projectName   testMyClass
 81 * @brief         更新寄存器数据
 82 * @author        SMY
 83 * @date          2019-03-26
 84 */
 85     void updateData(QModbusDataUnit::RegisterType table, int address, int size);
 86     /**
 87 * @projectName   testMyClass
 88 * @brief         device error
 89 * @author        SMY
 90 * @date          2019-03-27
 91 */
 92     void handleDeviceError(QModbusDevice::Error newError);
 93     /**
 94 * @projectName   testMyClass
 95 * @brief         连接状态改变
 96 * @author        SMY
 97 * @date          2019-03-27
 98 */
 99     void onStateChanged(int state);
100 private:
101     modbusConnection m_mode;
102     QModbusServer* modbusServer;
103 };
104 
105 #endif // MODBUSSERVER__H
  1 #include "modbusserver.h"
  2 #include <QDebug>
  3 
  4 ModbusServer::ModbusServer(QObject *parent) : QObject(parent)
  5 {
  6 
  7 }
  8 
  9 bool ModbusServer::initModbusSerialServer(QString portName, qint32 baudRate, QSerialPort::DataBits dataBits,
 10                                    QSerialPort::Parity parity,
 11                                    QSerialPort::StopBits stopBits)
 12 {
 13     //串口
 14 
 15     modbusServer = new QModbusRtuSerialSlave(this);
 16 
 17     m_mode = Serial;
 18 
 19     if(!modbusServer)
 20     {
 21         qDebug()<<"could not create modbus slave";
 22         return 0;
 23     }
 24 
 25     QModbusDataUnitMap reg;
 26     reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
 27     reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
 28     reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
 29     reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });
 30 
 31     modbusServer->setMap(reg);
 32 
 33     modbusServer->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
 34                                     portName);
 35     modbusServer->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
 36                                     baudRate);
 37     modbusServer->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
 38                                     dataBits);
 39     modbusServer->setConnectionParameter(QModbusDevice::SerialParityParameter,
 40                                     parity);
 41     modbusServer->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
 42                                     stopBits);
 43 
 44 
 45     //更新寄存器值
 46     connect(modbusServer,&QModbusServer::dataWritten,this,
 47             &ModbusServer::updateData);
 48     //更新连接状态
 49     connect(modbusServer, &QModbusServer::stateChanged,
 50             this, &ModbusServer::onStateChanged);
 51     //错误发生
 52     connect(modbusServer, &QModbusServer::errorOccurred,
 53             this, &ModbusServer::handleDeviceError);
 54     return  1;
 55 
 56 }
 57 
 58 bool ModbusServer::initModbusNetworkServer(QString address, int port)
 59 {
 60 //    if(modbusServer)
 61 //    {
 62 //        modbusServer->disconnect();
 63 //        delete modbusServer;
 64 //        modbusServer = nullptr;
 65 //    }
 66 
 67     //网口
 68     modbusServer = new QModbusTcpServer(this);
 69 
 70     m_mode = Tcp;
 71 
 72     if(!modbusServer)
 73     {
 74         qDebug()<<"could not create modbus slave";
 75         return false;
 76     }
 77 
 78     QModbusDataUnitMap reg;
 79     reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
 80     reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
 81     reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
 82     reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });
 83 
 84     modbusServer->setMap(reg);
 85 
 86     modbusServer->setConnectionParameter(QModbusDevice::NetworkAddressParameter,address);
 87     modbusServer->setConnectionParameter(QModbusDevice::NetworkPortParameter,port);
 88 
 89     //更新寄存器值
 90     connect(modbusServer,&QModbusServer::dataWritten,this,
 91             &ModbusServer::updateData);
 92     //更新连接状态
 93     connect(modbusServer, &QModbusServer::stateChanged,
 94             this, &ModbusServer::onStateChanged);
 95     //错误发生
 96     connect(modbusServer, &QModbusServer::errorOccurred,
 97             this, &ModbusServer::handleDeviceError);
 98 
 99     return true;
100 }
101 
102 bool ModbusServer::connectDevice()
103 {
104     //设置modbusServer的modbus地址固定为1
105     modbusServer->setServerAddress(1);
106     return modbusServer->connectDevice();
107 }
108 
109 void ModbusServer::updateData(QModbusDataUnit::RegisterType table, int address, int size)
110 {
111     for (int i = 0; i < size; ++i) {
112         quint16 value;
113         QString text;
114         switch (table) {
115         case QModbusDataUnit::Coils:
116             modbusServer->data(QModbusDataUnit::Coils, address + i, &value);
117 
118             break;
119         case QModbusDataUnit::HoldingRegisters:
120             modbusServer->data(QModbusDataUnit::HoldingRegisters, address + i, &value);
121 
122             break;
123         default:
124             break;
125         }
126 
127         emit registerData_signal(address+i,value);
128 
129     }
130 }
131 
132 void ModbusServer::handleDeviceError(QModbusDevice::Error newError)
133 {
134     if(newError == QModbusDevice::NoError || !modbusServer)
135         return;
136     emit error_signal(modbusServer->errorString());
137 }
138 
139 void ModbusServer::onStateChanged(int state)
140 {
141     if(state == QModbusDevice::UnconnectedState)
142         emit stateChanged_signal(0);
143     else if(state == QModbusDevice::ConnectedState)
144         emit stateChanged_signal(1);
145 }

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

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

调用我们封装的modbusServer类:

1 ModbusServer *modbusServer = new ModbusServer(this);
2 
3 modbusServer->initModbusNetworkServer("127.0.0.1", 502);
4 modbusServer->connectDevice();

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

接收成功了,我们可以根据需求再进行一些修改:

标签:modbusDevice,QModbusDataUnit,const,Qt,int,QModbus,ui,ModbusTcpServer,modbusServe
From: https://www.cnblogs.com/ybqjymy/p/18046596

相关文章

  • Qt QModbusServer类
    1、概述QModbusServer类是用于接收和处理Modbus请求的接口。1Header:#include<QModbusServer>2qmake:QT+=serialbus3Since:Qt5.84Inherits:QModbusDevice5InheritedBy:QModbusRtuSerialSlaveandQModbusTcpServerModbus网络可以具有多个Modbus......
  • Qt 多线程中使用QTimer和信号、槽 QObject::startTimer: Timers cannot be started fr
    多线程中使用QTimer我们可能在Qt的多线程中使用QTimer中都会遇到一个错误:Cannotcreatechildrenforaparentthatisinadifferentthread.或者QObject::startTimer:TimerscannotbestartedfromanotherthreadQTimer定时器不能在不同的线程中启动。出现这个主要原因......
  • Qt Cannot open include file: 'QtConcurrent': No such file or directory
    假期手痒用Qt写了个便笺程序,其中文件操作用到了QtConcurrent模块。噼里啪啦,一通猛如虎的操作下来,代码写完了,愉快地build+run一套,结果报错了:(Cannotopenincludefile:'QtConcurrent':Nosuchfileordirectory编译不过一声吼,操起鼠标查google。官方文档就是这么写的看......
  • Qt 多线程中使用信号槽的示例
    之前对线程理解得不深入,所以对Qt的线程机制没有搞清楚,今天写一篇文章总结一下,如有错误,欢迎指出。    首先需要理解线程是什么,线程在代码中的表现其实就是一个函数,只不过这个函数和主线程的函数同时运行,写C语言的都知道,一般代码是从main()函数开始运行的,每个线程都有一......
  • VS Qt - cmake项目中添加运行时命令行参数
    1、VS在项目目录中找到.vs目录--->launch.vs.json{"version":"0.2.1","defaults":{},"configurations":[{"type":"default","project":"CMakeLists.txt",......
  • OpenCV计数应用 c++(QT)
    一、前言为了挑战一下OpenCV的学习成果,最经一直在找各类项目进行实践。机缘巧合之下,得到了以下的需求:要求从以下图片中找出所有的近似矩形的点并计数,重叠点需要拆分单独计数。二、解题思路1.图片作二值化处理autoimage=cv::imread("points.jpg");cv::Matborder;//为......
  • Qt 随机数生成器:QRandomGenerator
    一、描述QRandomGenerator可用于从高质量随机数生成器生成随机值。与C++随机引擎一样,QRandomGenerator可以通过构造函数使用用户提供的值作为种子。播种时,此类生成的数字序列是确定性的。也就是说,给定相同的种子数据,QRandomGenerator会生成相同的数字序列。给定不同的种......
  • Qt 生成随机数 qrand、QRandomGenerator
    //老方法//利用qrand和qsrand生成随机数//位于QtGlobal中//例,生成一个0和10之间的随机数1qsrand(QTime::currentTime().msec());//设置种子,该种子作为qrand生成随机数的起始值,RAND_MAX为32767,即随机数在种子值到32767之间2qrand()%10;//新方法//利用QRandomGenerator类......
  • Qt 无法连接到进程内QML调试器
    问题:由于在Qt5以上版本默认开启QML调试器造成的。用于告知用户,这将打开一个到运行QML的Javascript解释器的端口,以便从中获得调试输出。显然,这会造成一个安全漏洞,所以在不安全的地方使用时应该关闭它(在释放运行时自动关闭)。Qt4默认不开启QML调试器,而Qt5版本以上默认开启。......
  • Qt QList使用总结
    概述QList是Qt的泛型容器类之一。它将项目存储在一个列表中,该列表提供基于索引的快速访问以及基于索引的插入和删除。QList、QLinkedList和QVector提供了类似的API和功能。它们通常是可互换的,但性能有所区别。QVector应该是默认首选的容器QList是最广泛用于QtAPI中传递值......