在疫情环境下催生出了很多的无人或者减少人员接触的项目,比如无人智慧餐厅项目中的无人送餐项目,主要是由送餐小车和一个中控屏和部分协助发餐的设备组成,由于餐厅一般的范围不会很大,考虑到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