Auf dieser Seite

Modbus-Client

Das Beispiel implementiert eine Modbus-Client-Anwendung.

Das Beispiel fungiert als Modbus-Client, der Modbus-Anfragen über eine serielle Schnittstelle oder TCP sendet. Der angezeigte Dialog ermöglicht die Definition von Standardanfragen und zeigt eingehende Antworten an.

Das Beispiel muss in Verbindung mit dem Modbus-Server-Beispiel oder einem anderen Modbus-Gerät verwendet werden, das entweder über TCP oder einen seriellen Anschluss verbunden ist.

Wichtige Klassen, die in diesem Beispiel verwendet werden:

Modbus-Client mit Verbindungseinstellungen, Lese-/Schreibbereichen und Ergebnisanzeige mit Registeradressen und Hexadezimalwerten

Erstellen eines QModbusClient

Für die Kommunikation ist eine Instanz von ` QModbusClient ` erforderlich. Je nach angegebenem Verbindungstyp kann das Beispiel eine Instanz von ` QModbusRtuSerialClient ` (für serielle Kommunikation) oder von ` QModbusTcpClient ` (für TCP-basierte Kommunikation) erstellen.

    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"));
    }

Sobald der Client erstellt ist, verwenden Sie die Methode ` setConnectionParameter()` zur Festlegung der Verbindungsparameter. Die Parameter variieren je nach Kommunikationstyp:

        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);

Nachdem der Client erstellt und alle Parameter festgelegt wurden, stellen Sie mithilfe von QModbusClient::connectDevice() eine Verbindung zum Modbus-Netzwerk her.

Daten lesen

Um Daten vom Modbus-Server zu lesen, muss der Client eine Serveradresse sowie die Parameter der Objekte angeben, die er lesen möchte:

Die Objektparameter werden durch die Klasse ` QModbusDataUnit ` dargestellt:

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);
}

Sobald die Parameter erfasst sind, wird die Methode ` sendReadRequest()` verwendet, um die eigentliche Anfrage zu senden. Die Methode gibt ein ` QModbusReply ` zurück, das asynchron verarbeitet werden sollte; daher wird das Signal ` QModbusReply::finished()` verwendet, um zu prüfen, wann die Antwort bereitsteht.

    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);
    }

Sobald das Signal „ QModbusReply::finished()“ empfangen wurde, kann das Antwortobjekt verwendet werden, um die Daten abzurufen oder auf Lesefehler zu prüfen:

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();
}

Daten schreiben

Um die Daten an den Modbus-Server zu schreiben, muss der Client die Serveradresse sowie die Parameter der Objekte angeben, die er schreiben möchte. Wie beim Lesen der Daten wird die Klasse ` QModbusDataUnit ` verwendet, um die Informationen über die zu schreibenden Daten darzustellen. Diesmal enthalten die Daten auch den gewünschten ` values`. Die Methode ` sendWriteRequest()` wird verwendet, um die gewünschten Daten zu schreiben:

    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);
    }

Wie beim Lesen der Daten wird das zurückgegebene ` QModbusReply `-Objekt verwendet, um auf Schreibfehler zu prüfen.

Ausführen des Beispiels

Sie können das Beispiel wie folgt ausführen:

Beispielprojekt @ code.qt.io

© 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.