项目实战:Qt西门子PLC通讯调试和模拟工具(包含PLC上位机通讯,PLC服务器)(持续更新,当前v1.4.0)

若该文为原创文章,转载请注明原文出处
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/110071837
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)

开发专栏:商业项目实战


前言

  西门子PLC、台达触摸屏、法兰克机床等等多年以前玩得比较多,改造机床、维修机床、给机床编程等等,没事还能车个零件啥的,对于多年以前的研发改造编程,有时间就重新整理下。
  先上点有历史年代感的照片:
  在这里插入图片描述
  在这里插入图片描述
  在这里插入图片描述
  在这里插入图片描述

  
  在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述


需求

  基于Qt实现与PLC通讯功能。


Demo

西门子PLC实物连接图

  在这里插入图片描述

连接西门子PLC实物读取数据演示(区分数据类型)

  在这里插入图片描述

连接西门子PLC实物写入数据演示(区分数据类型)

  在这里插入图片描述

连接西门子PLC实物读取数据演示(无类型)

  在这里插入图片描述

连接西门子PLC实物写入数据演示(无类型)

  在这里插入图片描述

模拟服务器演示

  在这里插入图片描述
  在这里插入图片描述

体验下载地址

  CSDN(粉丝免积分下载的):https://download.csdn.net/download/qq21497936/13712602
  QQ群:1047134658(点击“文件”搜索“plcCommunication”,群内与博文同步更新)


v1.4.0

  在这里插入图片描述
  在这里插入图片描述


v1.3.0

  在这里插入图片描述


v1.2.0

  在这里插入图片描述


v1.1.0

  在这里插入图片描述
  


关键源码

  在这里插入图片描述
  在这里插入图片描述

PlcWidget.h

#ifndef PLCSERVERMANAGER_H
#define PLCSERVERMANAGER_H

/************************************************************\
 * 控件名称:PlcServerManager
 * 功能描述:Plc通讯服务器(用于模拟PLC,包括仿真DB数据空间)
 * 控件功能:
 *          1.唯一实例类
 *          2.注册DB
 *          3.监听、停止监听
 *          4.对所有事件进行反馈
 * 作者:长沙红胖子(AAA红模仿)
 *      博客专家地址:https://blog.csdn.net/qq21497936/article/details/102478062
 *      联系方式:QQ(21497936) 微信(yangsir198808)
 * 版本信息
 *      日期          版本号        描述
 *  2020年11月23日    v1.0.0      基础功能
 *  2020年12月01日    v1.1.0      增加客户端写入提示信号
\************************************************************/

#include <QObject>
#include <QMutex>
#include <QHash>
#include "snap7.h"

class PlcServerManager : public QObject
{
    Q_OBJECT
private:
    explicit PlcServerManager(QObject *parent = 0);

public:
    static PlcServerManager * getInstance();

    QHash<int, QByteArray> getHashDB2ByteArray() const;

signals:
    void signal_listenStateChanged(bool listen);
    void signal_dataChanged();

public slots:
    void slot_start();
    void slot_stop();
    void slot_listen(QString ip);
    void slot_stopListen();
    void slot_regsiterDB(int dbNum, int size);
    void slot_setDB(int dbNum, QByteArray data);

private:
    static PlcServerManager *_pInstance;
    static QMutex _mutex;
    static void callBack_event(void *usrPtr, PSrvEvent PEvent, int Size);

private:
    bool _running;              // 线程是否启用
    bool _listen;               // 是否连接PLC
    QString _ip;                // ip地址
    QStringList _listIp;        // 连接上的客户端地址
    TS7Server *_pTS7Server;
    QHash<int, QByteArray> _hashDB2ByteArray;
};

#endif // PLCMANAGER_H

PlcWidget.cpp

#include "PlcWidget.h"
#include "ui_PlcWidget.h"
#include <QDebug>

#define LOG qDebug()<<__FILE__<<__LINE__

PlcWidget::PlcWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::PlcWidget),
    _pPlcClientManager(0),
    _pPlcClientManagerThread(0),
    _pPlcServerManager(0),
    _pPlcServerManagerThread(0),
    _pTimer(0)
{
    ui->setupUi(this);

    QString version = "v1.2.0";
    setWindowTitle(QString::fromLocal8Bit("西门子PLC通讯Demo %1(作者:红胖子(AAA红模仿) QQ:21497936 微信:yangsir198808 博客地址:blog.csdn.net/qq21497936)").arg(version));

    // 西门子客户端初始化
    _pPlcClientManager = PlcClientManager::getInstance();
    _pPlcClientManagerThread = new QThread;
    _pPlcClientManager->moveToThread(_pPlcClientManagerThread);
    connect(_pPlcClientManagerThread, SIGNAL(started()),
            _pPlcClientManager, SLOT(slot_start()));
    connect(_pPlcClientManager, SIGNAL(signal_connectedChanged(bool)),
            this, SLOT(slot_connectedChanged(bool)));
    connect(_pPlcClientManager, SIGNAL(signal_readDB(int,int,int,QByteArray)),
            this, SLOT(slot_readDB(int,int,int,QByteArray)));
    _pPlcClientManagerThread->start();

    // 西门子服务器初始化
    _pPlcServerManager = PlcServerManager::getInstance();
    _pPlcServerManagerThread = new QThread;
    _pPlcServerManager->moveToThread(_pPlcServerManagerThread);
    connect(_pPlcServerManagerThread, SIGNAL(started()),
            _pPlcServerManager, SLOT(slot_start()));
    connect(_pPlcServerManager, SIGNAL(signal_listenStateChanged(bool)),
            this, SLOT(slot_listenStateChanged(bool)));
    connect(_pPlcServerManager, SIGNAL(signal_dataChanged()),
            this, SLOT(slot_dataChanged()));
    _pPlcServerManagerThread->start();

    // 初始化控件
    ui->pushButton_connect->setEnabled(true);
    ui->pushButton_disconncet->setEnabled(false);

    // 客户端:控件初始化
    ui->lineEdit_dbNum->setValidator(new QIntValidator(0, 1024));
    ui->lineEdit_dbStart->setValidator(new QIntValidator(0, 1023));
    ui->lineEdit_dbSize->setValidator(new QIntValidator(1, 1023));
    ui->lineEdit_dbInterval->setValidator(new QIntValidator(100, 10000));
    ui->groupBox_read->setEnabled(false);
    ui->pushButton_readDB->setEnabled(true);
    ui->pushButton_startReadDB->setEnabled(true);
    ui->pushButton_stopReadDB->setEnabled(false);

    // 循环读取定时器
    _pTimer = new QTimer(this);
    connect(_pTimer, SIGNAL(timeout()), this, SLOT(slot_timeOut()));

    // 服务端:控件初始化
    ui->lineEdit_serverDbNum->setValidator(new QIntValidator(0, 512));
    ui->pushButton_serverListen->setEnabled(true);
    ui->pushButton_serverStopListen->setEnabled(false);
    ui->lineEdit_serverDbNum->setEnabled(true);
    ui->lineEdit_serverDbSize->setEnabled(true);
    ui->textEdit_serverDB->setEnabled(false);
}

PlcWidget::~PlcWidget()
{
    delete ui;
}

void PlcWidget::slot_connectedChanged(bool connected)
{
    LOG << connected;
    if(connected)
    {
        ui->pushButton_connect->setEnabled(false);
        ui->pushButton_disconncet->setEnabled(true);
        ui->groupBox_read->setEnabled(true);
    }else{
        ui->pushButton_connect->setEnabled(true);
        ui->pushButton_disconncet->setEnabled(false);
        ui->groupBox_read->setEnabled(false);

    }
}

void PlcWidget::slot_readDB(int dbNum, int start, int size, QByteArray data)
{
    if(ui->pushButton_connect->isEnabled())
    {
        return;
    }
    ui->textEdit_db->append(QString("========== %1 readDB DB%2: %3->%4 total: %5 bytes ==========")
                            .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz"))
                            .arg(dbNum)
                            .arg(start)
                            .arg(start + size - 1)
                            .arg(size));
    int rowNum = 10;
    for(int index = 0; index < data.size(); index+=rowNum)
    {
        QString str = data.mid(index, rowNum).toHex(' ');
        str.push_front("0x");
        str = str.replace(" ", " 0x");
        str = QString("%1 -> %2 : ")
                      .arg(start + index)
                      .arg(start + index + rowNum - 1)
              + str;
        ui->textEdit_db->append(str);
    }
    if(!_pTimer->isActive())
    {
        ui->pushButton_readDB->setEnabled(true);
    }
}

void PlcWidget::slot_timeOut()
{
    if(ui->pushButton_connect->isEnabled())
    {
        on_pushButton_stopReadDB_clicked();
        return;
    }
    QMetaObject::invokeMethod(_pPlcClientManager,
                              "slot_readDB",
                              Q_ARG(int, ui->lineEdit_dbNum->text().toInt()),
                              Q_ARG(int, ui->lineEdit_dbStart->text().toInt()),
                              Q_ARG(int, ui->lineEdit_dbSize->text().toInt()));
}

void PlcWidget::on_pushButton_connect_clicked()
{
    QMetaObject::invokeMethod(_pPlcClientManager,
                              "slot_connectTo",
                              Q_ARG(QString, ui->lineEdit_ip->text()));
    // 控件
    ui->pushButton_connect->setEnabled(false);
    ui->pushButton_disconncet->setEnabled(false);
    ui->groupBox_read->setEnabled(false);
}

void PlcWidget::on_pushButton_disconncet_clicked()
{
    _pPlcClientManager->slot_disconnct();
    // 控件
    ui->pushButton_connect->setEnabled(true);
    ui->pushButton_disconncet->setEnabled(false);
    ui->groupBox_read->setEnabled(false);
}

void PlcWidget::on_pushButton_readDB_clicked()
{
    QMetaObject::invokeMethod(_pPlcClientManager,
                              "slot_readDB",
                              Q_ARG(int, ui->lineEdit_dbNum->text().toInt()),
                              Q_ARG(int, ui->lineEdit_dbStart->text().toInt()),
                              Q_ARG(int, ui->lineEdit_dbSize->text().toInt()));
    ui->pushButton_readDB->setEnabled(false);
}

void PlcWidget::on_pushButton_writeDB_clicked()
{
    QByteArray data;
    if(ui->comboBox_type->currentText() == "byte")
    {
        data.append((uchar)ui->lineEdit_writeData->text().toInt());
        _pPlcClientManager->slot_writeDB(ui->lineEdit_writeDBNum->text().toInt(),
                                         ui->lineEdit_writeDBStart->text().toInt(),
                                         1,
                                         data);
    }else if(ui->comboBox_type->currentText() == "int") {
        int i = ui->lineEdit_writeData->text().toInt();
        data.append((uchar)(i / 256 / 265 / 256));
        data.append((uchar)(i / 256 / 265 % 256));
        data.append((uchar)(i / 256 % 256));
        data.append((uchar)(i % 256));
        _pPlcClientManager->slot_writeDB(ui->lineEdit_writeDBNum->text().toInt(),
                                         ui->lineEdit_writeDBStart->text().toInt(),
                                         4,
                                         data);
    }
}

void PlcWidget::on_pushButton_startReadDB_clicked()
{
    _pTimer->start(ui->lineEdit_dbInterval->text().toInt());
    ui->pushButton_readDB->setEnabled(false);
    ui->pushButton_startReadDB->setEnabled(false);
    ui->pushButton_stopReadDB->setEnabled(true);
}

void PlcWidget::on_pushButton_stopReadDB_clicked()
{
    _pTimer->stop();
    ui->pushButton_readDB->setEnabled(true);
    ui->pushButton_startReadDB->setEnabled(true);
    ui->pushButton_stopReadDB->setEnabled(false);
}

void PlcWidget::slot_listenStateChanged(bool listen)
{
    LOG << listen;
    if(listen)
    {
        ui->pushButton_serverListen->setEnabled(false);
        ui->pushButton_serverStopListen->setEnabled(true);
        ui->textEdit_serverDB->setEnabled(true);
        ui->lineEdit_ip->setEnabled(false);
        ui->lineEdit_serverDbNum->setEnabled(false);
        ui->lineEdit_serverDbSize->setEnabled(false);
    }else{
        ui->pushButton_serverListen->setEnabled(true);
        ui->pushButton_serverStopListen->setEnabled(false);
        ui->textEdit_serverDB->setEnabled(false);
        ui->lineEdit_ip->setEnabled(true);
        ui->lineEdit_serverDbNum->setEnabled(true);
        ui->lineEdit_serverDbSize->setEnabled(true);

    }
}

void PlcWidget::slot_dataChanged()
{
    QHash<int, QByteArray> hashDB2Bytearray = _pPlcServerManager->getHashDB2ByteArray();
    if(hashDB2Bytearray.contains(ui->lineEdit_serverDbNum->text().toInt()))
    {
       QString str;
       QByteArray byteArray = hashDB2Bytearray.value(ui->lineEdit_serverDbNum->text().toInt());
       ui->textEdit_serverDB->clear();
       ui->textEdit_serverDB->setText(QString(byteArray.toHex(' ')));
    };
}

void PlcWidget::on_pushButton_serverListen_clicked()
{
    _pPlcServerManager->slot_regsiterDB(ui->lineEdit_serverDbNum->text().toInt(),
                                        ui->lineEdit_serverDbSize->text().toInt());
    QMetaObject::invokeMethod(_pPlcServerManager,
                              "slot_listen",
                              Q_ARG(QString, ui->lineEdit_serverIp->text()));
    // 控件
    ui->pushButton_serverListen->setEnabled(false);
    ui->pushButton_serverStopListen->setEnabled(false);
    ui->lineEdit_serverDbNum->setEnabled(false);
    ui->lineEdit_serverDbSize->setEnabled(false);
    ui->lineEdit_ip->setEnabled(false);

    QHash<int, QByteArray> hashDB2Bytearray = _pPlcServerManager->getHashDB2ByteArray();
    if(hashDB2Bytearray.contains(ui->lineEdit_serverDbNum->text().toInt()))
    {
       QString str;
       QByteArray byteArray = hashDB2Bytearray.value(ui->lineEdit_serverDbNum->text().toInt());
       ui->textEdit_serverDB->clear();
       ui->textEdit_serverDB->setText(QString(byteArray.toHex(' ')));
    }

}

void PlcWidget::on_pushButton_serverStopListen_clicked()
{
    _pPlcServerManager->slot_stopListen();
    // 控件
    ui->pushButton_serverListen->setEnabled(true);
    ui->pushButton_serverStopListen->setEnabled(false);
    ui->lineEdit_serverDbNum->setEnabled(true);
    ui->lineEdit_serverDbSize->setEnabled(true);
    ui->lineEdit_serverIp->setEnabled(true);
}

void PlcWidget::on_pushButton_serverSet_clicked()
{
    QByteArray byteArray;
    QString str = ui->textEdit_serverDB->toPlainText();
    str = str.replace("\n", "");
    str = str.replace("  ", " ");
    QStringList list = str.split(" ");
    LOG << ui->lineEdit_serverDbSize->text().toInt() << list.size();
    if(ui->lineEdit_serverDbSize->text().toInt() == list.size())
    {
        for(int index = 0;  index < list.size(); index++)
        {
            QString d = list.at(index);
            byteArray.append(d.toInt(0, 16));
        }
        _pPlcServerManager->slot_setDB(ui->lineEdit_serverDbNum->text().toInt(),
                                       byteArray);
    }
}


void PlcWidget::on_pushButton_clear_clicked()
{
    ui->textEdit_db->clear();
}


若该文为原创文章,转载请注明原文出处
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/110071837

猜你喜欢

转载自blog.csdn.net/qq21497936/article/details/110071837