Просмотр исходного кода

多线程读取寄存器

master
鹏鹏 李 1 день назад
Родитель
Сommit
99e5dbb94d
8 измененных файлов: 292 добавлений и 167 удалений
  1. +2
    -0
      editor.pro
  2. +1
    -1
      editor.pro.user
  3. +4
    -0
      main.cpp
  4. +7
    -0
      mainwindow.cpp
  5. +37
    -151
      modbusmanager.cpp
  6. +10
    -15
      modbusmanager.h
  7. +184
    -0
      modbusworker.cpp
  8. +47
    -0
      modbusworker.h

+ 2
- 0
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 \


+ 1
- 1
editor.pro.user Просмотреть файл

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.11.1, 2025-08-13T11:12:10. -->
<!-- Written by QtCreator 4.11.1, 2025-08-13T17:04:04. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>


+ 4
- 0
main.cpp Просмотреть файл

@@ -8,6 +8,10 @@ int main(int argc, char *argv[])
// 设置应用程序信息
QApplication::setApplicationName("PLC梯形图编辑器");
QApplication::setApplicationVersion("1.0");
qRegisterMetaType<QSerialPort::BaudRate>("QSerialPort::BaudRate");
qRegisterMetaType<QSerialPort::DataBits>("QSerialPort::DataBits");
qRegisterMetaType<QSerialPort::Parity>("QSerialPort::Parity");
qRegisterMetaType<QSerialPort::StopBits>("QSerialPort::StopBits");

MainWindow w;
w.resize(1000, 600);


+ 7
- 0
mainwindow.cpp Просмотреть файл

@@ -13,6 +13,7 @@
#include <QAction>
#include <QFileDialog>
#include "creatitem.h"
#include <QDebug>

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,


+ 37
- 151
modbusmanager.cpp Просмотреть файл

@@ -1,58 +1,53 @@
#include "modbusmanager.h"
#include <QModbusDataUnit>
#include <QDebug>
#include <QThread>

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<QString, QSet<int>> 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<int> &addresses)
{
if (addresses.isEmpty()) return;

QList<int> 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<QModbusReply*>(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);
}

+ 10
- 15
modbusmanager.h Просмотреть файл

@@ -2,11 +2,10 @@
#define MODBUSMANAGER_H

#include <QObject>
#include <QModbusRtuSerialMaster>
#include <QSerialPort>
#include <QTimer>
#include <QMap>
#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<int> &addresses);
void readAddressRange(QModbusDataUnit::RegisterType type, int startAddr, int count);

private:
QModbusRtuSerialMaster *modbusDevice;
RegisterManager* registerManager;
ModbusWorker* worker;
QTimer* pollTimer;
int slaveAddress = 1; // 默认从站地址
QMap<QModbusReply*, QString> pendingRequests;
QThread* modbusThread;
};

#endif // MODBUSMANAGER_H

+ 184
- 0
modbusworker.cpp Просмотреть файл

@@ -0,0 +1,184 @@
#include "modbusworker.h"
#include <QModbusDataUnit>
#include <QDebug>
#include <QSerialPort>

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<QString, QSet<int>> 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<int> &addresses)
{
if (addresses.isEmpty()) return;

QList<int> 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<QModbusReply*>(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();
});
}
}

+ 47
- 0
modbusworker.h Просмотреть файл

@@ -0,0 +1,47 @@
#ifndef MODBUSWORKER_H
#define MODBUSWORKER_H

#include <QObject>
#include <QTimer>
#include <QModbusRtuSerialMaster>
#include <QSerialPort>
#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<int> &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<QModbusReply*, QString> pendingRequests;
};

#endif // MODBUSWORKER_H

Загрузка…
Отмена
Сохранить