Qt ModbusTCP ModbusRTU 使用同步读和异步写
生活随笔
收集整理的這篇文章主要介紹了
Qt ModbusTCP ModbusRTU 使用同步读和异步写
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
使用Qt自帶的庫開發,添加相關頭文件
#include <QModbusTcpClient> #include <QModbusReply> #include <QSerialPort> #include <QModbusDataUnit> #include <QModbusRtuSerialMaster>一、寄存器說明
Modbus寄存器的操作包括讀寫和只讀。具體如下:
enum RegisterType {Invalid,DiscreteInputs,Coils,InputRegisters,HoldingRegisters};分別叫做:
- 離散輸入寄存器(只讀,通常為開關量輸入)
- 線圈寄存器(讀寫,一般為繼電器的控制)
- 輸入寄存器(只讀,一般為模擬量輸入)
- 保持寄存器(讀寫,一般狀態參數控制)
二、同步讀取
QT采用事件處理機制,由于Modbus讀取過程通常有時延,Qt機制不適合采用while延時等待讀取的方式。網上大多采用的是基于ModbusReply的Finished信號,做異步處理。導致在獲取寄存器數據時候比較麻煩。因此,可以考慮使用事件循環做同步處理。
讀寄存器數據的接口:
QVector<quint16> MainWindow::readModbusTcpUnit(QModbusDataUnit::RegisterType type, int startAddr, int numbers, int serverID, bool *isOK)- type:指明讀取的類型,由RegisterType類型定義
- startAddr:起始地址
- numbers:讀取的數量
- serverID:服務器的ID
- isOK:當前操作是否成功
- 返回值:QVector<quint16> 類型,讀取的數據放在向量中?
以下是具體實現:
QVector<quint16> MainWindow::readModbusTcpUnit(QModbusDataUnit::RegisterType type, int startAddr, int numbers, int serverID, bool *isOK) {QVector<quint16> results;results.clear();if (mModbusClient->state() != QModbusDevice::ConnectedState) {*isOK = false;return results;}QModbusDataUnit readUnit(type, startAddr, static_cast<quint16>(numbers));auto *reply = mModbusClient->sendReadRequest(readUnit, serverID);if (!reply->isFinished()) {QEventLoop loop;connect(reply, &QModbusReply::finished,&loop,&QEventLoop::quit);eventLoop.exec();}if (reply->error() == QModbusDevice::NoError) {const QModbusDataUnit unit = reply->result();QString strType;switch (type){case QModbusDataUnit::Coils: strType = "Coils"; break;case QModbusDataUnit::DiscreteInputs: strType = "DiscreteInputs"; break;case QModbusDataUnit::HoldingRegisters: strType = "HoldingRegisters"; break;case QModbusDataUnit::InputRegisters: strType = "InputRegisters"; break;}qDebug()<<"read "<<strType<< " startAddr = "<<startAddr<<" numbers = "<<numbers<<" values = " <<unit.values();*isOK = true;results = unit.values();} else {*isOK = false;}delete reply;return results; }使用方法:
/** bool isOK;* QVector<quint16> readUnit = readModbusTcpUnit(QModbusDataUnit::Coils, 0, 10, SERVER_ID, &isOK);* QVector<quint16> readUnit = readModbusTcpUnit(QModbusDataUnit::DiscreteInputs, 0, 10, SERVER_ID, &isOK);* QVector<quint16> readUnit = readModbusTcpUnit(QModbusDataUnit::HoldingRegisters, 0, 10, SERVER_ID, &isOK);* QVector<quint16> readUnit = readModbusTcpUnit(QModbusDataUnit::InputRegisters, 0, 10, SERVER_ID, &isOK); */三、異步寫
寫寄存器只有Coils和HoldingRegisters可以操作,寫操作使用異步執行。
接口如下:
bool MainWindow::writeModbusTcpCoils(QVector<quint16> coilsValues, int startAddr, int numbers, int serverID)- coilsValues:向量,需要寫入的值;
- startAddr:起始地址
- numbers:需要寫寄存器的數量
- serverID:服務器的ID
以寫線圈為例,實現如下:
void MainWindow::writeModbusTcpCoils(QVector<quint16> coilsValues, int startAddr, int numbers, int serverID) {if (coilsValues.size() < numbers){qDebug()<<"error : coilsValue size < numbers";return;}if (mModbusClient->state() != QModbusDevice::ConnectedState) {qDebug()<<"error : disConnectedState";return;}QModbusDataUnit writeUnit(QModbusDataUnit::Coils, startAddr, static_cast<quint16>(numbers));for (int valueIdx = 0; valueIdx < writeUnit.valueCount(); ++valueIdx) {writeUnit.setValue(valueIdx, coilsValues.at(valueIdx));}auto *reply = mModbusClient->sendWriteRequest(writeUnit, serverID);if (!reply->isFinished()) {connect(reply, &QModbusReply::finished, this, [this, reply]() {if (reply->error() == QModbusDevice::ProtocolError) {qDebug() << “ProtocolError”;} else if (reply->error() != QModbusDevice::NoError) {qDebug() << “Error”;}});}reply->deleteLater(); }使用方法:
/** QVector<quint16> values;* values.push_back(1);* values.push_back(0);* values.push_back(1);* writeModbusTcpCoils(values, 0, 3, SERVER_ID);* writeModbusTcpCoils(values, 3, 2, SERVER_ID); */寫保持寄存器和寫線圈類似,不在贅述。
總結
以上是生活随笔為你收集整理的Qt ModbusTCP ModbusRTU 使用同步读和异步写的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java文字版格斗游戏
- 下一篇: java变量不声明可以直接使用吗_我们可