00. 目录

文章目录

  • 00. 目录
  • 01. 概述
  • 02. 开发环境
  • 03. 读Coils程序示例
  • 04. 读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 += target

03. 读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_H

widget.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);//禁用所有的写操作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);}}//析构函数
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);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已经连接到Server";ui->btnConnect->setText(tr("断开连接"));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() << "设备已经被关闭";}
}//连接按钮槽函数
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);ui->btnCoil_2->setEnabled(false);ui->btnHoldingRegisters_2->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()
{//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;}}
}//读输入寄存器
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;}}
}//读保持寄存器
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;}}
}//写线圈
void Widget::on_btnCoil_2_clicked()
{//从地址0开始写10个线圈的值QModbusDataUnit writeData(QModbusDataUnit::Coils, 0, 10);for (int i = 0; i < writeData.valueCount(); i++){writeData.setValue(i, (i * i) % 2);}qDebug() << "发送的数据为: " << writeData.values();QModbusReply* reply = modbusDevice->sendWriteRequest(writeData, 1);if (reply){if (!reply->isFinished()){//接收响应信息connect(reply, &QModbusReply::finished, this, [this, reply](){if (reply->error() == QModbusDevice::ProtocolError){//接收到的响应信息是协议错误qDebug() << "写入数据错误:" << reply->errorString();}else if (reply->error() != QModbusDevice::NoError){//接收到的响应消息是其它错误qDebug() << "写入数据错误: " << reply->errorString();}else{//接收到的消息没有错误 一般没有必要解析响应消息const QModbusDataUnit data = reply->result();qDebug() << "消息数据个数:" << data.valueCount() << " :" << data.values();}reply->deleteLater();});}else{//发送没有响应数据//broadcast replies return immediatelyreply->deleteLater();}}else{qDebug() << "sendWriteRequest Error: " << reply->errorString();}
}//写保持寄存器
void Widget::on_btnHoldingRegisters_2_clicked()
{}

执行结果

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已经连接到Server
发送的数据为:  QVector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
消息数据个数: 10  : QVector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
设备已经被关闭
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 0

04. 读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_H

widget.cpp文件

//写保持寄存器
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() << "发送的数据为: " << writeData.values();QModbusReply* reply = modbusDevice->sendWriteRequest(writeData, 1);if (reply){if (!reply->isFinished()){//接收响应信息connect(reply, &QModbusReply::finished, this, [this, reply](){if (reply->error() == QModbusDevice::ProtocolError){//接收到的响应信息是协议错误qDebug() << "写入数据错误:" << reply->errorString();}else if (reply->error() != QModbusDevice::NoError){//接收到的响应消息是其它错误qDebug() << "写入数据错误: " << reply->errorString();}else{//接收到的消息没有错误 一般没有必要解析响应消息const QModbusDataUnit data = reply->result();qDebug() << "消息数据个数:" << data.valueCount() << " :" << data.values();}reply->deleteLater();});}else{//发送没有响应数据//broadcast replies return immediatelyreply->deleteLater();}}else{qDebug() << "sendWriteRequest Error: " << reply->errorString();}
}

执行结果

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已经连接到Server
发送的数据为:  QVector(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)
消息数据个数: 10  : QVector(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)

07. 综合示例

程序界面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S2ap9szx-1621498438553)(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_H

settingdialog.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_H

mainwindow.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模式写操作相关推荐

  1. 【Qt】modbus之TCP模式读操作

    00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 读Coils程序示例 04. 读DiscreteInputs程序示例 05. 读InputRegisters程序示例 06 ...

  2. 【Qt】modbus之串口模式写操作

    00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 写Coils程序示例 04. 写HoldingRegisters程序示例 05. 综合示例 06. 程序下载 07. 附录 ...

  3. 【Qt】modbus之串口模式读操作

    00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 读DiscreteInputs程序示例 04. 读Coils程序示例 05. 读InputRegisters程序示例 06 ...

  4. 【嵌入式】Libmodbus之TCP模式Slave端程序示例

    00. 目录 文章目录 00. 目录 01. 开发TCPSlave端程序流程 02. TCP Slave端程序示例 03. TCP Slave端程序说明 04. 预留 05. 附录 01. 开发TCP ...

  5. 工业自动化MODBUS协议读写器读卡器配置软件|工具之读写卡模式配置操作攻略

    本程序MODBUS读卡器配置软件所支持配置的读卡模式有四种,分别为标准MODBUS.Enchance Mode.Continue Read Mode和Read Once Mode.具体使用何种读卡模式 ...

  6. Write operations are not allowed in read-only mode 只读模式下(FlushMode.NEVER/MANUAL)写操作不允

    来源:http://blog.sina.com.cn/s/blog_656ffe730100ugtw.html org.springframework.dao.InvalidDataAccessApi ...

  7. 相信我,SDRAM真的不难(四)----写操作(页突发模式)

    写在前面 本文是SDRAM系列文章的第四篇,对SDRAM的突发写操作进行了详细介绍.代码编写与仿真验证. 其他博文链接:相信我,SDRAM真的不难----汇总篇(电梯直达) 1.写操作 SDRAM提供 ...

  8. 【Qt Modbus通信】libmodbus实现modbus的主机功能/从机功能 源码分享

    前言 modbus在上下位机数据交互时被广泛使用,因此写了这篇笔记和大家一起学习. 参考文献 Libmodbus源码分析(二)-常用接口函数分析 Libmodbus源码分析(四)-RTU相关函数分析 ...

  9. 【嵌入式】Libmodbus之TCP模式Master端程序示例

    00. 目录 文章目录 00. 目录 01. TCP模式Master开发流程 02. 读写单个线圈程序示例 03. 读写多个线圈程序示例 04. 读写单个保持寄存器程序示例 05. 读写多个保持寄存器 ...

最新文章

  1. 计算机文化基础案例教程第三版答案,计算机文化基础案例教程(第3版 谭宁)教学课件 素材.zip-排骨做法.doc...
  2. 3. SQL Server数据库状态监控 - 可用空间
  3. springboot智慧幼儿园管理系统的设计与实现毕业设计源码271611
  4. F.grid_sample
  5. Java开发手册之二方库依赖
  6. 解决Visio中对象不能通过键盘方向键微调位置
  7. 坦克世界+服务器未响应,手把手解答win10系统玩坦克世界出现未响应的办法
  8. 抓包工具charles实践分享
  9. 如何实现一个朴实无华的Canvas时钟效果
  10. Postman|网页调试工具
  11. dubbo(4) Dubbo源码解析之服务引入过程
  12. 算法分析:时间和空间复杂度
  13. 覆盖式理解Android 消息处理机制(带源码解析)
  14. Android中IPC机制详解
  15. 重装系统准备就绪时间太长了?
  16. 浅谈全国大学生智能车竞赛-摄像头组图像处理及控制算法
  17. oracle运维系列0:Oracle installClient 安装
  18. 分页和分段有什么区别?
  19. 风火之旅那么多脱机外挂不知道前途如何?
  20. 使用sysprep.exe制作GHO或WIM镜像

热门文章

  1. IIS 8.5配置.net网站[花了半个多小时]
  2. size_t和ssie_t的区别
  3. 从字符串 到类型 Boolean 的转换无效。
  4. 取 Oracle Schema信息
  5. 启动指定参数_SpringBoot的三种启动方式
  6. c++随机打乱数组_【洗牌算法】你确定这样的抽奖算法是随机的?
  7. 每日程序C语言18-求分数序列的前20项和
  8. python字符编码使用_python – Numpy字符串编码
  9. 非苹果PC安装MacOS
  10. DevExpress WPF v18.2新版亮点(四)