Sur cette page

Serveur Modbus

Cet exemple met en œuvre une application de serveur Modbus.

L'exemple fait office de serveur Modbus. Il reçoit des requêtes Modbus standard, ajuste ses états internes en fonction de la requête et renvoie la réponse appropriée.

Cet exemple doit être utilisé conjointement avec l’exemple de client Modbus. Il doit être lancé et mis en état d’écoute avant le démarrage de l’exemple de client Modbus. Les interactions ultérieures entre les deux exemples s’effectuent via le protocole Modbus.

Classes clés utilisées dans cet exemple :

Serveur Modbus avec les paramètres de connexion, les cases à cocher « Bobines » et « Entrées discrètes », ainsi que les colonnes « Registres d'entrée » et « Registres de maintien »

Création d'un QModbusServer

Une instance de ` QModbusServer ` est requise pour établir toute communication. En fonction du type de connexion spécifié, l’exemple peut instancier un ` QModbusRtuSerialServer ` (pour la communication série) ou un ` QModbusTcpServer ` (pour la communication TCP).

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

Une fois le serveur créé, la carte des registres est définie à l’aide de la méthode QModbusServer::setMap(). Cette carte des registres est utilisée par les applications clientes pour lire et écrire les données du serveur.

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

Ensuite, les paramètres de communication et l’adresse du serveur sont spécifiés. Les paramètres de communication dépendent du type de communication :

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

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

Modification des valeurs locales

L'exemple permet de modifier les valeurs de tous les paramètres pris en charge ( register types ) à l'aide des listes déroulantes ou des champs de saisie fournis. Une fois la valeur mise à jour dans l'interface utilisateur, la méthode QModbusServer::setData() est utilisée pour mettre à jour la valeur réelle sur le serveur :

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

Gestion des écritures à distance

Les clients Modbus sont capables de mettre à jour les paramètres « Coils » et « HoldingRegisters » en envoyant des requêtes d’écriture. Une fois la valeur mise à jour côté serveur à l’aide d’une telle requête, un signal « QModbusServer::dataWritten() » est émis.

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

L'exemple de serveur Modbus s'abonne à ce signal, extrait les valeurs mises à jour et actualise l'interface utilisateur en conséquence :

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

Exécution de l’exemple

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

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