QModbusClient的链接与注意点

本文详细介绍了如何使用Qt的QModbusClient类实现ModbusTCP客户端编程,包括连接服务端、发送读写请求的具体步骤及注意事项,特别强调了异步API的正确使用方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

QModbusClient

以使用Modbus Tcp为例看看客户端怎么写程序

首先连接到服务端

QModbusTcpClient *client = new QModbusTcpClient();
client->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "192.168.0.1");
client->setConnectionParameter(QModbusDevice::NetworkPortParameter, 502);
client->connectDevice();

这样就连接上服务端了,下面可以发送请求了

发送读或写请求到服务端

写请求

QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, 40003, 1); // write 1 value in address 40003
writeUnit.setValue(0, 0x253); 
//这里先建好QModbusDataUnit

if (auto *reply = client->sendWriteRequest(writeUnit, 1))
//发送写请求
{
    if (!reply->isFinished())
    {
        connect(reply, &QModbusReply::finished, this, [this, reply]() 
        {
            if (reply->error() != QModbusDevice::NoError)               
                    // error in reply

                reply->deleteLater();
            });
    }
    else
    {
        if (reply->error() != QModbusDevice::NoError)           
            // error in reply

        // broadcast replies return immediately
        reply->deleteLater();
    }
}
else
{
    // error in request
}

先建个QModbusDataUnit,下面是Qt帮助文档中的介绍

QModbusDataUnit is a container class representing single bit and 16 bit word entries in the Modbus register.QModbusDataUnit can be used for read and write operations

给QModbusDataUnit赋好值后发送写请求sendWriteRequest,写到相应寄存器中的相应位置
如果没有发生错误的话sendWriteRequest将返回一个QModbusReply,否则返回空指针。
当reply完成或放弃后reply->isFinished()将返回true。

读请求

QModbusDataUnit readUnit(QModbusDataUnit::InputRegisters, 40006, 1); // just read input register 40006 

if (auto *reply = client->sendReadRequest(readUnit, 255)) // client id 255
{
    if (!reply->isFinished())
    {
        // connect the finished signal of the request to your read slot
        connect(reply, &QModbusReply::finished, this, &YourClass::readReady);
    }
    else
    {
        delete reply; // broadcast replies return immediately
    }
}
else
{
    // request error
}
YourClass::readReady
{
    QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
        return;

    if (reply->error() == QModbusDevice::NoError)
    {
        const QModbusDataUnit unit = reply->result();
        int startAddress = unit.startAddress(); // the start address, here 40006
        int value = unit.value(0); // value of the start address + 0
        ... 

    }
    else
    {
        // reply error
    }

    reply->deleteLater(); // delete the reply 
}

应该注意的问题
看看QModbusClient帮助文档中的一句话

QModbusClient has an asynchronous API. When the finished slot is called, the parameter it takes is the QModbusReply object containing the PDU as well as meta-data (Addressing, etc.).

这意味着

The API of the QModbusDevice classes are asynchronous. That means when you callclient->connectDevice() your client is not “really” connected to your server. The function just send an event to the event loop. When the application enters the event loop the event will be executed.The QModbusDevice class has some signals to control your connection state and error message.

所以我们应该

Check the client state with yout slot. Before reading registers ensure that the client is in connected state.

因此所有代码在一个函数中是不对的,像这样

YourClass::connect()
{
QModbusTcpClient *client=new QModbusTcpClient();
client->setConnectionParameter(QModbusDevice::NetworkAddressParameter,"192.168.0.201");
client->setConnectionParameter(QModbusDevice::NetworkPortParameter,502);
client->connectDevice();

QModbusDataUnit readUnit(QModbusDataUnit::Coils,00000,4);
if (auto *reply=client->sendReadRequest(readUnit,255)){

...
}

应该

MyClass::connectToModbusServer()
{
   QModbusTcpClient *client=new QModbusTcpClient();
   client->setConnectionParameter(QModbusDevice::NetworkAddressParameter,"192.168.0.201");
   client->setConnectionParameter(QModbusDevice::NetworkPortParameter,502);

   if (client->connectDevice())
   {
      connect(client, &QModbusTcpClient::stateChanged, this, &MyClass::onStateChanged); 
      connect(client, &QModbusTcpClient::errorOccurred, this, &MyClass::onErrorOccurred); 
   }
   else
      qDebug() << client->errorString();
}

MyClass::readCoil()
{
   QModbusDataUnit readUnit(QModbusDataUnit::Coils,00000,4);
}

原文链接:QModbusClient

这是我的代码:Cmakelist:cmake_minimum_required(VERSION 3.16) project(KamoerPumpControl VERSION 0.1 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 查找Qt模块(必须包含SerialPort和Modbus) find_package(Qt6 COMPONENTS Widgets SerialPort SerialBus REQUIRED) set(PROJECT_SOURCES main.cpp mainwindow.cpp mainwindow.h mainwindow.ui ) if (QT_VERSION_MAJOR VERSION_GREATER_EQUAL 6) qt_add_executable(KamoerPumpControl MANUAL_FINALIZATION ${PROJECT_SOURCES} ) else() add_executable(KamoerPumpControl ${PROJECT_SOURCES}) endif() # 链接必要的库 target_link_libraries(KamoerPumpControl PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::SerialPort Qt${QT_VERSION_MAJOR}::SerialBus ) # 其他配置保持不变 if(QT_VERSION_MAJOR EQUAL 6) qt_finalize_executable(KamoerPumpControl) endif() mainwindow.h:#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QSerialPort> #include <QModbusRtuSerialClient> // Modbus RTU主站 #include <QModbusDataUnit> #include <QTimer> #include <QModbusClient> #include <QSerialPortInfo> #include <QModbusReply> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: // 串口连接 void on_A3_clicked(); // 泵控制(4个泵的启动/停止/调速) void on_A4_clicked(); void on_A5_clicked(); void on_A6_valueChanged(int value); void on_A7_clicked(); void on_A8_clicked(); void on_A9_valueChanged(int value); void on_A10_clicked(); void on_A11_clicked(); void on_A12_valueChanged(int value); void on_A13_clicked(); void on_A14_clicked(); void on_A15_valueChanged(int value); // Modbus响应处理 void onModbusResponseReceived(QModbusReply *reply); private: Ui::MainWindow *ui; QModbusRtuSerialClient *modbusClient; // Modbus主站对象 QSerialPort *serialPort; QTimer *statusTimer; // 定时查询泵状态 // 初始化Modbus void initModbus(); // 发送Modbus指令(通用函数) void sendModbusCommand(int pumpAddress, quint16 registerAddress, quint16 value); // 查询泵状态(通用函数) void queryPumpStatus(int pumpAddress); // 解析状态响应 void parseStatus(int pumpAddress, const QModbusDataUnit &data); }; #endif // MAINWINDOW_H main.cpp:#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } mainwindow.cpp:#include "mainwindow.h" #include "./ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , modbusClient(new QModbusRtuSerialClient(this)) ,serialPort(new QSerialPort(this)) , statusTimer(new QTimer(this)) { ui->setupUi(this); setWindowTitle("卡莫尔KDS3000四泵控制器"); // 初始化串口选择框 foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { ui->A1->addItem(info.portName()); } ui->A2->setCurrentText("9600"); // 默认波特率 // 初始化Modbus initModbus(); // 定时查询状态(每2秒) connect(statusTimer, &QTimer::timeout, this, [=](){ queryPumpStatus(1); // 查询泵1状态 queryPumpStatus(2); // 查询泵2状态 queryPumpStatus(3); // 查询泵3状态 queryPumpStatus(4); // 查询泵4状态 }); // 初始化转速滑块(0~100%) ui->A6->setRange(0, 100); ui->A9->setRange(0, 100); ui->A12->setRange(0, 100); ui->A15->setRange(0, 100); } MainWindow::~MainWindow() { if (modbusClient->state() == QModbusDevice::ConnectedState) { modbusClient->disconnectDevice(); } delete ui; } // 初始化Modbus参数 void MainWindow::initModbus() { // 连接Modbus响应信号 connect(modbusClient, &QModbusClient::stateChanged, this, [=](QModbusDevice::State state){ if (state == QModbusDevice::ConnectedState) { ui->A26->append("Modbus已连接"); statusTimer->start(2000); // 开始定时查询 } else { ui->A26->append("Modbus已断开"); statusTimer->stop(); } }); // 处理Modbus响应 connect(modbusClient, &QModbusClient::finished, this, &MainWindow::onModbusResponseReceived); } // 连接/断开串口 void MainWindow::on_A3_clicked() { if (modbusClient->state() == QModbusDevice::ConnectedState) { modbusClient->disconnectDevice(); ui->A3->setText("连接"); return; } // 配置串口参数(需泵一致) serialPort->setPortName(ui->A1->currentText()); serialPort->setBaudRate(static_cast<QSerialPort::BaudRate>(ui->A2->currentText().toInt())); serialPort->setDataBits(QSerialPort::Data8); serialPort->setParity(QSerialPort::NoParity); // 默认无校验 serialPort->setStopBits(QSerialPort::OneStop); modbusClient->setDevice(serialPort); // 连接设备 if (modbusClient->connectDevice()) { ui->A3->setText("断开"); } else { ui->A26->append(QString("连接失败:%1").arg(modbusClient->errorString())); } } // 发送Modbus指令(写入寄存器) void MainWindow::sendModbusCommand(int pumpAddress, quint16 registerAddress, quint16 value) { if (modbusClient->state() != QModbusDevice::ConnectedState) { ui->A26->append("未连接,无法发送指令"); return; } // 准备写入数据(功能码0x06:单寄存器写入) QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, registerAddress, 1); writeUnit.setValue(0, value); // 发送指令到指定地址的泵 if (auto *reply = modbusClient->sendWriteRequest(writeUnit, pumpAddress)) { if (!reply->isFinished()) { connect(reply, &QModbusReply::errorOccurred, this, [=](QModbusDevice::Error error){ ui->A26->append(QString("[泵%1] 指令发送失败:%2").arg(pumpAddress).arg(reply->errorString())); }); } else { reply->deleteLater(); // 立即清理 } } else { ui->A26->append(QString("[泵%1] 发送失败:%2").arg(pumpAddress).arg(modbusMaster->errorString())); } } // 查询泵状态(读取寄存器) void MainWindow::queryPumpStatus(int pumpAddress) { if (modbusClient->state() != QModbusDevice::ConnectedState) return; // 读取状态寄存器(假设状态存放在0x0001,需参考泵的Modbus手册) QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0x0001, 1); if (auto *reply = modbusClient->sendReadRequest(readUnit, pumpAddress)) { if (!reply->isFinished()) { connect(reply, &QModbusReply::errorOccurred, this, [=](QModbusDevice::Error error){ ui->A26->append(QString("[泵%1] 状态查询失败:%2").arg(pumpAddress).arg(reply->errorString())); }); } else { reply->deleteLater(); } } } // 处理Modbus响应 void MainWindow::onModbusResponseReceived(QModbusReply *reply) { if (reply->error() != QModbusDevice::NoError) { reply->deleteLater(); return; } // 获取发送指令的泵地址 int pumpAddress = reply->serverAddress(); // 获取响应数据 QModbusDataUnit data = reply->result(); // 区分是读取还是写入响应 if (reply->functionCode() == QModbusRequest::ReadHoldingRegisters) { parseStatus(pumpAddress, data); // 解析状态 } else if (reply->functionCode() == QModbusRequest::WriteSingleRegister) { ui->A26->append(QString("[泵%1] 指令执行成功").arg(pumpAddress)); } reply->deleteLater(); } // 解析泵状态 void MainWindow::parseStatus(int pumpAddress, const QModbusDataUnit &data) { if (data.valueCount() == 0) return; quint16 status = data.value(0); QString statusStr = (status == 1) ? "运行中" : "已停止"; // 更新对应泵的状态标签 if (pumpAddress == 1) ui->A25->setText(statusStr); else if (pumpAddress == 2) ui->A27->setText(statusStr); else if (pumpAddress == 3) ui->A28->setText(statusStr); else if (pumpAddress == 4) ui->A29->setText(statusStr); ui->A26->append(QString("[泵%1] 状态:%2").arg(pumpAddress).arg(statusStr)); } // 泵1控制(启动) void MainWindow::on_A4_clicked() { // 假设启动寄存器为0x0000,值1为启动(需参考手册) sendModbusCommand(1, 0x0000, 1); } // 泵1控制(停止) void MainWindow::on_A5_clicked() { sendModbusCommand(1, 0x0000, 0); // 0为停止 } // 泵1调速(0~100%对应寄存器值0~1000) void MainWindow::on_A6_valueChanged(int value) { quint16 speed = value * 10; // 假设100%对应1000 sendModbusCommand(1, 0x0002, speed); // 转速寄存器0x0002 ui->A16->setText(QString("泵1速度%1%").arg(value)); } // 泵2控制(启动) void MainWindow::on_A7_clicked() { // 假设启动寄存器为0x0000,值1为启动(需参考手册) sendModbusCommand(2, 0x0000, 1); } // 泵2控制(停止) void MainWindow::on_A8_clicked() { sendModbusCommand(2, 0x0000, 0); // 0为停止 } // 泵2调速(0~100%对应寄存器值0~1000) void MainWindow::on_A9_valueChanged(int value) { quint16 speed = value * 10; // 假设100%对应1000 sendModbusCommand(2, 0x0002, speed); // 转速寄存器0x0002 ui->A17->setText(QString("泵2速度%1%").arg(value)); } // 泵3控制(启动) void MainWindow::on_A10_clicked() { // 假设启动寄存器为0x0000,值1为启动(需参考手册) sendModbusCommand(3, 0x0000, 1); } // 泵3控制(停止) void MainWindow::on_A11_clicked() { sendModbusCommand(3, 0x0000, 0); // 0为停止 } // 泵3调速(0~100%对应寄存器值0~1000) void MainWindow::on_A12_valueChanged(int value) { quint16 speed = value * 10; // 假设100%对应1000 sendModbusCommand(3, 0x0002, speed); // 转速寄存器0x0002 ui->A18->setText(QString("泵3速度%1%").arg(value)); } // 泵4控制(启动) void MainWindow::on_A13_clicked() { // 假设启动寄存器为0x0000,值1为启动(需参考手册) sendModbusCommand(4, 0x0000, 1); } // 泵4控制(停止) void MainWindow::on_A14_clicked() { sendModbusCommand(4, 0x0000, 0); // 0为停止 } // 泵4调速(0~100%对应寄存器值0~1000) void MainWindow::on_A15_valueChanged(int value) { quint16 speed = value * 10; // 假设100%对应1000 sendModbusCommand(4, 0x0002, speed); // 转速寄存器0x0002 ui->A19->setText(QString("泵4速度%1%").arg(value)); } // 泵2~4的控制函数泵1相同,只需替换地址(2、3、4) // ...(省略泵2~4的槽函数,复制泵1代码并修改地址即可) 这是报错:E:\Qte\RDB\mainwindow.cpp:61: error: 'finished' is not a member of 'QModbusClient' E:/Qte/RDB/mainwindow.cpp: In member function 'void MainWindow::initModbus()': E:/Qte/RDB/mainwindow.cpp:61:43: error: 'finished' is not a member of 'QModbusClient' 61 | connect(modbusClient, &QModbusClient::finished, this, &MainWindow::onModbusResponseReceived); | ^~~~~~~~ E:\Qte\RDB\mainwindow.cpp:80: error: 'class QModbusRtuSerialClient' has no member named 'setDevice'; did you mean 'device'? E:/Qte/RDB/mainwindow.cpp: In member function 'void MainWindow::on_A3_clicked()': E:/Qte/RDB/mainwindow.cpp:80:19: error: 'class QModbusRtuSerialClient' has no member named 'setDevice'; did you mean 'device'? 80 | modbusClient->setDevice(serialPort); | ^~~~~~~~~ | device E:\Qte\RDB\mainwindow.cpp:111: error: 'modbusMaster' was not declared in this scope E:/Qte/RDB/mainwindow.cpp: In member function 'void MainWindow::sendModbusCommand(int, quint16, quint16)': E:/Qte/RDB/mainwindow.cpp:111:77: error: 'modbusMaster' was not declared in this scope 111 | ui->A26->append(QString("[泵%1] 发送失败:%2").arg(pumpAddress).arg(modbusMaster->errorString())); | ^~~~~~~~~~~~ E:\Qte\RDB\mainwindow.cpp:147: error: 'class QModbusReply' has no member named 'functionCode' E:/Qte/RDB/mainwindow.cpp: In member function 'void MainWindow::onModbusResponseReceived(QModbusReply*)': E:/Qte/RDB/mainwindow.cpp:147:16: error: 'class QModbusReply' has no member named 'functionCode' 147 | if (reply->functionCode() == QModbusRequest::ReadHoldingRegisters) { | ^~~~~~~~~~~~ E:\Qte\RDB\mainwindow.cpp:149: error: 'class QModbusReply' has no member named 'functionCode' E:/Qte/RDB/mainwindow.cpp:149:23: error: 'class QModbusReply' has no member named 'functionCode' 149 | } else if (reply->functionCode() == QModbusRequest::WriteSingleRegister) { | ^~~~~~~~~~~~ :-1: error: ninja: build stopped: subcommand failed. E:\Qte\RDB\mainwindow.cpp:61: error: No member named 'finished' in 'QModbusClient' E:\Qte\RDB\mainwindow.cpp:80: error: No member named 'setDevice' in 'QModbusRtuSerialClient' E:\Qte\RDB\mainwindow.cpp:111: error: Use of undeclared identifier 'modbusMaster' E:\Qte\RDB\mainwindow.cpp:147: error: No member named 'functionCode' in 'QModbusReply' E:\Qte\RDB\mainwindow.cpp:149: error: No member named 'functionCode' in 'QModbusReply'
最新发布
08-05
这是我在Qt6.5.3 Cmake环境下的代码,请帮我检查:Cmakelist:cmake_minimum_required(VERSION 3.16) project(KamoerPumpControl VERSION 0.1 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 查找Qt模块(必须包含SerialPort和Modbus) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets SerialPort Modbus) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) find_package(Qt6 REQUIRED COMPONENTS SerialBus) set(PROJECT_SOURCES main.cpp mainwindow.cpp mainwindow.h mainwindow.ui ) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) qt_add_executable(KamoerPumpControl MANUAL_FINALIZATION ${PROJECT_SOURCES} ) else() add_executable(RDBl ${PROJECT_SOURCES}) endif() # 链接必要的库 target_link_libraries(KamoerPumpControl PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::SerialPort Qt${QT_VERSION_MAJOR}::SerialBus ) # 其他配置保持不变 if(QT_VERSION_MAJOR EQUAL 6) qt_finalize_executable(KamoerPumpControl) endif() mainwindow.h:#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QSerialPort> #include <QModbusRtuSerialMaster> // Modbus RTU主站 #include <QModbusDataUnit> #include <QTimer> #include <QModBusClient> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: // 串口连接 void on_A3_clicked(); // 泵控制(4个泵的启动/停止/调速) void on_A4_clicked(); void on_A5_clicked(); void on_A6_valueChanged(int value); void on_A7_clicked(); void on_A8_clicked(); void on_A9_valueChanged(int value); void on_A10_clicked(); void on_A11_clicked(); void on_A12_valueChanged(int value); void on_A13_clicked(); void on_A14_clicked(); void on_A15_valueChanged(int value); // Modbus响应处理 void onModbusResponseReceived(QModbusReply *reply); private: Ui::MainWindow *ui; QModbusRtuSerialMaster *modbusMaster; // Modbus主站对象 QTimer *statusTimer; // 定时查询泵状态 // 初始化Modbus void initModbus(); // 发送Modbus指令(通用函数) void sendModbusCommand(int pumpAddress, quint16 registerAddress, quint16 value); // 查询泵状态(通用函数) void queryPumpStatus(int pumpAddress); // 解析状态响应 void parseStatus(int pumpAddress, const QModbusDataUnit &data); }; #endif // MAINWINDOW_H main.cpp:#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } mainwindow.cpp:#include "mainwindow.h" #include "./ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , modbusMaster(new QModbusRtuSerialMaster(this)) , statusTimer(new QTimer(this)) { ui->setupUi(this); setWindowTitle("卡莫尔KDS3000四泵控制器"); // 初始化串口选择框 foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { ui->A1->addItem(info.portName()); } ui->A2->setCurrentText("9600"); // 默认波特率 // 初始化Modbus initModbus(); // 定时查询状态(每2秒) connect(statusTimer, &QTimer::timeout, this, [=](){ queryPumpStatus(1); // 查询泵1状态 queryPumpStatus(2); // 查询泵2状态 queryPumpStatus(3); // 查询泵3状态 queryPumpStatus(4); // 查询泵4状态 }); // 初始化转速滑块(0~100%) ui->A6->setRange(0, 100); ui->A9->setRange(0, 100); ui->A12->setRange(0, 100); ui->A15->setRange(0, 100); } MainWindow::~MainWindow() { if (modbusMaster->state() == QModbusDevice::ConnectedState) { modbusMaster->disconnectDevice(); } delete ui; } // 初始化Modbus参数 void MainWindow::initModbus() { // 连接Modbus响应信号 connect(modbusMaster, &QModbusClient::stateChanged, this, [=](QModbusDevice::State state){ if (state == QModbusDevice::ConnectedState) { ui->A26->append("Modbus已连接"); statusTimer->start(2000); // 开始定时查询 } else { ui->A26->append("Modbus已断开"); statusTimer->stop(); } }); // 处理Modbus响应 connect(modbusMaster, &QModbusRtuSerialMaster::finished, this, &MainWindow::onModbusResponseReceived); } // 连接/断开串口 void MainWindow::on_A3_clicked() { if (modbusMaster->state() == QModbusDevice::ConnectedState) { modbusMaster->disconnectDevice(); ui->A3->setText("连接"); return; } // 配置串口参数(需泵一致) modbusMaster->setPortName(ui->A1->currentText()); modbusMaster->setBaudRate(static_cast<QSerialPort::BaudRate>(ui->A2->currentText().toInt())); modbusMaster->setDataBits(QSerialPort::Data8); modbusMaster->setParity(QSerialPort::NoParity); // 默认无校验 modbusMaster->setStopBits(QSerialPort::OneStop); // 连接设备 if (modbusMaster->connectDevice()) { ui->A3->setText("断开"); } else { ui->A26->append(QString("连接失败:%1").arg(modbusMaster->errorString())); } } // 发送Modbus指令(写入寄存器) void MainWindow::sendModbusCommand(int pumpAddress, quint16 registerAddress, quint16 value) { if (modbusMaster->state() != QModbusDevice::ConnectedState) { ui->A26->append("未连接,无法发送指令"); return; } // 准备写入数据(功能码0x06:单寄存器写入) QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, registerAddress, 1); writeUnit.setValue(0, value); // 发送指令到指定地址的泵 if (auto *reply = modbusMaster->sendWriteRequest(writeUnit, pumpAddress)) { if (!reply->isFinished()) { connect(reply, &QModbusReply::errorOccurred, this, [=](QModbusDevice::Error error){ ui->A26->append(QString("[泵%1] 指令发送失败:%2").arg(pumpAddress).arg(reply->errorString())); }); } else { reply->deleteLater(); // 立即清理 } } else { ui->A26->append(QString("[泵%1] 发送失败:%2").arg(pumpAddress).arg(modbusMaster->errorString())); } } // 查询泵状态(读取寄存器) void MainWindow::queryPumpStatus(int pumpAddress) { if (modbusMaster->state() != QModbusDevice::ConnectedState) return; // 读取状态寄存器(假设状态存放在0x0001,需参考泵的Modbus手册) QModbusDataUnit readUnit(QModbusDataUnit::HoldingRegisters, 0x0001, 1); if (auto *reply = modbusMaster->sendReadRequest(readUnit, pumpAddress)) { if (!reply->isFinished()) { connect(reply, &QModbusReply::errorOccurred, this, [=](QModbusDevice::Error error){ ui->A26->append(QString("[泵%1] 状态查询失败:%2").arg(pumpAddress).arg(reply->errorString())); }); } else { reply->deleteLater(); } } } // 处理Modbus响应 void MainWindow::onModbusResponseReceived(QModbusReply *reply) { if (!reply || reply->isError()) { reply->deleteLater(); return; } // 获取发送指令的泵地址 int pumpAddress = reply->serverAddress(); // 获取响应数据 QModbusDataUnit data = reply->result(); // 区分是读取还是写入响应 if (reply->functionCode() == QModbusRequest::ReadHoldingRegisters) { parseStatus(pumpAddress, data); // 解析状态 } else if (reply->functionCode() == QModbusRequest::WriteSingleRegister) { ui->A26->append(QString("[泵%1] 指令执行成功").arg(pumpAddress)); } reply->deleteLater(); } // 解析泵状态 void MainWindow::parseStatus(int pumpAddress, const QModbusDataUnit &data) { if (data.valueCount() == 0) return; quint16 status = data.value(0); QString statusStr = (status == 1) ? "运行中" : "已停止"; // 更新对应泵的状态标签 if (pumpAddress == 1) ui->A25->setText(statusStr); else if (pumpAddress == 2) ui->A27->setText(statusStr); else if (pumpAddress == 3) ui->A28->setText(statusStr); else if (pumpAddress == 4) ui->A29->setText(statusStr); ui->A26->append(QString("[泵%1] 状态:%2").arg(pumpAddress).arg(statusStr)); } // 泵1控制(启动) void MainWindow::on_A4_clicked() { // 假设启动寄存器为0x0000,值1为启动(需参考手册) sendModbusCommand(1, 0x0000, 1); } // 泵1控制(停止) void MainWindow::on_A5_clicked() { sendModbusCommand(1, 0x0000, 0); // 0为停止 } // 泵1调速(0~100%对应寄存器值0~1000) void MainWindow::on_A6_valueChanged(int value) { quint16 speed = value * 10; // 假设100%对应1000 sendModbusCommand(1, 0x0002, speed); // 转速寄存器0x0002 ui->A16->setText(QString("泵1速度%1%").arg(value)); } // 泵2控制(启动) void MainWindow::on_A7_clicked() { // 假设启动寄存器为0x0000,值1为启动(需参考手册) sendModbusCommand(1, 0x0000, 1); } // 泵2控制(停止) void MainWindow::on_A8_clicked() { sendModbusCommand(1, 0x0000, 0); // 0为停止 } // 泵2调速(0~100%对应寄存器值0~1000) void MainWindow::on_A9_valueChanged(int value) { quint16 speed = value * 10; // 假设100%对应1000 sendModbusCommand(1, 0x0002, speed); // 转速寄存器0x0002 ui->A17->setText(QString("泵1速度%1%").arg(value)); } // 泵3控制(启动) void MainWindow::on_A10_clicked() { // 假设启动寄存器为0x0000,值1为启动(需参考手册) sendModbusCommand(1, 0x0000, 1); } // 泵3控制(停止) void MainWindow::on_A11_clicked() { sendModbusCommand(1, 0x0000, 0); // 0为停止 } // 泵3调速(0~100%对应寄存器值0~1000) void MainWindow::on_A12_valueChanged(int value) { quint16 speed = value * 10; // 假设100%对应1000 sendModbusCommand(1, 0x0002, speed); // 转速寄存器0x0002 ui->A18->setText(QString("泵1速度%1%").arg(value)); } // 泵4控制(启动) void MainWindow::on_A13_clicked() { // 假设启动寄存器为0x0000,值1为启动(需参考手册) sendModbusCommand(1, 0x0000, 1); } // 泵4控制(停止) void MainWindow::on_A14_clicked() { sendModbusCommand(1, 0x0000, 0); // 0为停止 } // 泵4调速(0~100%对应寄存器值0~1000) void MainWindow::on_A15_valueChanged(int value) { quint16 speed = value * 10; // 假设100%对应1000 sendModbusCommand(4, 0x0002, speed); // 转速寄存器0x0002 ui->A19->setText(QString("泵1速度%1%").arg(value)); } // 泵2~4的控制函数泵1相同,只需替换地址(2、3、4) // ...(省略泵2~4的槽函数,复制泵1代码并修改地址即可)
08-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值