QT Modbus 服务端

        该示例实现了Modbus服务器应用程序。
        该示例充当Modbus服务器。它接收标准的Modbus请求,根据请求调整其内部状态,并以适当的回复进行响应。
        此示例必须与Modbus客户端示例结合使用。在启动Modbus客户端示例之前,应启动此示例并将其置于监听状态。两个示例之间的后续交互使用Modbus协议。
        本例中使用的关键类:

        >QModbusServer

        >QModbusDataUnit

创造一个QModbusServer

        执行任何通信都需要QModbusServer的实例。根据指定的连接类型,该示例可以实例化QModbusRtuSerialServer(用于串行通信)或QModbusTcpServer(用于基于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"));
    }

        创建服务器后,使用QModbusServer::setMap()方法设置寄存器映射。客户端应用程序使用此寄存器映射来读取和写入服务器数据。

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

        之后,指定通信参数和服务器地址。通信参数取决于通信类型:

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

        创建服务器并指定所有参数后,使用QModbusServer::connectDevice()连接到Modbus网络。

改变本地值

        该示例允许通过使用提供的组合框或行编辑来更改所有支持的寄存器类型的值。在UI中更新值后,QModbusServer::setData()方法用于更新服务器上的实际值:

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

处理远程写入

        Modbus客户端能够通过发送写请求来更新线圈和保持寄存器。一旦在服务器端使用此类请求更新了值,就会发出QModbusServer::dataWritten()信号。

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

        Modbus服务器示例连接到此信号,提取更新的值并相应地更新UI:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值