首页 » 软件优化 » Qt modbus之串口模式写操作(数据串口设置函数连接)

Qt modbus之串口模式写操作(数据串口设置函数连接)

南宫静远 2024-11-17 05:30:52 0

扫一扫用手机浏览

文章目录 [+]

QModbusRtuSerialSlave //modbus串口通信方式下的服务器类QModbusRtuSerialMaster //串口通信方式下的客户端类QModbusServer // QModbusServer类接收和处理modbus的请求。
QModbusDataUnit //存储接收和发送数据的类,数据类型为1bit和16bitQModbusReply //客户端访问服务器后得到的回复(如客户端读服务器数据时包含数据信息)
2. 开发环境

Windows系统:Windows10

Qt版本:Qt5.15或者Qt6

Pro配置文件如下

Qt modbus之串口模式写操作(数据串口设置函数连接) 软件优化
(图片来自网络侵删)

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}/binelse: unix:!android: target.path = /opt/$${TARGET}/bin!isEmpty(target.path): INSTALLS += target3. 写Coils程序示例

widget.h文件

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>//前向声明class QModbusClient;class QModbusReply;class Widget : public QWidget{ Q_OBJECTpublic: Widget(QWidget parent = nullptr); ~Widget();private: QModbusClient modbusDevice = nullptr;private slots: void onReadReady();};#endif // WIDGET_H

widget.cpp文件

【领QT开发教程学习资料,点击下方链接莬费领取↓↓,先码住不迷路~】

点击→领取「链接」

#include "widget.h"#include <QModbusRtuSerialMaster>#include <QModbusDataUnit>#include <QModbusReply>#include <QVariant>#include <QSerialPort>#include <QDebug>//构造函数Widget::Widget(QWidget parent) : QWidget(parent){ //1. 创建QModbusDevice对象 modbusDevice = new QModbusRtuSerialMaster; //2. 如果处于连接状态,则断开连接 if (modbusDevice->state() == QModbusDevice::ConnectedState) { //断开连接设备 modbusDevice->disconnectDevice(); } //3. 设置串口相关参数 //设置串口信息 modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, QVariant("COM3")); //设置校验 无校验 modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity); //设置波特率 modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud19200); //设置停止位 modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop); //设置数据位 modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8); //4. 设置其他信息 //设置超时时间 modbusDevice->setTimeout(1000); //1秒 //设置失败重试次数 modbusDevice->setNumberOfRetries(3); //5. 连接到设备 bool ok = modbusDevice->connectDevice(); if (!ok) { qDebug() << "连接到串口失败: " << modbusDevice->errorString(); } else { qDebug() << "连接到串口成功"; } //6. 发送写请求 //从地址0开始写10个保持寄存器的值 //QModbusDataUnit writeData(QModbusDataUnit::HoldingRegisters, 0, 10); //从地址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 immediately reply->deleteLater(); } } else { qDebug() << "sendWriteRequest Error: " << reply->errorString(); } //7. 发送读取数据请求 //从地址0开始读取10个保持寄存器的值 //QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, 0, 10); //从地址0开始读取10个离散输入量的值 //QModbusDataUnit data(QModbusDataUnit::DiscreteInputs, 0, 10); //QModbusDataUnit::Coils 从地址0开始读取10个线圈值 QModbusDataUnit data(QModbusDataUnit::Coils, 0, 10); //QModbusDataUnit::InputRegisters 从地址0开始读取10个输入寄存器的值 //QModbusDataUnit data(QModbusDataUnit::InputRegisters, 0, 10); 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 immediately delete reply; } }}//析构函数Widget::~Widget(){ if (modbusDevice) { modbusDevice->disconnectDevice(); } delete modbusDevice;}//准备读取数据的槽函数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(); } //删除reply reply->deleteLater();}

执行结果

20:32:27: Starting D:\ProgramData\Qt\build-Test-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test.exe ...连接到串口成功发送的数据为: QVector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)消息数据个数: 10 : QVector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)读到数据为: QVector(0, 1, 0, 1, 0, 1, 0, 1, 0, 1)20:34:02: D:\ProgramData\Qt\build-Test-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test.exe exited with code 04. 写HoldingRegisters程序示例

widget.h文件

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>//前向声明class QModbusClient;class QModbusReply;class Widget : public QWidget{ Q_OBJECTpublic: Widget(QWidget parent = nullptr); ~Widget();private: QModbusClient modbusDevice = nullptr;private slots: void onReadReady();};#endif // WIDGET_H

widget.cpp文件

#include "widget.h"#include <QModbusRtuSerialMaster>#include <QModbusDataUnit>#include <QModbusReply>#include <QVariant>#include <QSerialPort>#include <QDebug>//构造函数Widget::Widget(QWidget parent) : QWidget(parent){ //1. 创建QModbusDevice对象 modbusDevice = new QModbusRtuSerialMaster; //2. 如果处于连接状态,则断开连接 if (modbusDevice->state() == QModbusDevice::ConnectedState) { //断开连接设备 modbusDevice->disconnectDevice(); } //3. 设置串口相关参数 //设置串口信息 modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, QVariant("COM3")); //设置校验 无校验 modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity); //设置波特率 modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud19200); //设置停止位 modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop); //设置数据位 modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8); //4. 设置其他信息 //设置超时时间 modbusDevice->setTimeout(1000); //1秒 //设置失败重试次数 modbusDevice->setNumberOfRetries(3); //5. 连接到设备 bool ok = modbusDevice->connectDevice(); if (!ok) { qDebug() << "连接到串口失败: " << modbusDevice->errorString(); } else { qDebug() << "连接到串口成功"; } //6. 发送写请求 //从地址0开始写10个保持寄存器的值 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 immediately reply->deleteLater(); } } else { qDebug() << "sendWriteRequest Error: " << reply->errorString(); } //7. 发送读取数据请求 //从地址0开始读取10个保持寄存器的值 QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, 0, 10); //从地址0开始读取10个离散输入量的值 //QModbusDataUnit data(QModbusDataUnit::DiscreteInputs, 0, 10); //QModbusDataUnit::Coils 从地址0开始读取10个线圈值 //QModbusDataUnit data(QModbusDataUnit::Coils, 0, 10); //QModbusDataUnit::InputRegisters 从地址0开始读取10个输入寄存器的值 //QModbusDataUnit data(QModbusDataUnit::InputRegisters, 0, 10); 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 immediately delete reply; } }}//析构函数Widget::~Widget(){ if (modbusDevice) { modbusDevice->disconnectDevice(); } delete modbusDevice;}//准备读取数据的槽函数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(); } //删除reply reply->deleteLater();}

执行结果

20:23:23: Starting D:\ProgramData\Qt\build-Test-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test.exe ...连接到串口成功发送的数据为: QVector(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)消息数据个数: 10 : QVector(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)读到数据为: QVector(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)20:23:29: D:\ProgramData\Qt\build-Test-Desktop_Qt_5_15_2_MinGW_32_bit-Debug\debug\Test.exe exited with code 05. 综合示例

程序界面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J2Oiv0Co-1621479015968)(assets/image-20210520104421393.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>#include "writeregistermodel.h"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; //写请求数据包封装 QModbusDataUnit writeRequest() const;private slots: void onConnectButtonClicked(); void onConnectTypeChanged(int); void onModbusStateChanged(int state); void onReadButtonClicked(); void onReadReady(); void onWriteButtonClicked(); void onReadWriteButtonClicked(); void onWriteTableChanged(int);private: Ui::MainWindow ui = nullptr; SettingDialog m_settingDialog = nullptr; QModbusClient modbusDevice = nullptr; QModbusReply reply = nullptr; WriteRegisterModel writeModel = 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>//连接类型枚举变量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()); //MVC ui->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;}//信号与槽进行关联svoid 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连接信息 } 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 Serialvoid 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) { } 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);}

writeregistermodel.h文件

#ifndef WRITEREGISTERMODEL_H#define WRITEREGISTERMODEL_H#include <QAbstractItemModel>#include <QBitArray>#include <QObject>class WriteRegisterModel : public QAbstractTableModel{ Q_OBJECTpublic: WriteRegisterModel(QObject parent = nullptr); int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; Qt::ItemFlags flags(const QModelIndex &index) const override;public slots: void setStartAddress(int address); void setNumberOfValues(const QString &number);signals: void updateViewport();public: int m_number = 0; int m_address = 0; QBitArray m_coils; QVector<quint16> m_holdingRegisters;};#endif // WRITEREGISTERMODEL_H

writeregistermodel.cpp文件

#include "writeregistermodel.h"enum { NumColumn = 0, CoilsColumn = 1, HoldingColumn = 2, ColumnCount = 3, RowCount = 10 };WriteRegisterModel::WriteRegisterModel(QObject parent) : QAbstractTableModel(parent), m_coils(RowCount, false), m_holdingRegisters(RowCount, 0u){}int WriteRegisterModel::rowCount(const QModelIndex &/parent/) const{ return RowCount;}int WriteRegisterModel::columnCount(const QModelIndex &/parent/) const{ return ColumnCount;}QVariant WriteRegisterModel::data(const QModelIndex &index, int role) const{ if (!index.isValid() || index.row() >= RowCount || index.column() >= ColumnCount) return QVariant(); Q_ASSERT(m_coils.count() == RowCount); Q_ASSERT(m_holdingRegisters.count() == RowCount); if (index.column() == NumColumn && role == Qt::DisplayRole) return QString::number(index.row()); if (index.column() == CoilsColumn && role == Qt::CheckStateRole) // coils return m_coils.at(index.row()) ? Qt::Checked : Qt::Unchecked; if (index.column() == HoldingColumn && role == Qt::DisplayRole) // holding registers return QString("0x%1").arg(QString::number(m_holdingRegisters.at(index.row()), 16)); return QVariant();}QVariant WriteRegisterModel::headerData(int section, Qt::Orientation orientation, int role) const{ if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { switch (section) { case NumColumn: return QStringLiteral("#"); case CoilsColumn: return QStringLiteral("Coils "); case HoldingColumn: return QStringLiteral("Holding Registers"); default: break; } } return QVariant();}bool WriteRegisterModel::setData(const QModelIndex &index, const QVariant &value, int role){ if (!index.isValid() || index.row() >= RowCount || index.column() >= ColumnCount) return false; Q_ASSERT(m_coils.count() == RowCount); Q_ASSERT(m_holdingRegisters.count() == RowCount); if (index.column() == CoilsColumn && role == Qt::CheckStateRole) { // coils auto s = static_cast<Qt::CheckState>(value.toUInt()); s == Qt::Checked ? m_coils.setBit(index.row()) : m_coils.clearBit(index.row()); emit dataChanged(index, index); return true; } if (index.column() == HoldingColumn && role == Qt::EditRole) { // holding registers bool result = false; quint16 newValue = value.toString().toUShort(&result, 16); if (result) m_holdingRegisters[index.row()] = newValue; emit dataChanged(index, index); return result; } return false;}Qt::ItemFlags WriteRegisterModel::flags(const QModelIndex &index) const{ if (!index.isValid() || index.row() >= RowCount || index.column() >= ColumnCount) return QAbstractTableModel::flags(index); Qt::ItemFlags flags = QAbstractTableModel::flags(index); if ((index.row() < m_address) || (index.row() >= (m_address + m_number))) flags &= ~Qt::ItemIsEnabled; if (index.column() == CoilsColumn) // coils return flags | Qt::ItemIsUserCheckable; if (index.column() == HoldingColumn) // holding registers return flags | Qt::ItemIsEditable; return flags;}void WriteRegisterModel::setStartAddress(int address){ m_address = address; emit updateViewport();}void WriteRegisterModel::setNumberOfValues(const QString &number){ m_number = number.toInt(); emit updateViewport();}

相关文章