【Qt】modbus之TCP模式写操作
生活随笔
收集整理的這篇文章主要介紹了
【Qt】modbus之TCP模式写操作
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
00. 目錄
文章目錄
- 00. 目錄
- 01. 概述
- 02. 開(kāi)發(fā)環(huán)境
- 03. 讀Coils程序示例
- 04. 讀HoldingRegisters程序示例
- 07. 綜合示例
- 08. 程序下載
- 09. 附錄
01. 概述
Qt中幾個(gè)常用的串口modbus類(lèi)
QModbusRtuSerialSlave //modbus串口通信方式下的服務(wù)器類(lèi) QModbusRtuSerialMaster //串口通信方式下的客戶(hù)端類(lèi) QModbusServer // QModbusServer類(lèi)接收和處理modbus的請(qǐng)求。 QModbusDataUnit //存儲(chǔ)接收和發(fā)送數(shù)據(jù)的類(lèi),數(shù)據(jù)類(lèi)型為1bit和16bit QModbusReply //客戶(hù)端訪(fǎng)問(wèn)服務(wù)器后得到的回復(fù)(如客戶(hù)端讀服務(wù)器數(shù)據(jù)時(shí)包含數(shù)據(jù)信息)02. 開(kāi)發(fā)環(huán)境
Windows系統(tǒng):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();void on_btnCoil_2_clicked();void on_btnHoldingRegisters_2_clicked(); }; #endif // WIDGET_Hwidget.cpp文件
#include "widget.h" #include "ui_widget.h" #include <QDebug> #include <QModbusTcpClient>//構(gòu)造函數(shù) Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//1. 創(chuàng)建QModbusDevice對(duì)象modbusDevice = new QModbusTcpClient(this);//禁用所有的讀操作ui->btnCoil->setEnabled(false);ui->btnDiscreteInputs->setEnabled(false);ui->btnHoldingRegisters->setEnabled(false);ui->btnInputRegisters->setEnabled(false);//禁用所有的寫(xiě)操作ui->btnCoil_2->setEnabled(false);ui->btnHoldingRegisters_2->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);}}//析構(gòu)函數(shù) Widget::~Widget() {if (modbusDevice){modbusDevice->disconnectDevice();}delete modbusDevice;delete ui; }void Widget::onReadReady() {auto reply = qobject_cast<QModbusReply*>(sender());if (nullptr == reply){return;}//判斷是否出錯(cuò)if (reply->error() == QModbusDevice::NoError){//讀取響應(yīng)數(shù)據(jù)const QModbusDataUnit responseData = reply->result();qDebug() << "讀到數(shù)據(jù)為:" << 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設(shè)備連接是否處于連接狀態(tài)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);ui->btnCoil_2->setEnabled(false);ui->btnHoldingRegisters_2->setEnabled(false);}else if (state == QModbusDevice::ConnectingState){qDebug() << "TCP Client正在連接Server";}else if (state == QModbusDevice::ConnectedState){qDebug() << "TCP Client已經(jīng)連接到Server";ui->btnConnect->setText(tr("斷開(kāi)連接"));ui->btnCoil->setEnabled(true);ui->btnDiscreteInputs->setEnabled(true);ui->btnHoldingRegisters->setEnabled(true);ui->btnInputRegisters->setEnabled(true);ui->btnCoil_2->setEnabled(true);ui->btnHoldingRegisters_2->setEnabled(true);}else if (state == QModbusDevice::ClosingState){qDebug() << "設(shè)備已經(jīng)被關(guān)閉";} }//連接按鈕槽函數(shù) 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);//設(shè)置超時(shí)時(shí)間modbusDevice->setTimeout(1000); //1秒//設(shè)置失敗重試次數(shù)modbusDevice->setNumberOfRetries(3);//連接到服務(wù)端bool ok = modbusDevice->connectDevice();if (!ok){qDebug() << "modbusDevice->connectDevice failed";}}else{//斷開(kāi)連接modbusDevice->disconnectDevice();ui->btnConnect->setText(tr("連接"));ui->btnCoil->setEnabled(false);ui->btnDiscreteInputs->setEnabled(false);ui->btnHoldingRegisters->setEnabled(false);ui->btnInputRegisters->setEnabled(false);ui->btnCoil_2->setEnabled(false);ui->btnHoldingRegisters_2->setEnabled(false);}}//讀線(xiàn)圈 void Widget::on_btnCoil_clicked() {//QModbusDataUnit::Coils 從地址0開(kāi)始讀取10個(gè)線(xiàn)圈值QModbusDataUnit data(QModbusDataUnit::Coils, 0, 10);auto reply = modbusDevice->sendReadRequest(data, 0x1);if (nullptr == reply){qDebug() << "發(fā)送請(qǐng)求數(shù)據(jù)失敗: " << modbusDevice->errorString();}else{if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);}else{//broadcast replies return immediatelydelete reply;}} }//讀離散輸入 void Widget::on_btnDiscreteInputs_clicked() {//QModbusDataUnit::DiscreteInputs 從地址0開(kāi)始讀取10個(gè)離散輸入值QModbusDataUnit data(QModbusDataUnit::DiscreteInputs, 0, 10);auto reply = modbusDevice->sendReadRequest(data, 0x1);if (nullptr == reply){qDebug() << "發(fā)送請(qǐng)求數(shù)據(jù)失敗: " << modbusDevice->errorString();}else{if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);}else{//broadcast replies return immediatelydelete reply;}} }//讀輸入寄存器 void Widget::on_btnInputRegisters_clicked() {//QModbusDataUnit::InputRegisters 從地址0開(kāi)始讀取10個(gè)輸入寄存器的值QModbusDataUnit data(QModbusDataUnit::InputRegisters, 0, 10);auto reply = modbusDevice->sendReadRequest(data, 0x1);if (nullptr == reply){qDebug() << "發(fā)送請(qǐng)求數(shù)據(jù)失敗: " << modbusDevice->errorString();}else{if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);}else{//broadcast replies return immediatelydelete reply;}} }//讀保持寄存器 void Widget::on_btnHoldingRegisters_clicked() {//從地址0開(kāi)始讀取10個(gè)保持寄存器的值QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, 0, 10);auto reply = modbusDevice->sendReadRequest(data, 0x1);if (nullptr == reply){qDebug() << "發(fā)送請(qǐng)求數(shù)據(jù)失敗: " << modbusDevice->errorString();}else{if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &Widget::onReadReady);}else{//broadcast replies return immediatelydelete reply;}} }//寫(xiě)線(xiàn)圈 void Widget::on_btnCoil_2_clicked() {//從地址0開(kāi)始寫(xiě)10個(gè)線(xiàn)圈的值QModbusDataUnit writeData(QModbusDataUnit::Coils, 0, 10);for (int i = 0; i < writeData.valueCount(); i++){writeData.setValue(i, (i * i) % 2);}qDebug() << "發(fā)送的數(shù)據(jù)為: " << writeData.values();QModbusReply* reply = modbusDevice->sendWriteRequest(writeData, 1);if (reply){if (!reply->isFinished()){//接收響應(yīng)信息connect(reply, &QModbusReply::finished, this, [this, reply](){if (reply->error() == QModbusDevice::ProtocolError){//接收到的響應(yīng)信息是協(xié)議錯(cuò)誤qDebug() << "寫(xiě)入數(shù)據(jù)錯(cuò)誤:" << reply->errorString();}else if (reply->error() != QModbusDevice::NoError){//接收到的響應(yīng)消息是其它錯(cuò)誤qDebug() << "寫(xiě)入數(shù)據(jù)錯(cuò)誤: " << reply->errorString();}else{//接收到的消息沒(méi)有錯(cuò)誤 一般沒(méi)有必要解析響應(yīng)消息const QModbusDataUnit data = reply->result();qDebug() << "消息數(shù)據(jù)個(gè)數(shù):" << data.valueCount() << " :" << data.values();}reply->deleteLater();});}else{//發(fā)送沒(méi)有響應(yīng)數(shù)據(jù)//broadcast replies return immediatelyreply->deleteLater();}}else{qDebug() << "sendWriteRequest Error: " << reply->errorString();} }//寫(xiě)保持寄存器 void Widget::on_btnHoldingRegisters_2_clicked() {}執(zhí)行結(jié)果
16:02:56: Starting D:\ProgramData\Qt\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test1.exe ... TCP Client正在連接Server TCP Client已經(jīng)連接到Server 發(fā)送的數(shù)據(jù)為: QVector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1) 消息數(shù)據(jù)個(gè)數(shù): 10 : QVector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1) 設(shè)備已經(jīng)被關(guān)閉 TCP Client連接到Server 未連接 16:03:17: D:\ProgramData\Qt\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test1.exe exited with code 004. 讀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();void on_btnCoil_2_clicked();void on_btnHoldingRegisters_2_clicked(); }; #endif // WIDGET_Hwidget.cpp文件
//寫(xiě)保持寄存器 void Widget::on_btnHoldingRegisters_2_clicked() {QModbusDataUnit writeData(QModbusDataUnit::HoldingRegisters, 0, 10);for (int i = 0; i < writeData.valueCount(); i++){writeData.setValue(i, i * i);}qDebug() << "發(fā)送的數(shù)據(jù)為: " << writeData.values();QModbusReply* reply = modbusDevice->sendWriteRequest(writeData, 1);if (reply){if (!reply->isFinished()){//接收響應(yīng)信息connect(reply, &QModbusReply::finished, this, [this, reply](){if (reply->error() == QModbusDevice::ProtocolError){//接收到的響應(yīng)信息是協(xié)議錯(cuò)誤qDebug() << "寫(xiě)入數(shù)據(jù)錯(cuò)誤:" << reply->errorString();}else if (reply->error() != QModbusDevice::NoError){//接收到的響應(yīng)消息是其它錯(cuò)誤qDebug() << "寫(xiě)入數(shù)據(jù)錯(cuò)誤: " << reply->errorString();}else{//接收到的消息沒(méi)有錯(cuò)誤 一般沒(méi)有必要解析響應(yīng)消息const QModbusDataUnit data = reply->result();qDebug() << "消息數(shù)據(jù)個(gè)數(shù):" << data.valueCount() << " :" << data.values();}reply->deleteLater();});}else{//發(fā)送沒(méi)有響應(yīng)數(shù)據(jù)//broadcast replies return immediatelyreply->deleteLater();}}else{qDebug() << "sendWriteRequest Error: " << reply->errorString();} }執(zhí)行結(jié)果
16:07:56: Starting D:\ProgramData\Qt\build-Test1-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test1.exe ... TCP Client正在連接Server TCP Client已經(jīng)連接到Server 發(fā)送的數(shù)據(jù)為: QVector(0, 1, 4, 9, 16, 25, 36, 49, 64, 81) 消息數(shù)據(jù)個(gè)數(shù): 10 : QVector(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)07. 綜合示例
程序界面
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-S2ap9szx-1621498438553)(assets/image-20210520154331905.png)]
settingdialog.h文件
#ifndef SETTINGDIALOG_H #define SETTINGDIALOG_H#include <QDialog> #include <QtSerialPort>namespace Ui { class SettingDialog; }//串口設(shè)置相關(guān)類(lèi) class SettingDialog : public QDialog {Q_OBJECTpublic:struct Settings{//串口名QString serialName = "COM3";//校驗(yàn)位int parity = QSerialPort::NoParity;//波特率int baud = QSerialPort::Baud19200;//數(shù)據(jù)位int dataBits = QSerialPort::Data8;//停止位int stopBits = QSerialPort::OneStop;//響應(yīng)時(shí)間int responseTime = 1000;//重試次數(shù)int numberOfRetries = 3;};explicit SettingDialog(QWidget *parent = nullptr);~SettingDialog();//返回參數(shù)設(shè)置信息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"//構(gòu)造函數(shù) SettingDialog::SettingDialog(QWidget *parent) :QDialog(parent),ui(new Ui::SettingDialog) {ui->setupUi(this);//設(shè)置默認(rèn)參數(shù)信息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);}//析構(gòu)函數(shù) SettingDialog::~SettingDialog() {delete ui; }//返回參數(shù)信息 SettingDialog::Settings SettingDialog::settings() const {return m_settings; }//引用按鈕槽函數(shù) 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();//隱藏參數(shù)設(shè)置對(duì)話(huà)框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();//信號(hào)與槽進(jìn)行關(guān)聯(lián)void initActions();//讀請(qǐng)求數(shù)據(jù)包封裝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>//連接類(lèi)型枚舉變量 enum ModbusConnection {Serial,Tcp };MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);//創(chuàng)建對(duì)象m_settingDialog = new SettingDialog(this);//初始化信號(hào)與槽initActions();//創(chuàng)建寫(xiě)模型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));//默認(rèn)為串口連接方式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++){//設(shè)置使能if (j < (10 - i)){lastIndex = j;model->item(j)->setEnabled(true);}else{//設(shè)置禁用model->item(j)->setEnabled(false);}}if (curIndex > lastIndex){ui->cbWriteCount->setCurrentIndex(lastIndex);}}); }//析構(gòu)函數(shù) MainWindow::~MainWindow() {if (modbusDevice){modbusDevice->disconnectDevice();delete modbusDevice;}delete ui; }//信號(hào)與槽進(jìn)行關(guān)聯(lián)s void MainWindow::initActions() {//使能部分功能ui->actionConnect->setEnabled(true);ui->actionDisconnect->setEnabled(false);ui->actionQuit->setEnabled(true);ui->actionOption->setEnabled(true);//禁用讀寫(xiě)操作ui->btnRead->setEnabled(false);ui->btnWrite->setEnabled(false);ui->btnReadWrite->setEnabled(false);//信號(hào)與槽關(guān)聯(lián)connect(ui->btnConnect, &QPushButton::clicked,this, &MainWindow::onConnectButtonClicked);connect(ui->actionConnect, &QAction::triggered,this, &MainWindow::onConnectButtonClicked);connect(ui->actionDisconnect, &QAction::triggered,this, &MainWindow::onConnectButtonClicked);//讀操作按鈕槽函數(shù)關(guān)聯(lián)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);//顯示參數(shù)設(shè)置對(duì)話(huà)框connect(ui->actionOption, &QAction::triggered, m_settingDialog, &QDialog::show);connect(ui->actionAbout, &QAction::triggered, [=]() {QMessageBox::aboutQt(this, "About Qt");}); }//構(gòu)建請(qǐng)求報(bào)文 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("線(xiàn)圈")){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() << "請(qǐng)求報(bào)文類(lèi)型: " << type;//獲取int startAddress = ui->spReadStartAddr->value();Q_ASSERT(startAddress >= 0 && startAddress < 10);quint16 numberOfEntries = ui->cbReadCount->currentText().toUShort();return QModbusDataUnit(type, startAddress, numberOfEntries); }//寫(xiě)請(qǐng)求數(shù)據(jù)包封裝 QModbusDataUnit MainWindow::writeRequest() const {QModbusDataUnit::RegisterType type = QModbusDataUnit::Invalid;qDebug() << ui->cbRegisterType->currentText();if (ui->cbRegisterType->currentText() == QString("線(xiàn)圈")){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() << "請(qǐng)求報(bào)文類(lèi)型: " << 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); }//連接和斷開(kāi)連接的槽函數(shù) void MainWindow::onConnectButtonClicked() {if (!modbusDevice){return;}//清空狀態(tài)欄消息statusBar()->clearMessage();if (modbusDevice->state() != QModbusDevice::ConnectedState){auto type = static_cast<ModbusConnection>(ui->cbConnType->currentIndex());if (type == Serial){//設(shè)置串口連接信息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);//使能讀寫(xiě)操作ui->btnRead->setEnabled(true);ui->btnWrite->setEnabled(true);ui->btnReadWrite->setEnabled(true);}}else{//斷開(kāi)連接modbusDevice->disconnectDevice();ui->actionConnect->setEnabled(true);ui->actionDisconnect->setDisabled(true);qDebug() << "斷開(kāi)連接成功";//禁用讀寫(xiě)操作ui->btnRead->setEnabled(false);ui->btnWrite->setEnabled(false);ui->btnReadWrite->setEnabled(false);} }//連接類(lèi)型槽函數(shù) TCP Serial void MainWindow::onConnectTypeChanged(int index) {//如果之前存在連接,則斷開(kāi)連接,然后釋放內(nèi)存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("連接類(lèi)型非法", 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("創(chuàng)建Modbus Master失敗"), 5000);}else{statusBar()->showMessage(tr("創(chuàng)建Modbus Client失敗"), 5000);}}else{connect(modbusDevice, &QModbusClient::stateChanged,this, &MainWindow::onModbusStateChanged);}}//Modbus狀態(tài)改變槽函數(shù) void MainWindow::onModbusStateChanged(int state) {//判斷Modbus設(shè)備連接是否處于連接狀態(tài)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"));} }//讀操作槽函數(shù) void MainWindow::onReadButtonClicked() {if (!modbusDevice){return;}ui->textEditRead->clear();statusBar()->clearMessage();//發(fā)送請(qǐng)求報(bào)文數(shù)據(jù)auto *reply = modbusDevice->sendReadRequest(readRequest(), ui->sbServerAddr->value());if (reply){if (!reply->isFinished()){//完畢之后 自動(dòng)觸發(fā)槽函數(shù)connect(reply, &QModbusReply::finished, this, &MainWindow::onReadReady);}else{//廣播消息 不需要返回響應(yīng)delete reply;}}else{statusBar()->showMessage(tr("Read Error: ") + modbusDevice->errorString(), 5000);}}//讀取數(shù)據(jù) 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);}//釋放內(nèi)存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() << "寫(xiě)數(shù)據(jù)內(nèi)容為:" << writeData.values();//發(fā)送請(qǐng)求報(bào)文數(shù)據(jù)auto *reply = modbusDevice->sendWriteRequest(writeData, ui->sbServerAddr->value());if (reply){if (!reply->isFinished()){//完畢之后 自動(dòng)觸發(fā)槽函數(shù)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() << "寫(xiě)響應(yīng)的數(shù)據(jù): " << reply->result().values();}reply->deleteLater();});}else{//廣播消息 不需要返回響應(yīng)reply->deleteLater();}}else{statusBar()->showMessage(tr("Write Error: ") + modbusDevice->errorString(), 5000);} }//讀寫(xiě)按鈕槽函數(shù) 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() << "寫(xiě)數(shù)據(jù)內(nèi)容為:" << writeData.values();//發(fā)送請(qǐng)求報(bào)文數(shù)據(jù)auto *reply = modbusDevice->sendReadWriteRequest(readRequest(), writeData, ui->sbServerAddr->value());if (reply){if (!reply->isFinished()){connect(reply, &QModbusReply::finished, this, &MainWindow::onReadReady);//完畢之后 自動(dòng)觸發(fā)槽函數(shù)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() << "寫(xiě)響應(yīng)的數(shù)據(jù): " << reply->result().values();}reply->deleteLater();});}else{//廣播消息 不需要返回響應(yīng)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模式寫(xiě)操作示例(一).rar
QModbus TCP模式綜合操作(二).rar
09. 附錄
9.1 Qt教程匯總
網(wǎng)址:https://dengjin.blog.csdn.net/article/details/115174639
總結(jié)
以上是生活随笔為你收集整理的【Qt】modbus之TCP模式写操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Qt】modbus之TCP模式读操作
- 下一篇: 【Tools】Win10系统搭建匿名FT