Modbus-Client

Das Beispiel implementiert eine Modbus-Client-Anwendung.

Das Beispiel agiert als Modbus-Client und sendet Modbus-Anfragen über die serielle Leitung oder TCP. Der gezeigte Dialog erlaubt 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 die serielle Schnittstelle angeschlossen ist.

In diesem Beispiel verwendete Schlüsselklassen:

Erstellen eines QModbusClient

Eine Instanz von QModbusClient ist erforderlich, um eine Kommunikation durchzuführen. Je nach dem angegebenen Verbindungstyp kann das Beispiel eine QModbusRtuSerialClient (für serielle Kommunikation) oder eine QModbusTcpClient (für TCP-basierte Kommunikation) instanziieren.

    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(), um die Verbindungsparameter anzugeben. Die Parameter sind je nach Kommunikationstyp unterschiedlich:

        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 wurde und alle Parameter angegeben wurden, verwenden Sie QModbusClient::connectDevice(), um eine Verbindung zum Modbus-Netzwerk herzustellen.

Daten lesen

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

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 bereit ist.

    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 zu erhalten 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 und 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 die gewünschte 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

Zum Ausführen des Beispiels von Qt Creatorauszuführen, öffnen Sie den Modus Welcome und wählen Sie das Beispiel aus Examples aus. Weitere Informationen finden Sie unter Erstellen und Ausführen eines Beispiels.

Beispielprojekt @ code.qt.io

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