【Qt】modbus之TCP模式读操作
生活随笔
收集整理的這篇文章主要介紹了
【Qt】modbus之TCP模式读操作
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
00. 目錄
文章目錄
- 00. 目錄
- 01. 概述
- 02. 開發環境
- 03. 讀Coils程序示例
- 04. 讀DiscreteInputs程序示例
- 05. 讀InputRegisters程序示例
- 06. 讀HoldingRegisters程序示例
- 07. 綜合示例
- 08. 程序下載
- 09. 附錄
01. 概述
Qt中幾個常用的串口modbus類
QModbusRtuSerialSlave //modbus串口通信方式下的服務器類 QModbusRtuSerialMaster //串口通信方式下的客戶端類 QModbusServer // QModbusServer類接收和處理modbus的請求。 QModbusDataUnit //存儲接收和發送數據的類,數據類型為1bit和16bit QModbusReply //客戶端訪問服務器后得到的回復(如客戶端讀服務器數據時包含數據信息)02. 開發環境
Windows系統:Windows10
Qt版本:Qt5.15或者Qt6
Pro配置文件如下
QT += core gui serialbus serialportgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \widget.cppHEADERS += \widget.h# Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target03. 讀Coils程序示例
widget.h文件
#ifndef WIDGET_H #define WIDGET_H#include <QWidget>//前向聲明 class QModbusClient; class QModbusReply;QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;QModbusClient *modbusDevice = nullptr;private slots:void onReadReady();void onModbusStateChanged(int state);void on_btnConnect_clicked();void on_btnCoil_clicked();void on_btnDiscreteInputs_clicked();void on_btnInputRegisters_clicked();void on_btnHoldingRegisters_clicked(); }; #endif // WIDGET_Hwidget.cpp文件
#include "widget.h" #include "ui_widget.h" #include <QDebug> #include <QModbusTcpClient>//構造函數 Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//1. 創建QModbusDevice對象modbusDevice = new QModbusTcpClient(this);//禁用所有的讀操作ui->btnCoil->setEnabled(false);ui->btnDiscreteInputs->setEnabled(false);ui->btnHoldingRegisters->setEnabled(false);ui->btnInputRegisters->setEnabled(false);connect(modbusDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {qDebug() << "new Error: " << modbusDevice->errorString();});if (nullptr == modbusDevice){qDebug() << "Cannot Create Modbus Client";}else{connect(modbusDevice, &QModbusClient::stateChanged,this, &Widget::onModbusStateChanged);}}//析構函數 Widget::~Widget() {if (modbusDevice){modbusDevice->disconnectDevice();}delete modbusDevice;delete ui; }void Widget::onReadReady() {auto reply = qobject_cast<QModbusReply*>(sender());if (nullptr == reply){return;}//判斷是否出錯if (reply->error() == QModbusDevice::NoError){//讀取響應數據const QModbusDataUnit responseData = reply->result();qDebug() << "讀到數據為:" << responseData.values();}else if (reply->error() == QModbusDevice::ProtocolError){qDebug() << "Read response Protocol error: " << reply->errorString();}else{qDebug() << "Read response Error: " << reply->errorString();}//刪除replyreply->deleteLater(); }void Widget::onModbusStateChanged(int state) {//判斷Modbus設備連接是否處于連接狀態if (state == QModbusDevice::UnconnectedState){qDebug() << "TCP Client連接到Server 未連接";ui->btnConnect->setText(tr("連接"));ui->btnCoil->setEnabled(false);ui->btnDiscreteInputs->setEnabled(false);ui->btnHoldingRegisters->setEnabled(false);ui->btnInputRegisters->setEnabled(false);}else if (state == QModbusDevice::ConnectingState){qDebug() << "TCP Client正在連接Server";}else if (state == QModbusDevice::ConnectedState){qDebug() << "TCP Client已經連接到Server";ui->btnConnect->setText(tr("斷開連接"));ui->btnCoil->setEnabled(true);ui->btnDiscreteInputs->setEnabled(true);ui->btnHoldingRegisters->setEnabled(true);ui->btnInputRegisters->setEnabled(true);}else if (state == QModbusDevice::ClosingState){qDebug() << "設備已經被關閉";} }//連接按鈕槽函數 void Widget::on_btnConnect_clicked() {if (!modbusDevice){return;}if (modbusDevice->state() != QModbusDevice::ConnectedState){modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "127.0.0.1");modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, 10086);//設置超時時間modbusDevice->setTimeout(1000); //1秒//設置失敗重試次數modbusDevice->setNumberOfRetries(3);//連接到服務端bool ok = modbusDevice->connectDevice();if (!ok){qDebug() << "modbusDevice->connectDevice failed";}}else{//斷開連接modbusDevice->disconnectDevice();ui->btnConnect->setText(tr("連接"));ui->btnCoil->setEnabled(false);ui->btnDiscreteInputs->setEnabled(false);ui->btnHoldingRegisters->setEnabled(false);ui->btnInputRegisters->setEnabled(false);}}//讀線圈 void Widget::on_btnCoil_clicked() {//QModbusDataUnit::Coils 從地址0開始讀取10個線圈值QModbusDataUnit data(QModbusDataUnit::Coils, 0, 10);auto reply = modbusDevice->sendReadRequest(data, 0x1);if (nullptr == reply){qDebug() << "發送請求數據失敗: " << modbusDevice->errorString();}else{if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);}else{//broadcast replies return immediatelydelete reply;}} }//讀離散輸入 void Widget::on_btnDiscreteInputs_clicked() {}//讀輸入寄存器 void Widget::on_btnInputRegisters_clicked() {}//讀保持寄存器 void Widget::on_btnHoldingRegisters_clicked() {}執行結果
15:18:15: Starting D:\ProgramData\Qt\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test1.exe ... TCP Client正在連接Server TCP Client已經連接到Server 讀到數據為: QVector(0, 0, 1, 0, 0, 0, 1, 0, 1, 0) 設備已經被關閉 TCP Client連接到Server 未連接 15:18:36: D:\ProgramData\Qt\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test1.exe exited with code 004. 讀DiscreteInputs程序示例
widget.h文件
#ifndef WIDGET_H #define WIDGET_H#include <QWidget>//前向聲明 class QModbusClient; class QModbusReply;QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;QModbusClient *modbusDevice = nullptr;private slots:void onReadReady();void onModbusStateChanged(int state);void on_btnConnect_clicked();void on_btnCoil_clicked();void on_btnDiscreteInputs_clicked();void on_btnInputRegisters_clicked();void on_btnHoldingRegisters_clicked(); }; #endif // WIDGET_Hwidget.cpp文件
//讀離散輸入 void Widget::on_btnDiscreteInputs_clicked() {//QModbusDataUnit::DiscreteInputs 從地址0開始讀取10個離散輸入值QModbusDataUnit data(QModbusDataUnit::DiscreteInputs, 0, 10);auto reply = modbusDevice->sendReadRequest(data, 0x1);if (nullptr == reply){qDebug() << "發送請求數據失敗: " << modbusDevice->errorString();}else{if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);}else{//broadcast replies return immediatelydelete reply;}} }執行結果
15:25:14: Starting D:\ProgramData\Qt\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test1.exe ... TCP Client正在連接Server TCP Client已經連接到Server 讀到數據為: QVector(1, 1, 1, 1, 1, 0, 0, 0, 0, 0) 設備已經被關閉 TCP Client連接到Server 未連接05. 讀InputRegisters程序示例
widget.h文件
#ifndef WIDGET_H #define WIDGET_H#include <QWidget>//前向聲明 class QModbusClient; class QModbusReply;QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;QModbusClient *modbusDevice = nullptr;private slots:void onReadReady();void onModbusStateChanged(int state);void on_btnConnect_clicked();void on_btnCoil_clicked();void on_btnDiscreteInputs_clicked();void on_btnInputRegisters_clicked();void on_btnHoldingRegisters_clicked(); }; #endif // WIDGET_Hwidget.cpp文件
//讀輸入寄存器 void Widget::on_btnInputRegisters_clicked() {//QModbusDataUnit::InputRegisters 從地址0開始讀取10個輸入寄存器的值QModbusDataUnit data(QModbusDataUnit::InputRegisters, 0, 10);auto reply = modbusDevice->sendReadRequest(data, 0x1);if (nullptr == reply){qDebug() << "發送請求數據失敗: " << modbusDevice->errorString();}else{if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);}else{//broadcast replies return immediatelydelete reply;}} }執行結果
15:28:06: Starting D:\ProgramData\Qt\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test1.exe ... TCP Client正在連接Server TCP Client已經連接到Server 讀到數據為: QVector(0, 12, 0, 11, 0, 0, 13, 0, 0, 0) 設備已經被關閉 TCP Client連接到Server 未連接06. 讀HoldingRegisters程序示例
widget.h文件
#ifndef WIDGET_H #define WIDGET_H#include <QWidget>//前向聲明 class QModbusClient; class QModbusReply;QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;QModbusClient *modbusDevice = nullptr;private slots:void onReadReady();void onModbusStateChanged(int state);void on_btnConnect_clicked();void on_btnCoil_clicked();void on_btnDiscreteInputs_clicked();void on_btnInputRegisters_clicked();void on_btnHoldingRegisters_clicked(); }; #endif // WIDGET_Hwidget.cpp文件
//讀保持寄存器 void Widget::on_btnHoldingRegisters_clicked() {//從地址0開始讀取10個保持寄存器的值QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, 0, 10);auto reply = modbusDevice->sendReadRequest(data, 0x1);if (nullptr == reply){qDebug() << "發送請求數據失敗: " << modbusDevice->errorString();}else{if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);}else{//broadcast replies return immediatelydelete reply;}} }執行結果
15:29:35: Starting D:\ProgramData\Qt\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test1.exe ... TCP Client正在連接Server TCP Client已經連接到Server 讀到數據為: QVector(0, 0, 11, 12, 13, 14, 15, 0, 0, 111) 設備已經被關閉 TCP Client連接到Server 未連接07. 綜合示例
程序界面
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-utd9gda4-1621496836516)(assets/image-20210520154331905.png)]
settingdialog.h文件
#ifndef SETTINGDIALOG_H #define SETTINGDIALOG_H#include <QDialog> #include <QtSerialPort>namespace Ui { class SettingDialog; }//串口設置相關類 class SettingDialog : public QDialog {Q_OBJECTpublic:struct Settings{//串口名QString serialName = "COM3";//校驗位int parity = QSerialPort::NoParity;//波特率int baud = QSerialPort::Baud19200;//數據位int dataBits = QSerialPort::Data8;//停止位int stopBits = QSerialPort::OneStop;//響應時間int responseTime = 1000;//重試次數int numberOfRetries = 3;};explicit SettingDialog(QWidget *parent = nullptr);~SettingDialog();//返回參數設置信息Settings settings() const;private slots:void on_btnApply_clicked();private:Ui::SettingDialog *ui;Settings m_settings; };#endif // SETTINGDIALOG_Hsettingdialog.cpp文件
#include "settingdialog.h" #include "ui_settingdialog.h"//構造函數 SettingDialog::SettingDialog(QWidget *parent) :QDialog(parent),ui(new Ui::SettingDialog) {ui->setupUi(this);//設置默認參數信息ui->serialNameLineEdit->setText(tr("COM3"));ui->parityComboBox->setCurrentIndex(0);ui->baudComboBox->setCurrentText(QString::number(m_settings.baud));ui->dataBitComboBox->setCurrentText(QString::number(m_settings.dataBits));ui->stopBitComboBox->setCurrentText(QString::number(m_settings.stopBits));ui->spinBoxTimeOut->setValue(m_settings.responseTime);ui->spinBoxRetry->setValue(m_settings.numberOfRetries);}//析構函數 SettingDialog::~SettingDialog() {delete ui; }//返回參數信息 SettingDialog::Settings SettingDialog::settings() const {return m_settings; }//引用按鈕槽函數 void SettingDialog::on_btnApply_clicked() {m_settings.serialName = ui->serialNameLineEdit->text();m_settings.parity = ui->parityComboBox->currentText().toInt();m_settings.baud = ui->baudComboBox->currentText().toInt();m_settings.dataBits = ui->dataBitComboBox->currentText().toInt();m_settings.stopBits = ui->stopBitComboBox->currentText().toInt();m_settings.responseTime = ui->spinBoxTimeOut->value();m_settings.numberOfRetries = ui->spinBoxRetry->value();//隱藏參數設置對話框hide(); }mainwindow.h文件
#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QModbusDataUnit>QT_BEGIN_NAMESPACEnamespace Ui {class MainWindow; }class SettingDialog; class QModbusClient; class QModbusReply;QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();//信號與槽進行關聯void initActions();//讀請求數據包封裝QModbusDataUnit readRequest() const;private slots:void onConnectButtonClicked();void onConnectTypeChanged(int);void onModbusStateChanged(int state);void onReadButtonClicked();void onReadReady();private:Ui::MainWindow *ui = nullptr;SettingDialog *m_settingDialog = nullptr;QModbusClient *modbusDevice = nullptr;QModbusReply *reply = nullptr;}; #endif // MAINWINDOW_Hmainwindow.cpp文件
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QMessageBox> #include "settingdialog.h" #include <QModbusRtuSerialMaster> #include <QModbusReply> #include <QStandardItemModel> #include <QModbusDataUnit> #include <QModbusTcpClient>//連接類型枚舉變量 enum ModbusConnection {Serial,Tcp };MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);//創建對象m_settingDialog = new SettingDialog(this);//初始化信號與槽initActions();//創建寫模型writeModel = new WriteRegisterModel(this);writeModel->setStartAddress(ui->sbWriteStartAddr->value());writeModel->setNumberOfValues(ui->cbWriteCount->currentText());//MVCui->treeViewWrite->setModel(writeModel);//隱藏第二列ui->treeViewWrite->hideColumn(2);connect(writeModel, &WriteRegisterModel::updateViewport,ui->treeViewWrite->viewport(), QOverload<>::of(&QWidget::update));//默認為串口連接方式ui->cbConnType->setCurrentIndex(0);onConnectTypeChanged(0);auto model = new QStandardItemModel(10, 1, this);for (int i = 0; i < 10; i++){model->setItem(i, new QStandardItem(QStringLiteral("%1").arg(i + 1)));}ui->cbWriteCount->setModel(model);ui->cbWriteCount->setCurrentText("10");connect(ui->cbWriteCount, &QComboBox::currentTextChanged,writeModel, &WriteRegisterModel::setNumberOfValues);auto valueChanged = QOverload<int>::of(&QSpinBox::valueChanged);connect(ui->sbWriteStartAddr, valueChanged, writeModel, &WriteRegisterModel::setStartAddress);connect(ui->sbWriteStartAddr, valueChanged, this, [this, model](int i){int lastIndex = 0;const int curIndex = ui->cbWriteCount->currentIndex();for (int j = 0; j < 10; j++){//設置使能if (j < (10 - i)){lastIndex = j;model->item(j)->setEnabled(true);}else{//設置禁用model->item(j)->setEnabled(false);}}if (curIndex > lastIndex){ui->cbWriteCount->setCurrentIndex(lastIndex);}}); }//析構函數 MainWindow::~MainWindow() {if (modbusDevice){modbusDevice->disconnectDevice();delete modbusDevice;}delete ui; }//信號與槽進行關聯s void MainWindow::initActions() {//使能部分功能ui->actionConnect->setEnabled(true);ui->actionDisconnect->setEnabled(false);ui->actionQuit->setEnabled(true);ui->actionOption->setEnabled(true);//禁用讀寫操作ui->btnRead->setEnabled(false);ui->btnWrite->setEnabled(false);ui->btnReadWrite->setEnabled(false);//信號與槽關聯connect(ui->btnConnect, &QPushButton::clicked,this, &MainWindow::onConnectButtonClicked);connect(ui->actionConnect, &QAction::triggered,this, &MainWindow::onConnectButtonClicked);connect(ui->actionDisconnect, &QAction::triggered,this, &MainWindow::onConnectButtonClicked);//讀操作按鈕槽函數關聯connect(ui->btnRead, &QPushButton::clicked,this, &MainWindow::onReadButtonClicked);connect(ui->btnWrite, &QPushButton::clicked,this, &MainWindow::onWriteButtonClicked);connect(ui->btnReadWrite, &QPushButton::clicked,this, &MainWindow::onReadWriteButtonClicked);connect(ui->cbRegisterType, QOverload<int>::of(&QComboBox::currentIndexChanged),this, &MainWindow::onWriteTableChanged);connect(ui->cbConnType, QOverload<int>::of(&QComboBox::currentIndexChanged),this, &MainWindow::onConnectTypeChanged);//退出菜單connect(ui->actionQuit, &QAction::triggered, this, &MainWindow::close);//顯示參數設置對話框connect(ui->actionOption, &QAction::triggered, m_settingDialog, &QDialog::show);connect(ui->actionAbout, &QAction::triggered, [=]() {QMessageBox::aboutQt(this, "About Qt");}); }//構建請求報文 QModbusDataUnit MainWindow::readRequest() const {//const auto type = static_cast<QModbusDataUnit::RegisterType>(ui->cbRegisterType->currentData().toInt());QModbusDataUnit::RegisterType type = QModbusDataUnit::Invalid;qDebug() << ui->cbRegisterType->currentText();if (ui->cbRegisterType->currentText() == QString("線圈")){type = QModbusDataUnit::Coils;}else if (ui->cbRegisterType->currentText() == QString("離散輸入")){type = QModbusDataUnit::DiscreteInputs;}else if (ui->cbRegisterType->currentText() == QString("輸入寄存器")){type = QModbusDataUnit::InputRegisters;}else if (ui->cbRegisterType->currentText() == QString("保持寄存器")){type = QModbusDataUnit::HoldingRegisters;}qDebug() << "請求報文類型: " << type;//獲取int startAddress = ui->spReadStartAddr->value();Q_ASSERT(startAddress >= 0 && startAddress < 10);quint16 numberOfEntries = ui->cbReadCount->currentText().toUShort();return QModbusDataUnit(type, startAddress, numberOfEntries); }//寫請求數據包封裝 QModbusDataUnit MainWindow::writeRequest() const {QModbusDataUnit::RegisterType type = QModbusDataUnit::Invalid;qDebug() << ui->cbRegisterType->currentText();if (ui->cbRegisterType->currentText() == QString("線圈")){type = QModbusDataUnit::Coils;}else if (ui->cbRegisterType->currentText() == QString("離散輸入")){type = QModbusDataUnit::DiscreteInputs;}else if (ui->cbRegisterType->currentText() == QString("輸入寄存器")){type = QModbusDataUnit::InputRegisters;}else if (ui->cbRegisterType->currentText() == QString("保持寄存器")){type = QModbusDataUnit::HoldingRegisters;}qDebug() << "請求報文類型: " << type;//獲取int startAddress = ui->sbWriteStartAddr->value();Q_ASSERT(startAddress >= 0 && startAddress < 10);quint16 numberOfEntries = ui->cbWriteCount->currentText().toUShort();//qDebug() << "Test: " << startAddress << " " << numberOfEntries;return QModbusDataUnit(type, startAddress, numberOfEntries); }//連接和斷開連接的槽函數 void MainWindow::onConnectButtonClicked() {if (!modbusDevice){return;}//清空狀態欄消息statusBar()->clearMessage();if (modbusDevice->state() != QModbusDevice::ConnectedState){auto type = static_cast<ModbusConnection>(ui->cbConnType->currentIndex());if (type == Serial){//設置串口連接信息modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,m_settingDialog->settings().serialName);modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,m_settingDialog->settings().parity);modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,m_settingDialog->settings().baud);modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,m_settingDialog->settings().dataBits);modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,m_settingDialog->settings().stopBits);}else{//TCP連接信息const QUrl url = QUrl::fromUserInput(ui->lineEditPort->text());modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter,url.port());modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter,url.host());}modbusDevice->setTimeout(m_settingDialog->settings().responseTime);modbusDevice->setNumberOfRetries(m_settingDialog->settings().numberOfRetries);if (!modbusDevice->connectDevice()){statusBar()->showMessage(tr("Connect failed..") + modbusDevice->errorString(), 5000);}else{statusBar()->showMessage(tr("Connect Successfully"), 5000);qDebug() << "連接OK";ui->actionConnect->setEnabled(false);ui->actionDisconnect->setEnabled(true);//使能讀寫操作ui->btnRead->setEnabled(true);ui->btnWrite->setEnabled(true);ui->btnReadWrite->setEnabled(true);}}else{//斷開連接modbusDevice->disconnectDevice();ui->actionConnect->setEnabled(true);ui->actionDisconnect->setDisabled(true);qDebug() << "斷開連接成功";//禁用讀寫操作ui->btnRead->setEnabled(false);ui->btnWrite->setEnabled(false);ui->btnReadWrite->setEnabled(false);} }//連接類型槽函數 TCP Serial void MainWindow::onConnectTypeChanged(int index) {//如果之前存在連接,則斷開連接,然后釋放內存if(modbusDevice){modbusDevice->disconnectDevice();delete modbusDevice;modbusDevice = nullptr;}auto type = static_cast<ModbusConnection>(index);if (type == Serial){modbusDevice = new QModbusRtuSerialMaster(this);qDebug() << "new QModbusRtuSerialMaster Ok";statusBar()->showMessage("new QModbusRtuSerialMaster Ok", 3000);}else if (type == Tcp){modbusDevice = new QModbusTcpClient(this);if (ui->lineEditPort->text().isEmpty())ui->lineEditPort->setText(QLatin1String("127.0.0.1:10086"));}else{statusBar()->showMessage("連接類型非法", 5000);}connect(modbusDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error){statusBar()->showMessage(modbusDevice->errorString(), 5000);});if (!modbusDevice){//分配空間失敗ui->btnConnect->setDisabled(true);if (type == Serial){statusBar()->showMessage(tr("創建Modbus Master失敗"), 5000);}else{statusBar()->showMessage(tr("創建Modbus Client失敗"), 5000);}}else{connect(modbusDevice, &QModbusClient::stateChanged,this, &MainWindow::onModbusStateChanged);}}//Modbus狀態改變槽函數 void MainWindow::onModbusStateChanged(int state) {//判斷Modbus設備連接是否處于連接狀態bool connected = (state != QModbusDevice::UnconnectedState);ui->actionConnect->setEnabled(!connected);ui->actionDisconnect->setEnabled(connected);if (QModbusDevice::UnconnectedState == state){ui->btnConnect->setText(tr("Connect"));}else{ui->btnConnect->setText(tr("Disconnect"));} }//讀操作槽函數 void MainWindow::onReadButtonClicked() {if (!modbusDevice){return;}ui->textEditRead->clear();statusBar()->clearMessage();//發送請求報文數據auto *reply = modbusDevice->sendReadRequest(readRequest(), ui->sbServerAddr->value());if (reply){if (!reply->isFinished()){//完畢之后 自動觸發槽函數connect(reply, &QModbusReply::finished, this, &MainWindow::onReadReady);}else{//廣播消息 不需要返回響應delete reply;}}else{statusBar()->showMessage(tr("Read Error: ") + modbusDevice->errorString(), 5000);}}//讀取數據 void MainWindow::onReadReady() {auto reply = qobject_cast<QModbusReply*>(sender());if (!reply){return;}if (reply->error() == QModbusDevice::NoError){const QModbusDataUnit data = reply->result();for (int i = 0, total = (int)data.valueCount(); i < total; i++){const QString str = tr("Address: %1 Value: %2").arg(data.startAddress() + i).arg(QString::number(data.value(i), data.registerType() <= QModbusDataUnit::Coils ? 10 : 16));ui->textEditRead->append(str);}}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(); }void MainWindow::onWriteButtonClicked() {if (!modbusDevice){return;}statusBar()->clearMessage();QModbusDataUnit writeData = writeRequest();QModbusDataUnit::RegisterType type = writeData.registerType();//qDebug() << "test: " << writeData.valueCount();for (int i = 0, total = (int)(writeData.valueCount()); i < total; i++){if (type == QModbusDataUnit::Coils){writeData.setValue(i, writeModel->m_coils[i + writeData.startAddress()]);}else{//qDebug() << "test: " << writeModel->m_holdingRegisters[i + writeData.startAddress()];writeData.setValue(i, writeModel->m_holdingRegisters[i + writeData.startAddress()]);}}qDebug() << "寫數據內容為:" << writeData.values();//發送請求報文數據auto *reply = modbusDevice->sendWriteRequest(writeData, ui->sbServerAddr->value());if (reply){if (!reply->isFinished()){//完畢之后 自動觸發槽函數connect(reply, &QModbusReply::finished, this, [this, reply]{if (reply->error() == QModbusDevice::ProtocolError){statusBar()->showMessage(tr("Write Protocaol response error: %1").arg(reply->errorString()), 5000);}else if (reply->error() != QModbusDevice::NoError){statusBar()->showMessage(tr("Write response error: %1").arg(reply->errorString()), 5000);}else{qDebug() << "寫響應的數據: " << reply->result().values();}reply->deleteLater();});}else{//廣播消息 不需要返回響應reply->deleteLater();}}else{statusBar()->showMessage(tr("Write Error: ") + modbusDevice->errorString(), 5000);} }//讀寫按鈕槽函數 void MainWindow::onReadWriteButtonClicked() {if (!modbusDevice){return;}statusBar()->clearMessage();QModbusDataUnit writeData = writeRequest();QModbusDataUnit::RegisterType type = writeData.registerType();//qDebug() << "test: " << writeData.valueCount();for (int i = 0, total = (int)(writeData.valueCount()); i < total; i++){if (type == QModbusDataUnit::Coils){writeData.setValue(i, writeModel->m_coils[i + writeData.startAddress()]);}else{//qDebug() << "test: " << writeModel->m_holdingRegisters[i + writeData.startAddress()];writeData.setValue(i, writeModel->m_holdingRegisters[i + writeData.startAddress()]);}}qDebug() << "寫數據內容為:" << writeData.values();//發送請求報文數據auto *reply = modbusDevice->sendReadWriteRequest(readRequest(), writeData, ui->sbServerAddr->value());if (reply){if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &MainWindow::onReadReady);//完畢之后 自動觸發槽函數connect(reply, &QModbusReply::finished, this, [this, reply]{if (reply->error() == QModbusDevice::ProtocolError){statusBar()->showMessage(tr("Write Protocaol response error: %1").arg(reply->errorString()), 5000);}else if (reply->error() != QModbusDevice::NoError){statusBar()->showMessage(tr("Write response error: %1").arg(reply->errorString()), 5000);}else{qDebug() << "寫響應的數據: " << reply->result().values();}reply->deleteLater();});}else{//廣播消息 不需要返回響應reply->deleteLater();}}else{statusBar()->showMessage(tr("Write Error: ") + modbusDevice->errorString(), 5000);} }void MainWindow::onWriteTableChanged(int index) {const bool coilsOrHolding = index == 0 || index == 3;if (coilsOrHolding){ui->treeViewWrite->setColumnHidden(1, index != 0);ui->treeViewWrite->setColumnHidden(2, index != 3);ui->treeViewWrite->resizeColumnToContents(0);}ui->btnReadWrite->setEnabled(index == 3);ui->btnWrite->setEnabled(coilsOrHolding);ui->groupBox_2->setEnabled(coilsOrHolding); }08. 程序下載
QModbus TCP模式客戶端讀操作(一).rar
QModbus TCP模式綜合操作(二).rar
09. 附錄
9.1 Qt教程匯總
網址:https://dengjin.blog.csdn.net/article/details/115174639
總結
以上是生活随笔為你收集整理的【Qt】modbus之TCP模式读操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Qt】modbus之串口模式写操作
- 下一篇: 【Qt】modbus之TCP模式写操作