Análisis del ejemplo QModbus en Qt: configuración y conexión de esclavo serie

Fundamentos de Modbus

Modbus es un protocolo maestro-esclavo muy utilizado en automatización industrial para intercambiar información entre controladores y sensores/actuadores. Fue creado en 1979 por Modicon (hoy Schneider Electric) y destaca por su simplicidad, fiabilidad y ser de dominio público.

Modos de transmisión

  • ASCII: cada byte se codifica como dos caracteres ASCII; útil para enlaces muy lentos.
  • RTU: formato binario compacto que maximiza el throughput en puerto serie.
  • TCP/IP: encapsula las tramas Modbus sobre TCP, permitiendo comunicación en red Ethernet.

Funcionamiento básico

El maestro inicia siempre la comunicación enviando una petición con un código de función y la dirección del esclavo. El esclavo responde con los datos solicitados o un código de error. Las funciones habituales son lectura/escritura de coils (salidas digitales) y registros (valores analógicos).

Configuración del puerto serie con SettingsDialog

El diálogo SettingsDialog centraliza los parámetros serie que necesita QModbusDevice cuando se trabaja en modo RTU.

Definición de la estructuar Settings

struct SerialCfg {
#if QT_CONFIG(modbus_serialport)
    int parity  = QSerialPort::EvenParity;
    int baud    = QSerialPort::Baud19200;
    int dataBit = QSerialPort::Data8;
    int stopBit = QSerialPort::OneStop;
#endif
};

Diálogo de configuración

class SettingsDialog : public QDialog {
    Q_OBJECT
public:
    explicit SettingsDialog(QWidget *parent = nullptr);
    ~SettingsDialog();

    SerialCfg parameters() const { return m_cfg; }

private:
    SerialCfg m_cfg;
    Ui::SettingsDialog *ui;
};

El constructor inicializa los combos con los valores por defecto y conecta el botón Aplicar para actualizar la estructura interna:

connect(ui->btnApply, &QPushButton::clicked, this, [this] {
#if QT_CONFIG(modbus_serialport)
    m_cfg.parity  = ui->cmbParity->currentIndex();
    if (m_cfg.parity > 0) ++m_cfg.parity;;   // ajuste interno de Qt
    m_cfg.baud    = ui->cmbBaud->currentText().toInt();
    m_cfg.dataBit = ui->cmbDataBits->currentText().toInt();
    m_cfg.stopBit = ui->cmbStopBits->currentText().toInt();
#endif
    accept();
});

Establecimiento de la conexión en MainWindow

La ventana principal gestiona dos tipos de conexión: serie (RTU) y red (TCP). El método onConnectButtonClicked decide qué camino seguir según el valor del combo connectType.

void MainWindow::toggleConnection()
{
    const bool conectar =
        (modbusDevice->state() == QModbusDevice::UnconnectedState);

    statusBar()->clearMessage();

    if (conectar) {
        const auto tipo =
            static_cast<ModbusConnection>(ui->cmbTipo->currentIndex());

        if (tipo == Serial) {
            modbusDevice->setConnectionParameter(
                QModbusDevice::SerialPortNameParameter,
                ui->edPuerto->text());

#if QT_CONFIG(modbus_serialport)
            const SerialCfg cfg = settingsDlg->parameters();
            modbusDevice->setConnectionParameter(
                QModbusDevice::SerialParityParameter,  cfg.parity);
            modbusDevice->setConnectionParameter(
                QModbusDevice::SerialBaudRateParameter, cfg.baud);
            modbusDevice->setConnectionParameter(
                QModbusDevice::SerialDataBitsParameter, cfg.dataBit);
            modbusDevice->setConnectionParameter(
                QModbusDevice::SerialStopBitsParameter, cfg.stopBit);
#endif
        } else {
            const QUrl url = QUrl::fromUserInput(ui->edPuerto->text());
            modbusDevice->setConnectionParameter(
                QModbusDevice::NetworkPortParameter, url.port());
            modbusDevice->setConnectionParameter(
                QModbusDevice::NetworkAddressParameter, url.host());
        }

        modbusDevice->setServerAddress(ui->edEsclavo->text().toInt());

        if (!modbusDevice->connectDevice()) {
            statusBar()->showMessage(
                tr("Falló la conexión: ") + modbusDevice->errorString(), 5000);
        } else {
            ui->actConectar->setEnabled(false);
            ui->actDesconectar->setEnabled(true);
        }
    } else {
        modbusDevice->disconnectDevice();
        ui->actConectar->setEnabled(true);
        ui->actDesconectar->setEnabled(false);
    }
}

Con esta estructura, la aplicación puede operar como maestro Modbus tanto en redes seriales como Ethernet, delegando la configuración física a un diálogo reutilizable.

Etiquetas: Qt QModbus Modbus RTU Modbus TCP serial port

Publicado el 8-5 06:03