瀏覽代碼

子线程实现轮训读线圈,写线圈暂时有问题版本

main
email 2 天之前
父節點
當前提交
04477bfec7
共有 4 個檔案被更改,包括 156 行新增67 行删除
  1. +3
    -3
      untitled/hmidocument.cpp
  2. +113
    -55
      untitled/modbussimulator.cpp
  3. +39
    -8
      untitled/modbussimulator.h
  4. +1
    -1
      untitled/untitled.pro.user

+ 3
- 3
untitled/hmidocument.cpp 查看文件

@@ -103,9 +103,9 @@ void HMIDocument::startSimulation()
QMessageBox::warning(nullptr, "仿真启动", "没有找到有效的线圈地址绑定");
return;
}
if (!m_modbusSimulator) {
m_modbusSimulator = new ModbusSimulator(this);
m_modbusSimulator = new ModbusSimulator(this);
if (m_modbusSimulator)
{
connect(m_modbusSimulator, &ModbusSimulator::coilStatusRead,
this, &HMIDocument::onCoilStatusRead);
connect(m_modbusSimulator, &ModbusSimulator::errorOccurred,


+ 113
- 55
untitled/modbussimulator.cpp 查看文件

@@ -2,13 +2,81 @@
#include <QSerialPort>
#include <QDebug>
#include <algorithm>
#include<QThread>
#include <QCoreApplication>
#include <atomic>

// PollingWorker 实现
PollingWorker::PollingWorker(QModbusRtuSerialMaster *client,
QMutex *mutex,
QSet<int> *addresses,
std::atomic<bool> *runningFlag,
QObject *parent)
: QObject(parent),
m_modbusClient(client),
m_mutex(mutex),
m_coilAddresses(addresses),
m_runningFlag(runningFlag),
m_stop(false)
{
}

void PollingWorker::startPolling(int interval)
{
while (!m_stop) {
QThread::msleep(interval); // 使用线程休眠替代定时器
if (!m_stop && *m_runningFlag) {
performCoilReading();
}
}
}

void PollingWorker::performCoilReading()
{
QSet<int> addressesCopy;
{
QMutexLocker locker(m_mutex);
if (m_coilAddresses->isEmpty()) return;
addressesCopy = *m_coilAddresses;
}

int minAddress = *std::min_element(addressesCopy.begin(), addressesCopy.end());
int maxAddress = *std::max_element(addressesCopy.begin(), addressesCopy.end());
int count = maxAddress - minAddress + 1;

QModbusDataUnit readUnit(QModbusDataUnit::Coils, minAddress, count);
if (auto *reply = m_modbusClient->sendReadRequest(readUnit, 1)) {
if (!reply->isFinished()) {
auto safeAddresses = QSharedPointer<QSet<int>>::create(addressesCopy);
connect(reply, &QModbusReply::finished, [this, reply, safeAddresses]() {
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
for (int i = 0; i < unit.valueCount(); ++i) {
int address = unit.startAddress() + i;
bool state = unit.value(i);
if (safeAddresses->contains(address)) {
emit coilReadResult(address, state);
}
}
} else {
emit errorOccurred(reply->errorString());
}
reply->deleteLater();
});
} else {
delete reply;
}
}
}

// ModbusSimulator 实现
ModbusSimulator::ModbusSimulator(QObject *parent)
: QObject(parent), m_coilAddresses(),m_running(false), m_mutex()
: QObject(parent),
m_coilAddresses(),
m_running(false),
m_workerThread(nullptr),
m_worker(nullptr)
{
m_modbusClient = new QModbusRtuSerialMaster(this);
m_readTimer = new QTimer(this);
connect(m_readTimer, &QTimer::timeout, this, &ModbusSimulator::readCoils);
}

ModbusSimulator::~ModbusSimulator()
@@ -23,9 +91,7 @@ bool ModbusSimulator::isRunning() const

void ModbusSimulator::startSimulation()
{
qDebug() << "进入 startSimulation() 函数";
if (m_running) return;
qDebug() << "启动Modbus仿真555...";
// 配置Modbus连接
m_modbusClient->setConnectionParameter(QModbusDevice::SerialPortNameParameter, "COM1");
m_modbusClient->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);
@@ -38,35 +104,64 @@ void ModbusSimulator::startSimulation()
emit errorOccurred("无法连接Modbus设备");
return;
}
qDebug() << "Modbus设备连接成功";
m_modbusClient->moveToThread(m_workerThread);
m_running = true;
m_readTimer->start(1000); // 每秒读取一次

// 创建工作线程和Worker
m_workerThread = new QThread(this);
m_worker = new PollingWorker(m_modbusClient, &m_mutex, &m_coilAddresses, &m_running);
m_worker->moveToThread(m_workerThread);

// 连接信号槽
connect(m_worker, &PollingWorker::coilReadResult,
this, &ModbusSimulator::coilStatusRead);
connect(m_worker, &PollingWorker::errorOccurred,
this, &ModbusSimulator::errorOccurred);
connect(m_workerThread, &QThread::started, [this]() {
m_worker->startPolling(500); // 每秒轮询一次
});
connect(m_workerThread, &QThread::finished,
m_worker, &QObject::deleteLater);
connect(m_workerThread, &QThread::finished,
m_workerThread, &QObject::deleteLater);

m_workerThread->start();
}

void ModbusSimulator::stopSimulation()
{
if (!m_running) return;

m_readTimer->stop();
m_modbusClient->disconnectDevice();
m_running = false;

if (m_worker) {
m_worker->stop(); // 通过公共接口设置停止标志
}

if (m_workerThread && m_workerThread->isRunning()) {
m_workerThread->quit();
m_workerThread->wait();
}

if (m_modbusClient) {
m_modbusClient->disconnectDevice();
}
}

void ModbusSimulator::setCoilAddresses(const QSet<int> &addresses)
{
qDebug() <<"执行到此";
qDebug() << "setCoilAddresses called, this:" << this; // 打印对象地址
QMutexLocker locker(&m_mutex); // 必须加锁
m_coilAddresses = QSet<int>(addresses);
{ //qDebug()<<"这里";
QMutexLocker locker(&m_mutex);
qDebug()<<"这里2";
m_coilAddresses = addresses;
}

void ModbusSimulator::writeCoil(int address, bool state)
{
if (!m_running) return;

if (auto reply = m_modbusClient->sendWriteRequest(
QModbusDataUnit(QModbusDataUnit::Coils, address, {state}), 1)) {
QModbusDataUnit(QModbusDataUnit::Coils, address, {state}), 1))
{
connect(reply, &QModbusReply::finished, [reply, address]() {
if (reply->error() != QModbusDevice::NoError) {
qWarning() << "写线圈失败:" << reply->errorString() << "地址:" << address;
@@ -75,40 +170,3 @@ void ModbusSimulator::writeCoil(int address, bool state)
});
}
}

void ModbusSimulator::readCoils()
{
QSet<int> addressesCopy;
{
QMutexLocker locker(&m_mutex);
if (!m_running || m_coilAddresses.isEmpty()) return;
addressesCopy = m_coilAddresses; // 在锁保护下复制
}
int minAddress = *std::min_element(addressesCopy.begin(), addressesCopy.end());
int maxAddress = *std::max_element(addressesCopy.begin(), addressesCopy.end());
int count = maxAddress - minAddress + 1;

// 创建读请求
QModbusDataUnit readUnit(QModbusDataUnit::Coils, minAddress, count);
if (auto *reply = m_modbusClient->sendReadRequest(readUnit, 1)) {
if (!reply->isFinished()) {
// 使用智能指针确保地址集合在回调中有效
auto safeAddresses = QSharedPointer<QSet<int>>::create(addressesCopy);
connect(reply, &QModbusReply::finished, this, [this, reply, safeAddresses]() {
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
for (int i = 0; i < unit.valueCount(); ++i) {
int address = unit.startAddress() + i;
bool state = unit.value(i);
if (safeAddresses->contains(address)) {
emit coilStatusRead(address, state);
}
}
}
reply->deleteLater();
});
} else {
delete reply;
}
}
}

+ 39
- 8
untitled/modbussimulator.h 查看文件

@@ -3,9 +3,13 @@

#include <QObject>
#include <QModbusRtuSerialMaster>
#include <QTimer>
#include <QSet>
#include <QMutex> // 新增:互斥锁头文件
#include <QMutex>
#include <QThread>
#include <atomic>

class PollingWorker; // 前向声明

class ModbusSimulator : public QObject
{
Q_OBJECT
@@ -25,15 +29,42 @@ signals:
void coilStatusRead(int address, bool state);
void errorOccurred(const QString &message);

private slots:
void readCoils();

private:
QModbusRtuSerialMaster *m_modbusClient;
QTimer *m_readTimer;
QSet<int> m_coilAddresses;
bool m_running;
QMutex m_mutex; // 新增:保护m_coilAddresses的互斥锁
std::atomic<bool> m_running;
QMutex m_mutex;
QThread *m_workerThread;
PollingWorker *m_worker;
};

// 轮询工作线程类
class PollingWorker : public QObject
{
Q_OBJECT
public:
void stop() { m_stop = true; } // 新增公共接口
explicit PollingWorker(QModbusRtuSerialMaster *client,
QMutex *mutex,
QSet<int> *addresses,
std::atomic<bool> *runningFlag,
QObject *parent = nullptr);

public slots:
void startPolling(int interval);

signals:
void coilReadResult(int address, bool state);
void errorOccurred(const QString &message);

private:
void performCoilReading();

QModbusRtuSerialMaster *m_modbusClient;
QMutex *m_mutex;
QSet<int> *m_coilAddresses;
std::atomic<bool> *m_runningFlag;
std::atomic<bool> m_stop;
};

#endif // MODBUSSIMULATOR_H

+ 1
- 1
untitled/untitled.pro.user 查看文件

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.11.1, 2025-08-14T12:27:31. -->
<!-- Written by QtCreator 4.11.1, 2025-08-14T14:19:55. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>


Loading…
取消
儲存