Sur cette page

Client Modbus

Cet exemple implémente une application client Modbus.

L'exemple fait office de client Modbus envoyant des requêtes Modbus via une ligne série ou TCP. La boîte de dialogue affichée permet de définir des requêtes standard et affiche les réponses reçues.

Cet exemple doit être utilisé conjointement avec l'exemple de serveur Modbus ou avec un autre périphérique Modbus connecté soit via TCP, soit via un port série.

Classes clés utilisées dans cet exemple :

Client Modbus avec paramètres de connexion, sections de lecture/écriture et affichage des résultats indiquant les adresses de registres avec leurs valeurs hexadécimales

Création d'un QModbusClient

Une instance de ` QModbusClient ` est nécessaire pour établir toute communication. En fonction du type de connexion spécifié, l’exemple peut instancier un ` QModbusRtuSerialClient ` (pour la communication série) ou un ` QModbusTcpClient ` (pour la communication via 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"));
    }

Une fois le client créé, utilisez la méthode setConnectionParameter() pour spécifier les paramètres de connexion. Ces paramètres varient en fonction du type de communication :

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

Une fois le client créé et tous les paramètres spécifiés, utilisez QModbusClient::connectDevice() pour vous connecter au réseau Modbus.

Lecture des données

Pour lire des données depuis un serveur Modbus, le client doit spécifier une adresse de serveur ainsi que les paramètres des objets qu’il souhaite lire :

Les paramètres des objets sont représentés par la classe ` 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);
}

Une fois les paramètres collectés, la méthode sendReadRequest() est utilisée pour envoyer la requête proprement dite. La méthode renvoie un objet QModbusReply qui doit être traité de manière asynchrone ; le signal QModbusReply::finished() est donc utilisé pour vérifier quand la réponse est prête.

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

Une fois le signal ` QModbusReply::finished()` reçu, l’objet `reply` peut être utilisé pour récupérer les données ou pour vérifier s’il y a des erreurs de lecture :

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

Écriture de données

Pour écrire des données sur le serveur Modbus, le client doit spécifier l’adresse du serveur ainsi que les paramètres des objets qu’il souhaite écrire. Comme pour la lecture des données, la classe ` QModbusDataUnit ` est utilisée pour représenter les informations relatives aux données à écrire. Cette fois-ci, les données incluent également l’ values souhaité. La méthode ` sendWriteRequest()` est utilisée pour écrire les données souhaitées :

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

Comme pour la lecture des données, l’objet ` QModbusReply ` renvoyé est utilisé pour vérifier s’il y a des erreurs d’écriture.

Exécution de l'exemple

Vous pouvez exécuter l’exemple à partir de :

Exemple de projet @ 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.