Cliente Modbus
El ejemplo implementa una aplicación cliente Modbus.
El ejemplo actúa como cliente Modbus enviando peticiones Modbus vía línea serie o TCP. El diálogo mostrado permite la definición de peticiones estándar y muestra las respuestas entrantes.
El ejemplo debe ser usado en conjunto con el ejemplo Servidor Modbus u otro dispositivo Modbus que esté conectado vía TCP o Puerto Serie.
Clases clave utilizadas en este ejemplo:

Creando un QModbusClient
Se requiere una instancia de QModbusClient para realizar cualquier comunicación. Dependiendo del tipo de conexión especificado, el ejemplo puede instanciar un QModbusRtuSerialClient (para comunicación serial), o un QModbusTcpClient (para comunicación basada en TCP).
auto type = static_cast<ModbusConnection>(index); if (type == Serial) { #if QT_CONFIG(modbus_serialport) modbusDevice = new QModbusRtuSerialClient(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 QModbusTcpClient(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")); }
Una vez creado el cliente, utilice el método setConnectionParameter() para especificar los parámetros de conexión. Los parámetros varían en función del tipo de comunicación:
const auto settings = m_settingsDialog->settings(); if (static_cast<ModbusConnection>(ui->connectType->currentIndex()) == Serial) { modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, ui->portEdit->text()); #if QT_CONFIG(modbus_serialport) modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, settings.parity); modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, settings.baud); modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, settings.dataBits); modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, 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->setTimeout(settings.responseTime); modbusDevice->setNumberOfRetries(settings.numberOfRetries);
Una vez creado el cliente y especificados todos los parámetros, utilice QModbusClient::connectDevice() para conectarse a la red Modbus.
Lectura de datos
Para leer datos del servidor Modbus, el cliente necesita especificar una dirección de servidor y los parámetros de los objetos que quiere leer:
Los parámetros de los objetos están representados por la clase QModbusDataUnit:
QModbusDataUnit MainWindow::readRequest() const { const auto table = ui->writeTable->currentData().value<QModbusDataUnit::RegisterType>(); int startAddress = ui->readAddress->value(); Q_ASSERT(startAddress >= 0 && startAddress < 10); // do not go beyond 10 entries quint16 numberOfEntries = qMin(ui->readSize->currentText().toUShort(), quint16(10 - startAddress)); return QModbusDataUnit(table, startAddress, numberOfEntries); }
Una vez recogidos los parámetros, se utiliza el método sendReadRequest() para enviar la petición real. El método devuelve un QModbusReply que debe procesarse de forma asíncrona, por lo que se utiliza la señal QModbusReply::finished() para comprobar cuándo está lista la respuesta.
if (auto *reply = modbusDevice->sendReadRequest(readRequest(), ui->serverEdit->value())) { if (!reply->isFinished()) connect(reply, &QModbusReply::finished, this, &MainWindow::onReadReady); else delete reply; // broadcast replies return immediately } else { statusBar()->showMessage(tr("Read error: %1").arg(modbusDevice->errorString()), 5000); }
Una vez recibida la señal QModbusReply::finished(), el objeto de respuesta puede utilizarse para obtener los datos o para comprobar si hay errores de lectura:
void MainWindow::onReadReady() { auto reply = qobject_cast<QModbusReply *>(sender()); if (!reply) return; if (reply->error() == QModbusDevice::NoError) { const QModbusDataUnit unit = reply->result(); for (qsizetype i = 0, total = unit.valueCount(); i < total; ++i) { const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress() + i) .arg(QString::number(unit.value(i), unit.registerType() <= QModbusDataUnit::Coils ? 10 : 16)); ui->readValue->addItem(entry); } } else if (reply->error() == QModbusDevice::ProtocolError) { statusBar()->showMessage(tr("Read response error: %1 (Modbus exception: 0x%2)"). arg(reply->errorString()). arg(reply->rawResult().exceptionCode(), -1, 16), 5000); } else { statusBar()->showMessage(tr("Read response error: %1 (code: 0x%2)"). arg(reply->errorString()). arg(reply->error(), -1, 16), 5000); } reply->deleteLater(); }
Escribir datos
Para escribir los datos en el servidor Modbus, el cliente necesita especificar la dirección del servidor, y los parámetros de los objetos que quiere escribir. Al igual que con la lectura de los datos, se utiliza la clase QModbusDataUnit para representar la información sobre los datos a escribir. Esta vez los datos también incluyen el values deseado. El método sendWriteRequest() se utiliza para escribir los datos deseados:
QModbusDataUnit writeUnit = writeRequest(); QModbusDataUnit::RegisterType table = writeUnit.registerType(); for (qsizetype i = 0, total = writeUnit.valueCount(); i < total; ++i) { const auto addr = i + writeUnit.startAddress(); if (table == QModbusDataUnit::Coils) writeUnit.setValue(i, writeModel->m_coils[addr]); else writeUnit.setValue(i, writeModel->m_holdingRegisters[addr]); } if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, ui->serverEdit->value())) { if (!reply->isFinished()) { connect(reply, &QModbusReply::finished, this, [this, reply]() { const auto error = reply->error(); if (error == QModbusDevice::ProtocolError) { statusBar()->showMessage(tr("Write response error: %1 (Modbus exception: 0x%2)") .arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16), 5000); } else if (error != QModbusDevice::NoError) { statusBar()->showMessage(tr("Write response error: %1 (code: 0x%2)"). arg(reply->errorString()).arg(error, -1, 16), 5000); } reply->deleteLater(); }); } else { // broadcast replies return immediately reply->deleteLater(); } } else { statusBar()->showMessage(tr("Write error: %1").arg(modbusDevice->errorString()), 5000); }
Al igual que con la lectura de los datos, el objeto QModbusReply devuelto se utiliza para comprobar si hay errores de escritura.
Ejecución del ejemplo
Para ejecutar el ejemplo desde Qt Creatorabra el modo Welcome y seleccione el ejemplo de Examples. Para más información, consulte Qt Creator: Tutorial: Construir y ejecutar.
© 2026 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.