Modbus 服务器
该示例实现了一个 Modbus 服务器应用程序。
该示例充当 Modbus 服务器。它接收标准 Modbus 请求,根据请求调整其内部状态,并作出相应的响应。
该示例必须与Modbus 客户端示例结合使用。该示例应在 Modbus 客户端示例启动前启动并进入监听状态。这两个示例之间的后续交互使用 Modbus 协议。
本示例中使用的关键类:
创建 QModbusServer
执行任何通信都需要QModbusServer 的实例。根据指定的连接类型,示例可以实例化QModbusRtuSerialServer (用于串行通信)或QModbusTcpServer (用于基于 TCP 的通信)。
auto type = static_cast<ModbusConnection>(index); if (type == Serial) { #if QT_CONFIG(modbus_serialport) modbusDevice = new QModbusRtuSerialServer(this); // Try to fill in the first available serial port name if the line edit // is empty, or contains a url (assume that ':' is only a part of url). const auto ports = QSerialPortInfo::availablePorts(); const auto currentText = ui->portEdit->text(); if (!ports.isEmpty() && (currentText.isEmpty() || currentText.contains(u':'))) ui->portEdit->setText(ports.front().portName()); #endif } else if (type == Tcp) { modbusDevice = new QModbusTcpServer(this); const QUrl currentUrl = QUrl::fromUserInput(ui->portEdit->text()); // Check if we already have <ip address>:<port> if (currentUrl.port() <= 0) ui->portEdit->setText(QLatin1String("127.0.0.1:50200")); }
服务器创建后,将使用QModbusServer::setMap() 方法设置寄存器映射。客户端应用程序使用该寄存器映射读写服务器数据。
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);
然后指定通信参数和服务器地址。通信参数取决于通信类型:
if (static_cast<ModbusConnection>(ui->connectType->currentIndex()) == Serial) { modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, ui->portEdit->text()); #if QT_CONFIG(modbus_serialport) 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); #endif } 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());
创建服务器并指定所有参数后,使用QModbusServer::connectDevice() 连接到 Modbus 网络。
更改本地值
该示例允许使用提供的组合框或行编辑更改所有支持的register types 的值。用户界面中的值更新后,QModbusServer::setData() 方法将用于更新服务器上的实际值:
void MainWindow::bitChanged(int id, QModbusDataUnit::RegisterType table, bool value) { if (!modbusDevice) return; if (!modbusDevice->setData(table, quint16(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 quint16 id = quint16(QObject::sender()->property("ID").toUInt()); if (objectName.startsWith(QStringLiteral("inReg"))) { const auto uval = value.toUShort(&ok, 16); if (ok) ok = modbusDevice->setData(QModbusDataUnit::InputRegisters, id, uval); } else if (objectName.startsWith(QStringLiteral("holdReg"))) { const auto uval = value.toUShort(&ok, 16); if (ok) ok = modbusDevice->setData(QModbusDataUnit::HoldingRegisters, id, uval); } if (!ok) statusBar()->showMessage(tr("Could not set register: ") + modbusDevice->errorString(), 5000); } }
处理远程写入
Modbus 客户端可以通过发送写入请求更新Coils 和HoldingRegisters 。一旦服务器端使用此类请求更新了值,就会发出QModbusServer::dataWritten() 信号。
connect(modbusDevice, &QModbusServer::dataWritten, this, &MainWindow::updateWidgets);
Modbus 服务器示例连接到该信号,提取更新值并相应更新用户界面:
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, quint16(address + i), &value); coilButtons.button(address + i)->setChecked(value); break; case QModbusDataUnit::HoldingRegisters: modbusDevice->data(QModbusDataUnit::HoldingRegisters, quint16(address + i), &value); registers.value(QStringLiteral("holdReg_%1").arg(address + i))->setText(text .setNum(value, 16)); break; default: break; } } }
运行示例
运行示例 Qt Creator,打开Welcome 模式并从Examples 中选择示例。更多信息,请参阅Qt Creator: 教程:构建并运行。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.