From 99e5dbb94d1301bf1b4ae054ecde91352e9ac30b Mon Sep 17 00:00:00 2001 From: lipengpeng Date: Wed, 13 Aug 2025 17:04:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E5=AF=84=E5=AD=98=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- editor.pro | 2 + editor.pro.user | 2 +- main.cpp | 4 + mainwindow.cpp | 7 ++ modbusmanager.cpp | 188 +++++++++------------------------------------- modbusmanager.h | 25 +++--- modbusworker.cpp | 184 +++++++++++++++++++++++++++++++++++++++++++++ modbusworker.h | 47 ++++++++++++ 8 files changed, 292 insertions(+), 167 deletions(-) create mode 100644 modbusworker.cpp create mode 100644 modbusworker.h diff --git a/editor.pro b/editor.pro index 695bcfa..bd41e7e 100644 --- a/editor.pro +++ b/editor.pro @@ -30,6 +30,7 @@ SOURCES += \ main.cpp \ mainwindow.cpp \ modbusmanager.cpp \ + modbusworker.cpp \ mygraphicsview.cpp \ myscene.cpp \ plc.cpp \ @@ -48,6 +49,7 @@ HEADERS += \ light.h \ mainwindow.h \ modbusmanager.h \ + modbusworker.h \ mygraphicsview.h \ myscene.h \ plc.h \ diff --git a/editor.pro.user b/editor.pro.user index 96aecba..71d2d67 100644 --- a/editor.pro.user +++ b/editor.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/main.cpp b/main.cpp index 1136a77..31333a6 100644 --- a/main.cpp +++ b/main.cpp @@ -8,6 +8,10 @@ int main(int argc, char *argv[]) // 设置应用程序信息 QApplication::setApplicationName("PLC梯形图编辑器"); QApplication::setApplicationVersion("1.0"); + qRegisterMetaType("QSerialPort::BaudRate"); + qRegisterMetaType("QSerialPort::DataBits"); + qRegisterMetaType("QSerialPort::Parity"); + qRegisterMetaType("QSerialPort::StopBits"); MainWindow w; w.resize(1000, 600); diff --git a/mainwindow.cpp b/mainwindow.cpp index f3da4a5..b8cb700 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -13,6 +13,7 @@ #include #include #include "creatitem.h" +#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -56,6 +57,12 @@ MainWindow::MainWindow(QWidget *parent) connect(modbusManager, &ModbusManager::connectionStatusChanged, this, &MainWindow::updateConnectionStatus); + connect(modbusManager, &ModbusManager::registerValueUpdated, + registerManager, &RegisterManager::updateRegisterValue); + connect(modbusManager, &ModbusManager::errorOccurred, + this, [this](const QString& error) { + ui->textEdit->append("错误: " + error); + }); // connect(modbusManager, &ModbusManager::connectionStatusChanged, // this, &PLC::updateConnectionStatus); // connect(modbusManager, &ModbusManager::errorOccurred, diff --git a/modbusmanager.cpp b/modbusmanager.cpp index 8b95c5a..6afd9c6 100644 --- a/modbusmanager.cpp +++ b/modbusmanager.cpp @@ -1,58 +1,53 @@ #include "modbusmanager.h" -#include -#include +#include ModbusManager::ModbusManager(RegisterManager* regManager, QObject *parent) - : QObject(parent), registerManager(regManager) + : QObject(parent) { - modbusDevice = new QModbusRtuSerialMaster(this); + modbusThread = new QThread(this); + worker = new ModbusWorker(regManager); pollTimer = new QTimer(this); + worker->moveToThread(modbusThread); - connect(modbusDevice, &QModbusClient::errorOccurred, this, - [this](QModbusDevice::Error) { - emit errorOccurred(modbusDevice->errorString()); - }); + // 连接工作线程信号 + connect(worker, &ModbusWorker::connectionStatusChanged, + this, &ModbusManager::connectionStatusChanged); + connect(worker, &ModbusWorker::errorOccurred, + this, &ModbusManager::errorOccurred); + connect(worker, &ModbusWorker::registerValueUpdated, + this, &ModbusManager::registerValueUpdated); connect(pollTimer, &QTimer::timeout, this, &ModbusManager::readRegisters); + connect(modbusThread, &QThread::started, worker, &ModbusWorker::initModbusDevice); + + modbusThread->start(); } ModbusManager::~ModbusManager() { - stopSimulation(); - disconnectDevice(); + modbusThread->quit(); + modbusThread->wait(); + delete worker; + pollTimer->stop(); } -bool ModbusManager::connectToDevice(const QString& portName, - QSerialPort::BaudRate baudRate, - QSerialPort::DataBits dataBits, - QSerialPort::Parity parity, - QSerialPort::StopBits stopBits) +void ModbusManager::connectToDevice(const QString& portName, + QSerialPort::BaudRate baudRate, + QSerialPort::DataBits dataBits, + QSerialPort::Parity parity, + QSerialPort::StopBits stopBits) { - if (modbusDevice->state() != QModbusDevice::UnconnectedState) { - disconnectDevice(); - } - - modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, portName); - modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudRate); - modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits); - modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, parity); - modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits); - - if (!modbusDevice->connectDevice()) { - emit errorOccurred(tr("连接失败: %1").arg(modbusDevice->errorString())); - return false; - } - - emit connectionStatusChanged(true); - return true; + QMetaObject::invokeMethod(worker, "connectToDevice", Qt::QueuedConnection, + Q_ARG(QString, portName), + Q_ARG(QSerialPort::BaudRate, baudRate), + Q_ARG(QSerialPort::DataBits, dataBits), + Q_ARG(QSerialPort::Parity, parity), + Q_ARG(QSerialPort::StopBits, stopBits)); } void ModbusManager::disconnectDevice() { - if (modbusDevice->state() != QModbusDevice::UnconnectedState) { - modbusDevice->disconnectDevice(); - emit connectionStatusChanged(false); - } + QMetaObject::invokeMethod(worker, "disconnectDevice", Qt::QueuedConnection); } void ModbusManager::startSimulation(int interval) @@ -65,123 +60,14 @@ void ModbusManager::stopSimulation() pollTimer->stop(); } -void ModbusManager::readRegisters() -{ - if (!modbusDevice || modbusDevice->state() != QModbusDevice::ConnectedState) - return; - - // 获取所有已注册的寄存器ID - QStringList regIds = registerManager->getAllRegisteredRegisters(); - QMap> regMap; // 按类型分组存储地址 - - // 分组寄存器地址 - for (const QString &id : regIds) { - if (id.startsWith("D") || id.startsWith("M")) { - bool ok; - int addr = id.mid(1).toInt(&ok); - if (ok && addr >= 0 && addr <= 4000) { - regMap[id.left(1)].insert(addr); - } - } - } - - // 读取D寄存器 (保持寄存器) - if (regMap.contains("D")) { - readRegisterGroup(QModbusDataUnit::HoldingRegisters, regMap["D"].values()); - } - - // 读取M寄存器 (线圈) - if (regMap.contains("M")) { - readRegisterGroup(QModbusDataUnit::Coils, regMap["M"].values()); - } -} - -void ModbusManager::readRegisterGroup(QModbusDataUnit::RegisterType type, const QList &addresses) -{ - if (addresses.isEmpty()) return; - - QList sortedAddrs = addresses; - std::sort(sortedAddrs.begin(), sortedAddrs.end()); - - // 合并连续地址范围 - int start = sortedAddrs.first(); - int end = start; - - for (int i = 1; i < sortedAddrs.size(); i++) { - if (sortedAddrs[i] == end + 1) { - end = sortedAddrs[i]; - } else { - readAddressRange(type, start, end - start + 1); - start = sortedAddrs[i]; - end = start; - } - } - readAddressRange(type, start, end - start + 1); -} - -void ModbusManager::readAddressRange(QModbusDataUnit::RegisterType type, int startAddr, int count) -{ - const int MAX_REG_PER_REQUEST = 120; - - for (int offset = 0; offset < count; offset += MAX_REG_PER_REQUEST) { - int readCount = qMin(MAX_REG_PER_REQUEST, count - offset); - QModbusDataUnit unit(type, startAddr + offset, readCount); - - if (auto *reply = modbusDevice->sendReadRequest(unit, slaveAddress)) { - QString regType = (type == QModbusDataUnit::HoldingRegisters) ? "D" : "M"; - pendingRequests[reply] = regType; - connect(reply, &QModbusReply::finished, this, &ModbusManager::processModbusReply); - } - } -} - -void ModbusManager::processModbusReply() +void ModbusManager::writeRegister(const QString& registerId, quint16 value) { - auto *reply = qobject_cast(sender()); - if (!reply) return; - - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - QString regType = pendingRequests.value(reply); - - int startAddr = unit.startAddress(); - - for (uint i = 0; i < unit.valueCount(); i++) { - int regAddr = startAddr + i; - quint16 value = unit.value(i); - - QString regId = QString("%1%2").arg(regType).arg(regAddr); - - // 更新图元状态 - registerManager->updateRegisterValue(regId, value); - } - } else { - emit errorOccurred(tr("Modbus错误: %1").arg(reply->errorString())); - } - - pendingRequests.remove(reply); - reply->deleteLater(); + QMetaObject::invokeMethod(worker, "writeRegister", Qt::QueuedConnection, + Q_ARG(QString, registerId), + Q_ARG(quint16, value)); } -void ModbusManager::writeRegister(const QString& registerId, quint16 value) +void ModbusManager::readRegisters() { - if (registerId.isEmpty()) return; - - QModbusDataUnit::RegisterType regType = registerId.startsWith("D") - ? QModbusDataUnit::HoldingRegisters - : QModbusDataUnit::Coils; - - int regAddr = registerId.mid(1).toInt(); - - QModbusDataUnit writeUnit(regType, regAddr, 1); - writeUnit.setValue(0, value); - - if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, slaveAddress)) { - connect(reply, &QModbusReply::finished, this, [this, reply]() { - if (reply->error() != QModbusDevice::NoError) { - emit errorOccurred(tr("写入失败: %1").arg(reply->errorString())); - } - reply->deleteLater(); - }); - } + QMetaObject::invokeMethod(worker, "readRegisters", Qt::QueuedConnection); } diff --git a/modbusmanager.h b/modbusmanager.h index d162da5..9d54fcc 100644 --- a/modbusmanager.h +++ b/modbusmanager.h @@ -2,11 +2,10 @@ #define MODBUSMANAGER_H #include -#include -#include -#include -#include -#include "registermanager.h" +#include "modbusworker.h" + +class RegisterManager; +class QThread; class ModbusManager : public QObject { @@ -16,7 +15,7 @@ public: ~ModbusManager(); // 串口连接管理 - bool connectToDevice(const QString& portName, + void connectToDevice(const QString& portName, QSerialPort::BaudRate baudRate = QSerialPort::Baud9600, QSerialPort::DataBits dataBits = QSerialPort::Data8, QSerialPort::Parity parity = QSerialPort::NoParity, @@ -32,24 +31,20 @@ public: void writeRegister(const QString& registerId, quint16 value); // 设置从站地址 - void setSlaveAddress(int address) { slaveAddress = address; } +// void setSlaveAddress(int address) { worker->setSlaveAddress(address); } signals: void connectionStatusChanged(bool connected); void errorOccurred(const QString& error); + void registerValueUpdated(const QString& registerId, quint16 value); -private slots: +public slots: void readRegisters(); - void processModbusReply(); - void readRegisterGroup(QModbusDataUnit::RegisterType type, const QList &addresses); - void readAddressRange(QModbusDataUnit::RegisterType type, int startAddr, int count); private: - QModbusRtuSerialMaster *modbusDevice; - RegisterManager* registerManager; + ModbusWorker* worker; QTimer* pollTimer; - int slaveAddress = 1; // 默认从站地址 - QMap pendingRequests; + QThread* modbusThread; }; #endif // MODBUSMANAGER_H diff --git a/modbusworker.cpp b/modbusworker.cpp new file mode 100644 index 0000000..20d4f27 --- /dev/null +++ b/modbusworker.cpp @@ -0,0 +1,184 @@ +#include "modbusworker.h" +#include +#include +#include + +ModbusWorker::ModbusWorker(RegisterManager* regManager, QObject *parent) + : QObject(parent), registerManager(regManager) +{ +// modbusDevice = new QModbusRtuSerialMaster(this); +// connect(modbusDevice, &QModbusClient::errorOccurred, this, +// [this](QModbusDevice::Error) { +// emit errorOccurred(modbusDevice->errorString()); +// }); +} + +ModbusWorker::~ModbusWorker() +{ + disconnectDevice(); +} + +bool ModbusWorker::connectToDevice(const QString& portName, + QSerialPort::BaudRate baudRate, + QSerialPort::DataBits dataBits, + QSerialPort::Parity parity, + QSerialPort::StopBits stopBits) +{ + if (!modbusDevice) { // 新增检查 + emit errorOccurred("Modbus设备未初始化"); + return false; + } + if (modbusDevice->state() != QModbusDevice::UnconnectedState) { + disconnectDevice(); + } + + modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, portName); + modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudRate); + modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits); + modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, parity); + modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits); + + if (!modbusDevice->connectDevice()) { + emit errorOccurred(tr("连接失败: %1").arg(modbusDevice->errorString())); + return false; + } + + emit connectionStatusChanged(true); + return true; +} + +void ModbusWorker::disconnectDevice() +{ + if (modbusDevice->state() != QModbusDevice::UnconnectedState) { + modbusDevice->disconnectDevice(); + emit connectionStatusChanged(false); + } +} + +void ModbusWorker::initModbusDevice() +{ + modbusDevice = new QModbusRtuSerialMaster(this); + connect(modbusDevice, &QModbusClient::errorOccurred, this, + [this](QModbusDevice::Error) { + emit errorOccurred(modbusDevice->errorString()); + }); +} + +void ModbusWorker::readRegisters() +{ + if (!modbusDevice || modbusDevice->state() != QModbusDevice::ConnectedState) + return; + + // 获取所有已注册的寄存器ID + QStringList regIds = registerManager->getAllRegisteredRegisters(); + QMap> regMap; + + for (const QString &id : regIds) { + if (id.startsWith("D") || id.startsWith("M")) { + bool ok; + int addr = id.mid(1).toInt(&ok); + if (ok && addr >= 0 && addr <= 4000) { + regMap[id.left(1)].insert(addr); + } + } + } + + if (regMap.contains("D")) { + readRegisterGroup(QModbusDataUnit::HoldingRegisters, regMap["D"].values()); + } + + if (regMap.contains("M")) { + readRegisterGroup(QModbusDataUnit::Coils, regMap["M"].values()); + } +} + +void ModbusWorker::readRegisterGroup(QModbusDataUnit::RegisterType type, const QList &addresses) +{ + if (addresses.isEmpty()) return; + + QList sortedAddrs = addresses; + std::sort(sortedAddrs.begin(), sortedAddrs.end()); + + int start = sortedAddrs.first(); + int end = start; + + for (int i = 1; i < sortedAddrs.size(); i++) { + if (sortedAddrs[i] == end + 1) { + end = sortedAddrs[i]; + } else { + readAddressRange(type, start, end - start + 1); + start = sortedAddrs[i]; + end = start; + } + } + readAddressRange(type, start, end - start + 1); +} + +void ModbusWorker::readAddressRange(QModbusDataUnit::RegisterType type, int startAddr, int count) +{ + const int MAX_REG_PER_REQUEST = 120; + + for (int offset = 0; offset < count; offset += MAX_REG_PER_REQUEST) { + int readCount = qMin(MAX_REG_PER_REQUEST, count - offset); + QModbusDataUnit unit(type, startAddr + offset, readCount); + + if (auto *reply = modbusDevice->sendReadRequest(unit, slaveAddress)) { + QString regType = (type == QModbusDataUnit::HoldingRegisters) ? "D" : "M"; + pendingRequests[reply] = regType; + connect(reply, &QModbusReply::finished, this, &ModbusWorker::processModbusReply); + } + } +} + +void ModbusWorker::processModbusReply() +{ + auto *reply = qobject_cast(sender()); + if (!reply) return; + + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + QString regType = pendingRequests.value(reply); + + int startAddr = unit.startAddress(); + + for (uint i = 0; i < unit.valueCount(); i++) { + int regAddr = startAddr + i; + quint16 value = unit.value(i); + + QString regId = QString("%1%2").arg(regType).arg(regAddr); + emit registerValueUpdated(regId, value); + } + } else { + emit errorOccurred(tr("Modbus错误: %1").arg(reply->errorString())); + } + + pendingRequests.remove(reply); + reply->deleteLater(); +} + +void ModbusWorker::writeRegister(const QString& registerId, quint16 value) +{ + if (!modbusDevice) { + emit errorOccurred("Modbus设备未初始化"); + return; + } + if (registerId.isEmpty()) return; + + QModbusDataUnit::RegisterType regType = registerId.startsWith("D") + ? QModbusDataUnit::HoldingRegisters + : QModbusDataUnit::Coils; + + int regAddr = registerId.mid(1).toInt(); + + QModbusDataUnit writeUnit(regType, regAddr, 1); + writeUnit.setValue(0, value); + + if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, slaveAddress)) { + connect(reply, &QModbusReply::finished, this, [this, reply]() { + if (reply->error() != QModbusDevice::NoError) { + emit errorOccurred(tr("写入失败: %1").arg(reply->errorString())); + } + reply->deleteLater(); + }); + } +} diff --git a/modbusworker.h b/modbusworker.h new file mode 100644 index 0000000..4804ac8 --- /dev/null +++ b/modbusworker.h @@ -0,0 +1,47 @@ +#ifndef MODBUSWORKER_H +#define MODBUSWORKER_H + +#include +#include +#include +#include +#include "registermanager.h" + +class ModbusWorker : public QObject +{ + Q_OBJECT +public: + explicit ModbusWorker(RegisterManager* regManager, QObject *parent = nullptr); + ~ModbusWorker(); + +public slots: +// void startSimulation(int interval = 500); +// void stopSimulation(); + void writeRegister(const QString& registerId, quint16 value); + bool connectToDevice(const QString& portName, + QSerialPort::BaudRate baudRate, + QSerialPort::DataBits dataBits, + QSerialPort::Parity parity, + QSerialPort::StopBits stopBits); + void disconnectDevice(); + void initModbusDevice(); + +private slots: + void readRegisters(); + void processModbusReply(); + void readRegisterGroup(QModbusDataUnit::RegisterType type, const QList &addresses); + void readAddressRange(QModbusDataUnit::RegisterType type, int startAddr, int count); + +signals: + void connectionStatusChanged(bool connected); + void errorOccurred(const QString& error); + void registerValueUpdated(const QString& registerId, quint16 value); + +private: + QModbusRtuSerialMaster *modbusDevice = nullptr; + RegisterManager* registerManager; + int slaveAddress = 1; + QMap pendingRequests; +}; + +#endif // MODBUSWORKER_H