Modbus-Server

Das Beispiel implementiert eine Modbus-Server-Anwendung.

Das Beispiel agiert als Modbus-Server. Es empfängt Standard-Modbus-Anfragen, passt seine internen Zustände auf der Grundlage der Anfrage an und antwortet mit der entsprechenden Antwort.

Dieses Beispiel muss in Verbindung mit dem Modbus-Client-Beispiel verwendet werden. Dieses Beispiel sollte gestartet und in den Listen-Status versetzt werden, bevor das Modbus-Client-Beispiel gestartet wird. Nachfolgende Interaktionen zwischen den beiden Beispielen verwenden das Modbus-Protokoll.

In diesem Beispiel verwendete Schlüsselklassen:

Erstellen eines QModbusServers

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

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

Sobald der Server erstellt ist, wird die Registerkarte mit der Methode QModbusServer::setMap() festgelegt. Diese Registerkarte wird von Client-Anwendungen zum Lesen und Schreiben von Serverdaten verwendet.

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

Danach werden die Kommunikationsparameter und die Serveradresse festgelegt. Die Kommunikationsparameter hängen von der Art der Kommunikation ab:

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

Nachdem der Server erstellt wurde und alle Parameter festgelegt sind, verwenden Sie QModbusServer::connectDevice(), um eine Verbindung zum Modbus-Netzwerk herzustellen.

Ändern lokaler Werte

Das Beispiel ermöglicht die Änderung der Werte aller unterstützten register types mit Hilfe der bereitgestellten Kombinationsfelder oder Zeilenbearbeitungen. Sobald der Wert in der Benutzeroberfläche aktualisiert wurde, wird die Methode QModbusServer::setData() verwendet, um den tatsächlichen Wert auf dem Server zu aktualisieren:

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

Handhabung von Remote Writes

Die Modbus-Clients sind in der Lage, Coils und HoldingRegisters durch das Senden von Schreibanforderungen zu aktualisieren. Sobald der Wert auf der Serverseite durch eine solche Anforderung aktualisiert wird, wird ein QModbusServer::dataWritten()-Signal ausgegeben.

        connect(modbusDevice, &QModbusServer::dataWritten,
                this, &MainWindow::updateWidgets);

Das Modbus-Server-Beispiel stellt eine Verbindung zu diesem Signal her, extrahiert die aktualisierten Werte und aktualisiert die Benutzeroberfläche entsprechend:

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

Ausführen des Beispiels

Zum Ausführen des Beispiels von Qt Creatorzu starten, öffnen Sie den Modus Welcome und wählen Sie das Beispiel unter 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.