Qt下调用Snap7库与西门子PLC通信

文章目录

  • 前言
  • 一、Snap7源码下载
  • 二、Snap7的dll常用函数功能介绍
  • 三、Snap7Lib.pri模块的封装
  • 四、下载链接
  • 总结


前言

本文主要讲述了在Qt下调用Snap7库与西门子PLC进行通信,在这里将Snap7的源码与动态库整合在一起封装了一个自己的Snap7Lib.pri子模块,方便在之后的工作中进行使用,也希望可以帮助到大家,如有错误之处,欢迎大家批评指正。


提示:以下是本篇文章正文内容,下面案例可供参考

一、Snap7源码下载

在这里我已经将需要的源码和库文件进行了整理,以及Snap7的参考手册pdf放在下文中的下载链接中。也可以在Snqp7的官网进行下载:
稳定版本snap7源码下载:snap7-full-1.4.2.7z
详情可见参考文章:C++[QT] 环境下使用Snap7与PLC通讯

二、Snap7的dll常用函数功能介绍

在这篇文章中有对Snap7库的常用函数进行了介绍,详情可见参考文章:C++(QT)调用snap7库连接西门子plc

三、Snap7Lib.pri模块的封装

pri模块化开发在Qt中是非常重要的,不仅可以使工程结构更加清晰,还能方便我们对这个子模块的复用,在其它的项目中需要实现类似的功能,直接在项目Pro文件中来包含这个pri文件就能实现调用:

#包含子模块
include (./Snap7Lib/Snap7Lib.pri)

在这里实现了一个Snap7Lib.pri的创建,下面是这个子模块的全部代码:
1.Snap7Lib.pri

HEADERS += \$$PWD/myts7client.h \$$PWD/snap7.hSOURCES += \$$PWD/myts7client.cpp \$$PWD/snap7.cppLIBS += -L$$PWD/lib/ -lsnap7

2.myts7client.h

#ifndef MYTS7CLIENT_H
#define MYTS7CLIENT_H#include <QTime>
#include <QDebug>
#include "snap7.h"#define LOGDEBUG qDebug()<<QTime::currentTime().toString("[hh:mm:ss:zzz]")class MyTS7Client
{
public:MyTS7Client();~MyTS7Client();bool initConnect(QString ip);bool writeBool(int address,int offset,int bit,bool value);bool readBool(int address,int offset,int bit);void printByteBits(uchar byteValue);bool writeInt(int address,int offset,const QString &value);QString readInt(int address,int offset);bool writePlcData(int type,int address,int offset,const QString &value);QString readPlcData(int type,int address,int offset);private:bool m_connectFlag;   //连接标志TS7Client *m_ts7Client;   //TS7Client对象};#endif // MYTS7CLIENT_H

3.myts7client.cpp

#include "myts7client.h"MyTS7Client::MyTS7Client()
{m_connectFlag = false;
}MyTS7Client::~MyTS7Client()
{}//初始化连接
bool MyTS7Client::initConnect(QString ip)
{//创建TS7Client对象m_ts7Client = new TS7Client();int rNum = m_ts7Client->ConnectTo(ip.toLocal8Bit().data(),0,1);if(rNum == 0){LOGDEBUG<<"PLC连接成功!";m_connectFlag = true;return true;}else{LOGDEBUG<<"PLC连接失败!";m_connectFlag = false;return false;}return true;
}//将bool类型数据写入指定偏移量的位
bool MyTS7Client::writeBool(int address,int offset,int bit,bool value)
{//是否连接if(!m_connectFlag){LOGDEBUG<<"PLC未连接!";return false;}//验证偏移量和位号是否有效if(offset < 0 || offset > 3 || bit < 0 || bit > 7){LOGDEBUG<<"无效的偏移量和位号!";return false;}//读取包含目标位的字节以保留其他位的值uchar byteValue;int result = m_ts7Client->DBRead(address,offset,1,&byteValue);if(result != 0){//处理错误LOGDEBUG<<"读取DB"<<address<<"_"<<offset<<"."<<bit<<"失败!";return false;}//LOGDEBUG<<"byteValue1:"<<byteValue;//设置或清除目标位的值uchar bitMask = 1 << bit;if(value){byteValue |= bitMask;   //设置目标位为1}else{byteValue &= ~bitMask;   //清除目标位}//将修改后的字节写回DB100result = m_ts7Client->DBWrite(address,offset,1,&byteValue);if(result != 0){//处理错误LOGDEBUG<<"写入数据到DB"<<address<<"_"<<offset<<"."<<bit<<"失败!";return false;}LOGDEBUG<<"写入数据"<<value<<"到DB"<<address<<"_"<<offset<<"."<<bit<<"成功!";return true;
}//从指定偏移量的位读取bool类型数据
bool MyTS7Client::readBool(int address,int offset,int bit)
{//是否连接if(!m_connectFlag){LOGDEBUG<<"PLC未连接!";return false;}//验证偏移量和位号是否有效if(offset < 0 || offset > 3 || bit < 0 || bit > 7){LOGDEBUG<<"无效的偏移量和位号!";return false;}//读取包含目标位的字节uchar byteValue;int result = m_ts7Client->DBRead(address,offset,1,&byteValue);if(result != 0){//处理错误LOGDEBUG<<"读取DB"<<address<<"_"<<offset<<"."<<bit<<"失败!";return false;}//printByteBits(byteValue);//提取目标位的bool值uchar bitMask = 1 << bit;bool boolValue = (byteValue & bitMask) != 0;//LOGDEBUG<<"读取DB"<<address<<"_"<<offset<<"."<<bit<<"成功!   返回值为:"<<boolValue;return boolValue;
}//打印字节各位的值
void MyTS7Client::printByteBits(uchar byteValue)
{for(int bitIndex = 0;bitIndex <8;++bitIndex){//使用位操作符检查特定位的值bool bitValue = (byteValue & (1 << bitIndex)) != 0;//打印位的值LOGDEBUG<<"bit["<<bitIndex<<"]:"<<(bitValue ? "1" : "0");}
}//将int类型数据写入指定偏移量
bool MyTS7Client::writeInt(int address,int offset,const QString &value)
{//是否连接if(!m_connectFlag){LOGDEBUG<<"PLC未连接!";return false;}qint16 buff = value.toShort();QVector<char> buffToWrite(2);buffToWrite[0] = (buff >> 8) & 0xFF;   //高位字节buffToWrite[1] = buff & 0xFF;   //低位字节int rNum = m_ts7Client->DBWrite(address,offset,2,buffToWrite.data());if(rNum == 0){//LOGDEBUG<<"写入DB"<<address<<"_"<<offset<<"成功!";return true;}else{LOGDEBUG<<"写入DB"<<address<<"_"<<offset<<"失败!   错误码:"<<rNum;return false;}return true;
}//从指定偏移量读取int类型数据
QString MyTS7Client::readInt(int address,int offset)
{//是否连接if(!m_connectFlag){LOGDEBUG<<"PLC未连接!";return "";}QString result;QVector<char> buff(2);int rNum = m_ts7Client->DBRead(address,offset,2,buff.data());if(rNum == 0){qint16 resultValue = ((unsigned char)buff[0] << 8) | (unsigned char)buff[1];result = QString::number(resultValue);//LOGDEBUG<<"读取DB"<<address<<"_"<<offset<<"成功!   返回值为:"<<result;}else{LOGDEBUG<<"读取DB"<<address<<"_"<<offset<<"失败!   错误码:"<<rNum;}return result;
}//写入数据到PLC
bool MyTS7Client::writePlcData(int type,int address,int offset,const QString &value)
{//是否连接if(!m_connectFlag){LOGDEBUG<<"PLC未连接!";return false;}//1-int 2-string 3-floatswitch(type){case 1:{qint16 buff = value.toShort();QVector<char> buffToWrite(2);buffToWrite[0] = (buff >> 8) & 0xFF;   //高位字节buffToWrite[1] = buff & 0xFF;   //低位字节int rNum = m_ts7Client->DBWrite(address,offset,2,buffToWrite.data());if(rNum == 0){LOGDEBUG<<"写入数据:"<<value<<"成功!";return true;}else{LOGDEBUG<<"写入DB失败!返回错误码:"<<rNum;}break;}case 2:{QByteArray strBytes = value.toUtf8();   //转换为UTF-8编码的字节序列QByteArray byte;   //用来发送到PLC的数据byte.append(strBytes);   //字符串的内容if(byte.size() <= 0){QByteArray byte(64,' ');   //创建一个包含64个空格字节的字节数组int rNum = m_ts7Client->DBWrite(address,offset,byte.size(),byte.data());   //写入PLCif(rNum == 0){LOGDEBUG<<"写入数据:"<<value<<"成功!";}else{LOGDEBUG<<"写入DB失败!返回错误码:"<<rNum;}}else{int rNum = m_ts7Client->DBWrite(address,offset,byte.size(),byte.data());   //写入PLCif(rNum == 0){LOGDEBUG<<"写入数据:"<<value<<"成功!";}else{LOGDEBUG<<"写入DB失败!返回错误码:"<<rNum;}}break;}case 3:{float floatValue = value.toFloat();quint32 iniValue;union{float floatVal;quint32 iniValue;}u;u.floatVal = floatValue;iniValue = u.iniValue;QVector<char> buffToWrite(4);buffToWrite[0] = (iniValue >> 24) & 0xFF;buffToWrite[1] = (iniValue >> 16) & 0xFF;buffToWrite[2] = (iniValue >> 8) & 0xFF;buffToWrite[3] = iniValue & 0xFF;int rNum = m_ts7Client->DBWrite(address,offset,4,buffToWrite.data());if(rNum == 0){LOGDEBUG<<"写入数据:"<<value<<"成功!";}else{LOGDEBUG<<"写入DB失败!返回错误码:"<<rNum;}break;}default:LOGDEBUG<<"无效的数据类型!";return false;}
}//从PLC读取数据
QString MyTS7Client::readPlcData(int type,int address,int offset)
{//是否连接if(!m_connectFlag){LOGDEBUG<<"PLC未连接!";return "";}//1-int 2-string 3-floatQString result;switch(type){case 1:{QVector<char> buff(2);int rNum = m_ts7Client->DBRead(address,offset,2,buff.data());if(rNum == 0){qint16 resultValue = ((unsigned char)buff[0] << 8) | (unsigned char)buff[1];//qint16 resultValue = ((unsigned char)buff[0]) | (unsigned char)buff[1] << 8;result = QString::number(resultValue);LOGDEBUG<<"读取成功,返回结果"<<result<<"   "<<resultValue;}else{LOGDEBUG<<"读取DB失败!返回错误码:"<<rNum;}break;}case 2:{QVector<char> buff(64);int rNum = m_ts7Client->DBRead(address,offset,64,buff.data());if(rNum == 0){for(int i=0;i<buff.size();++i){if(buff[i] == ' ')break;result += buff[i];}LOGDEBUG<<"读取成功,返回结果"<<result;}else{LOGDEBUG<<"读取DB失败!返回错误码:"<<rNum;}break;}case 3:{QVector<char> buff(4);int rNum = m_ts7Client->DBRead(address,offset,4,buff.data());if(rNum == 0){//qint32 iniValue = ((unsigned char)buff[0] << 24) | ((unsigned char)buff[1] << 16) |//                  ((unsigned char)buff[2] << 8) | (unsigned char)buff[3];qint32 iniValue = ((unsigned char)buff[0]) | ((unsigned char)buff[1] << 8) |((unsigned char)buff[2] << 16) | ((unsigned char)buff[3] << 24);union{quint32 intValue;float floatValue;}u;u.intValue = iniValue;float floatValue = u.floatValue;result = QString::number(floatValue);LOGDEBUG<<"读取成功,返回结果"<<result<<"   "<<floatValue;}else{LOGDEBUG<<"读取DB失败!返回错误码:"<<rNum;}break;}default:LOGDEBUG<<"无效的数据类型!";}return result;
}

4.文件夹结构
请添加图片描述

四、下载链接

我的压缩包内容如下:
请添加图片描述

Snap7源码和库文件的百度网盘链接:
提取码:


总结

我的文章一开始使用了参考文章中的部分代码,在实际测试过程中也是出现了读写失败等问题,所以在其基础上进行了修改优化,其中的读写bool和int类型数据是没有问题的,而float和string类型实际没有测试,这里无法得之其是否正确,文中代码仅供参考。


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

参考博客:
C++[QT] 环境下使用Snap7与PLC通讯
C++(QT)调用snap7库连接西门子plc
Qt使用S7协议进行数据类型转换

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/24435.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python】读取文件夹中所有excel文件拼接成一个excel表格 的方法

我们平常会遇到下载了一些Excel文件放在一个文件夹下&#xff0c;而这些Excel文件的格式都一样&#xff0c;这时候需要批量这些文件合并成一个excel 文件里。 在Python中&#xff0c;我们可以使用pandas库来读取文件夹中的所有Excel文件&#xff0c;并将它们拼接成一个Excel表…

尝试使用blazor(一)吐槽blazor,未开始之前,先吐为敬

为什么要写一点关于blazor的文章呢?其实是没什么人看的&#xff0c;我知道blazor目前在国内使用的人数&#xff0c;恐怕一辆大巴车都坐不满。非常冷门&#xff0c;我刚用blazor遇到问题&#xff0c;花钱找人解决&#xff0c;找了国内几个著名的平台&#xff0c;几乎没人会blaz…

【docker】centos7配置docker镜像阿里云加速

国内从 DockerHub 拉取镜像有时会遇到困难&#xff0c;由于网络原因&#xff0c;下载一个Docker官方镜像可能会需要很长的时间&#xff0c;甚至下载失败。此时可以配置镜像加速器。Docker 官方和国内很多云服务商都提供了国内加速器服务。 测试了几次阿里云的加速是最快的。 …

Golang | Leetcode Golang题解之第131题分割回文串

题目&#xff1a; 题解&#xff1a; func partition(s string) (ans [][]string) {n : len(s)f : make([][]int8, n)for i : range f {f[i] make([]int8, n)}// 0 表示尚未搜索&#xff0c;1 表示是回文串&#xff0c;-1 表示不是回文串var isPalindrome func(i, j int) int8…

安装 JDK 8

安装包 百度网盘 提取码&#xff1a;6666 安装步骤 安装路径不要有中文或者特殊符号如空格等。 双击安装包开始安装。 更改安装路径&#xff1a; 跳出一个页面&#xff0c;安装公共 JRE&#xff1a; 配置环境变量&#xff1a; 配置成功&#xff1a; 去掉自动更新

AI数据分析:用deepseek根据Excel数据绘制分裂饼形图

工作任务&#xff1a;要绘制下面表格中月活用户占比的分裂饼形图 在deepseek中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个Python脚本编写的任务&#xff0c;具体步骤如下&#xff1a; 读取Excel文件"F:\AI自媒体内容\AI行业数据分析\poetop5…

【LLM】度小满金融大模型技术创新与应用探索

note 从通用大模型到金融大模型金融大模型的训练技术创新金融大模型的评测方法创新金融大模型的应用实践创新总结&#xff1a;金融大模型迭代路径 一、轩辕大模型 二、垂直大模型训练 1. 数据准备 数据质量是模型效果的保障。首先数据要丰富&#xff0c;这是必备的条件。我们…

MeiliSearch-轻量级且美丽的搜索引擎

MeiliSearch-轻量级且美丽的搜索引擎 MeiliSearch 是一个功能强大、快速、开源、易于使用和部署的搜索引擎。它具有以下特点&#xff1a; 支持中文搜索&#xff1a;MeiliSearch 对中文有良好的支持&#xff0c;不需要额外的配置。高度可定制&#xff1a;搜索和索引都可以高度…

UML实现图-组件图

概述 组件图(ComponentDiagram)描述了软件的各种组件和它们之间的依赖关系。组件图中通常包含4种元素:组件、程序、包、任务&#xff0c;各个组件之间还可以相互依赖。 一、组件的表示法 组件是定义了良好接口的物理实现单元&#xff0c;是系统中可替换的物理部件。在一般情…

攻防世界---misc---小小的PDF

1、题目描述&#xff0c;下载附件是一个PDF&#xff0c;打开之后是这样&#xff0c;有两页PDF 2、用winhex分析&#xff0c;没有发现奇怪的地方 3、在kali中binwalk发现有多张照片 4、接着使用foremost将图片分离出来&#xff0c; 5、得到3张图片&#xff0c;打开第3张图片&am…

Android音频架构

Android音频架构 前面《Android音频API》介绍了Android系统提供的四个层面的音频API&#xff1a; Java层MediaRecorder&MediaPlayer系列&#xff1b;Java层AudioTrack&AudioRecorder系列&#xff1b;Jni层opensles&#xff1b;JNI层AAudio&#xff08;Android O引入&…

探索智慧林业系统的总体架构与应用

背景&#xff1a; 随着人们对森林资源保护和管理的重视&#xff0c;智慧林业系统作为一种新兴的林业管理手段&#xff0c;正在逐渐受到广泛关注和应用。智慧林业系统的总体架构设计与应用&#xff0c;将现代信息技术与林业管理相结合&#xff0c;为森林资源的保护、管理和利用…

注册自定义材质实现qgis里不同比例尺下材质不被拉升的效果

前景提要&#xff1a; 在QGIS里的显示效果&#xff0c;用的是示例的/img/textures/line-interval.png材质图片。 下载示例 git clone https://gitee.com/marsgis/mars3d-vue-example.git 相关效果 比如材质是5像素&#xff0c;在1:100000万比例尺下&#xff0c;线显示的长…

树的重心-java

主要通过深度优先搜索来完成树的重心&#xff0c;其中关于树的重心的定义可以结合文字多加理解。 文章目录 前言☀ 一、树的重心☀ 二、算法思路☀ 1.图用邻接表存储 2.图的遍历 3.算法思路 二、代码如下☀ 1.代码如下&#xff1a; 2.读入数据 3,代码运行结果 总结 前言☀ 主…

电机控制系列模块解析(28)—— 其他功能概述

其他功能概述 软件侧&#xff1a;观测器估计发散保护、时序异常检测 主电路侧&#xff1a;IGBT结温估算、直流母线电容容值估算 电机侧&#xff1a;电机温度估计、轴承异常估计、电机退磁检测 负载侧&#xff1a;负载不平衡检测、掉载检测、负载惯量自适应 上述各项功能&a…

新书推荐:2.2.4 第11练:消息循环

/*------------------------------------------------------------------------ 011 编程达人win32 API每日一练 第11个例子GetMessage.c&#xff1a;消息循环 MSG结构 GetMessage函数 TranslateMessage函数&#xff1a;将虚拟键消息转换为字符消息 DispatchMessage函数…

信息系统项目管理师0148:输出(9项目范围管理—9.3规划范围管理—9.3.3输出)

点击查看专栏目录 文章目录 9.3.3 输出 9.3.3 输出 范围管理计划 范围管理计划是项目管理计划的组成部分&#xff0c;描述将如何定义、制定、监督、控制和确认项 目范围。范围管理计划用于指导如下过程和相关工作&#xff1a; ①制定项目范围说明书&#xff1b;②根据详细项目范…

【机器学习】XGBoost: 强化学习与梯度提升的杰作

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 XGBoost: 强化学习与梯度提升的杰作引言1. XGBoost概览1.1 什么是XGBoost&#…

纷享销客安全体系:安全运维运营

安全运维运营(Security Operations,SecOps)是指在信息安全管理中负责监控、检测、响应和恢复安全事件的一系列运营活动。它旨在保护组织的信息系统和数据免受安全威胁和攻击的损害。 通过有效的安全运维运营&#xff0c;组织可以及时发现和应对安全威胁&#xff0c;减少安全事…

09.2手工制作docker镜像-kod服务

手工制作docker镜像-kod服务 基于centos6.9系统镜像&#xff0c;搭建kod服务&#xff0c;提交镜像 创建并进入容器 添加centos6系统的yum源和epel源 yum源 curl -o /etc/yum.repos.d/CentOS-Base.repo https://www.xmpan.com/Centos-6-Vault-Aliyun.repo epel源 curl -o /e…