若该文为原创文章,转载请注明原文出处
本文章博客地址: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