在疫情环境下催生出了很多的无人或者减少人员接触的项目,比如无人智慧餐厅项目中的无人送餐项目,主要是由送餐小车和一个中控屏和部分协助发餐的设备组成,由于餐厅一般的范围不会很大,考虑到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();
其实还应该添加析构方法断开连接释放资源,自己加一下哦~
接收成功了,我们可以根据需求再进行一些修改: