Pārlūkot izejas kodu

实现HMI的modbus通信

master
付春阳 pirms 19 stundām
vecāks
revīzija
04137d0271
9 mainītis faili ar 251 papildinājumiem un 13 dzēšanām
  1. +8
    -1
      customgraphics.cpp
  2. +5
    -1
      customgraphics.h
  3. +0
    -9
      customgraphicsscene.cpp
  4. +46
    -1
      hmimodule.cpp
  5. +6
    -1
      hmimodule.h
  6. +18
    -0
      mainwindow.cpp
  7. +3
    -0
      mainwindow.h
  8. +124
    -0
      modbusmanager.cpp
  9. +41
    -0
      modbusmanager.h

+ 8
- 1
customgraphics.cpp Parādīt failu

@@ -402,6 +402,7 @@ void HmiButton::setOn(bool on)
setColor(m_onColor);
else
setColor(m_offColor);
emit stateChanged(m_isOn); // 通知 HMIModule 更新
update();
}
}
@@ -414,10 +415,16 @@ QRectF HmiButton::boundingRect() const
void HmiButton::paintShape(QPainter *painter)
{
painter->setPen(Qt::NoPen);
painter->setBrush(m_color);
painter->setBrush(m_isOn ? m_onColor : m_offColor);
painter->drawRect(boundingRect());
}

void HmiButton::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
// 让基类处理其他情况(选择、拖动等)
HmiComponent::mousePressEvent(event);
}

HmiIndicator::HmiIndicator(QGraphicsItem *parent) : HmiComponent(parent)
{
// 指示灯初始为圆形


+ 5
- 1
customgraphics.h Parādīt failu

@@ -87,6 +87,7 @@ protected:
// 按钮类
class HmiButton : public HmiComponent
{
Q_OBJECT
public:
HmiButton(QGraphicsItem *parent = nullptr);
QRectF boundingRect() const override;
@@ -96,9 +97,12 @@ public:
bool isOn() const;
void setOn(bool on);

signals:
void stateChanged(bool on);

protected:
void paintShape(QPainter *painter) override;

void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
private:
bool m_isOn = false; // 默认OFF
};


+ 0
- 9
customgraphicsscene.cpp Parādīt failu

@@ -15,16 +15,7 @@ CustomGraphicsScene::CustomGraphicsScene(QGraphicsView* view, QObject *parent)

void CustomGraphicsScene::setMode(Mode mode)
{
if (m_mode == mode) return;

m_mode = mode;

// 根据模式设置光标
if (m_mode == CreateItem) {
m_view->setCursor(Qt::CrossCursor);
} else {
m_view->setCursor(Qt::ArrowCursor); // 恢复为标准箭头光标
}
}

void CustomGraphicsScene::setComponentTypeToCreate(ComponentType type)


+ 46
- 1
hmimodule.cpp Parādīt failu

@@ -14,10 +14,18 @@
#include <QDebug>

HMIModule::HMIModule(Ui::MainWindow* ui, QObject *parent)
: QObject{parent}, ui_(ui), m_scene(nullptr)
: QObject{parent}, ui_(ui), m_scene(nullptr), m_modbusManager(new ModbusManager(this))
{
// 初始化 m_pageOrder
m_pageOrder.append(1); // 初始页面

// 接收 Modbus 更新
connect(m_modbusManager, &ModbusManager::coilUpdated, this, [this](int address, bool value){
updateComponentsByAddress(address, value);
});

// 接收日志
connect(m_modbusManager, &ModbusManager::logMessage, this, &HMIModule::logMessageGenerated);
}

void HMIModule::setButtonIcon(QAbstractButton *button, const QString &iconPath)
@@ -391,6 +399,11 @@ void HMIModule::setModified(bool modified)
m_isModified = modified;
}

ModbusManager *HMIModule::getModbusManager() const
{
return m_modbusManager;
}

void HMIModule::setupNewComponent(HmiComponent* item)
{
if (!item) return;
@@ -401,12 +414,44 @@ void HMIModule::setupNewComponent(HmiComponent* item)
connect(item, &HmiComponent::changeOnColorRequested, this, &HMIModule::onChangeOnColorRequested);
connect(item, &HmiComponent::changeOffColorRequested, this, &HMIModule::onChangeOffColorRequested);

if (auto *btn = dynamic_cast<HmiButton*>(item)) {
connect(btn, &HmiButton::stateChanged, this, [this, btn](bool on){
int addr = btn->address();
updateComponentsByAddress(addr, on);
if (m_modbusManager && m_modbusManager->isRunning()) {
m_modbusManager->writeCoil(addr, on);
}
});
}

QString currentTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
QString log = QString("[%1] 创建 %2 组件").arg(currentTime).arg(item->componentName());
emit logMessageGenerated(log);
}

void HMIModule::updateComponentsByAddress(int address, bool on)
{
QTabWidget* tabWidget = ui_->tabWidget_2;
for (int i = 0; i < tabWidget->count(); ++i) {
QGraphicsView* view = tabWidget->widget(i)->findChild<QGraphicsView*>();
if (!view) continue;

auto scene = view->scene();
for (auto *item : scene->items()) {
if (auto hmi = dynamic_cast<HmiComponent*>(item)) {
if (hmi->address() == address) {
if (auto btn = dynamic_cast<HmiButton*>(hmi)) {
btn->setOn(on); // 按钮联动
} else {
// 非按钮类就按颜色更新
hmi->setColor(on ? hmi->onColor() : hmi->offColor());
}
}
}
}
}
}

void HMIModule::prepareToCreateButton()
{
// 获取当前 TabWidget 中选中的 GraphicsView


+ 6
- 1
hmimodule.h Parādīt failu

@@ -1,9 +1,10 @@
#ifndef HMIMODULE_H
#define HMIMODULE_H

#include <QObject>
#include "ui_MainWindow.h"
#include "customgraphicsscene.h"
#include "modbusmanager.h"
#include <QObject>
#include <QList>
#include <QMap>
#include <QVector>
@@ -21,6 +22,7 @@ public:
void resetPages();
bool isModified() const; // 判断是否有未保存的修改
void setModified(bool modified); // 设置修改状态
ModbusManager* getModbusManager() const;

signals:
void pageAdded(int pageNumber, int index);
@@ -46,6 +48,7 @@ private slots:

private:
void setupNewComponent(HmiComponent* item);
void updateComponentsByAddress(int address, bool on);

private:
Ui::MainWindow* ui_;
@@ -66,6 +69,8 @@ private:
QList<int> m_availablePageNumbers; // 存储可用的页面编号 (有序列表)
QList<int> m_pageOrder; // 维护页面顺序
bool m_isModified = false; // 添加一个修改标志变量

ModbusManager *m_modbusManager;
};

#endif // HMIMODULE_H

+ 18
- 0
mainwindow.cpp Parādīt failu

@@ -23,6 +23,9 @@ MainWindow::MainWindow(QWidget *parent)
connect(ui_->actionNew, &QAction::triggered, this, &MainWindow::onNewFile);
connect(ui_->actionOpen, &QAction::triggered, this, &MainWindow::onOpenFile);
connect(ui_->actionSave, &QAction::triggered, this, &MainWindow::onSaveFile);

connect(ui_->actionStart, &QAction::triggered, this, &MainWindow::startSimulation);
connect(ui_->actionStop, &QAction::triggered, this, &MainWindow::stopSimulation);
}

MainWindow::~MainWindow()
@@ -109,3 +112,18 @@ void MainWindow::onSaveFile()
}
}

void MainWindow::startSimulation()
{
if (hmi_ && hmi_->getModbusManager()) {
// 自己的串口参数,如 COM2 / 9600
hmi_->getModbusManager()->startSimulation("COM2", 9600, QSerialPort::NoParity, QSerialPort::Data8, QSerialPort::OneStop);
}
}

void MainWindow::stopSimulation()
{
if (hmi_ && hmi_->getModbusManager()) {
hmi_->getModbusManager()->stopSimulation();
}
}


+ 3
- 0
mainwindow.h Parādīt failu

@@ -27,6 +27,9 @@ private slots:
void onNewFile();
void onOpenFile();
void onSaveFile();
void startSimulation();
void stopSimulation();


private:
Ui::MainWindow *ui_;


+ 124
- 0
modbusmanager.cpp Parādīt failu

@@ -0,0 +1,124 @@
#include "ModbusManager.h"
#include <QModbusDataUnit>
#include <QModbusReply>
#include <QSerialPort>
#include <QVariant>

ModbusManager::ModbusManager(QObject *parent)
: QObject(parent)
{
}

ModbusManager::~ModbusManager()
{
stopSimulation();
}

bool ModbusManager::startSimulation(const QString &serialPortName,
int baudRate,
int parity,
int dataBits,
int stopBits)
{
if (m_running) {
emit logMessage("仿真已经在运行");
return true;
}

m_modbusDevice = new QModbusRtuSerialClient(this);
if (!m_modbusDevice)
return false;

m_modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, serialPortName);
m_modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, parity);
m_modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudRate);
m_modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits);
m_modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits);
m_modbusDevice->setTimeout(1000);
m_modbusDevice->setNumberOfRetries(3);

if (!m_modbusDevice->connectDevice()) {
emit logMessage("无法连接到 Modbus RTU 从站");
delete m_modbusDevice;
m_modbusDevice = nullptr;
return false;
}

// 定时轮询
m_pollingTimer = new QTimer(this);
connect(m_pollingTimer, &QTimer::timeout, this, &ModbusManager::pollModbusCoils);
m_pollingTimer->start(200); // 200毫秒轮询

m_running = true;
emit logMessage(QString("开始仿真:串口 ") + serialPortName);
return true;
}

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

if (m_pollingTimer) {
m_pollingTimer->stop();
m_pollingTimer->deleteLater();
m_pollingTimer = nullptr;
}
if (m_modbusDevice) {
m_modbusDevice->disconnectDevice();
m_modbusDevice->deleteLater();
m_modbusDevice = nullptr;
}

m_running = false;
emit logMessage("停止仿真");
}

void ModbusManager::pollModbusCoils()
{
if (!m_modbusDevice) return;

int startAddress = 0;
int numberOfCoils = 9; // 根据需要修改

QModbusDataUnit readUnit(QModbusDataUnit::Coils, startAddress, numberOfCoils);

if (auto *reply = m_modbusDevice->sendReadRequest(readUnit, 1)) { // 1 = 从站ID
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, this, [this, reply]() {
if (reply->error() == QModbusDevice::NoError) {
auto result = reply->result();
for (uint i = 0; i < result.valueCount(); ++i) {
int addr = result.startAddress() + i;
bool val = result.value(i);
if (m_coilValues.value(addr) != val) {
m_coilValues[addr] = val;
emit coilUpdated(addr, val);
}
}
} else {
emit logMessage("读取线圈失败: " + reply->errorString());
}
reply->deleteLater();
});
} else {
reply->deleteLater();
}
}
}

void ModbusManager::writeCoil(int address, bool value)
{
if (!m_running || !m_modbusDevice) return;

QModbusDataUnit writeUnit(QModbusDataUnit::Coils, address, 1);
writeUnit.setValue(0, value);

if (auto *reply = m_modbusDevice->sendWriteRequest(writeUnit, 1)) {
connect(reply, &QModbusReply::finished, reply, &QObject::deleteLater);
}
}

bool ModbusManager::isRunning() const
{
return m_running;
}

+ 41
- 0
modbusmanager.h Parādīt failu

@@ -0,0 +1,41 @@
#ifndef MODBUSMANAGER_H
#define MODBUSMANAGER_H

#include <QObject>
#include <qmodbusrtuserialclient.h>
#include <QTimer>
#include <QMap>
#include <QSerialPort>

class ModbusManager : public QObject
{
Q_OBJECT
public:
explicit ModbusManager(QObject *parent = nullptr);
~ModbusManager();

bool startSimulation(const QString &serialPortName,
int baudRate = 9600,
int parity = QSerialPort::NoParity,
int dataBits = QSerialPort::Data8,
int stopBits = QSerialPort::OneStop);
void stopSimulation();

void writeCoil(int address, bool value);
bool isRunning() const;

signals:
void coilUpdated(int address, bool value); // 从站数据更新
void logMessage(const QString &msg); // 日志

private slots:
void pollModbusCoils();

private:
QModbusClient *m_modbusDevice = nullptr;
QTimer *m_pollingTimer = nullptr;
bool m_running = false;
QMap<int, bool> m_coilValues;
};

#endif // MODBUSMANAGER_H

Notiek ielāde…
Atcelt
Saglabāt