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.rhkb.cn/news/343799.html

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

相关文章

RHEL - 订阅、注册系统和 Yum Repository(新版界面)

《OpenShift / RHEL / DevSecOps 汇总目录》 演示环境说明 本文需要有 redhat.com 账号以及包含 RHEL 的有效订阅。 演示环境使用了通过 minimal 方式安装的 RHEL 7.6 环境&#xff0c;RHEL 可以访问互联网。 红帽网站 access.redhat.com 针对新用户提供了新版界面&#xff0…

vue3+vite插件开发

插件开发目的:由于我司使用的前端技术栈为vue3tsvite2.Xaxios,在前端代码框架设计初期,做了把axios挂载到proxy对象上的操作,具体可见我的另一篇文章vue3TS自动化封装全局api_ts 封装腾讯位置api-CSDN博客 现在可以实现vue2的类似this.$api.xxx去调用接口,但是vue2源码使用的是…

【CS.AI】GPT-4o:重新定义人工智能的新标杆

文章目录 1 序言2 GPT-4o的技术亮点3 GPT-4o与前代版本的对比3.1 热门AI模型对比表格GPT-3.5GPT-4GPT-4oBERTT5 3.2 其他 4 个人体验与感受5 结论 1 序言 嘿&#xff0c;大家好&#xff01;今天要聊聊一个超级酷的AI新突破——GPT-4o&#xff01;最近&#xff0c;OpenAI发布了…

MTK联发科MT6897(天玑8300)5G智能移动处理器规格参数

天玑 8300 采用台积电第二代 4nm 制程&#xff0c;基于 Armv9 CPU 架构&#xff0c;八核 CPU 包含 4 个 Cortex-A715 性能核心和 4 个 Cortex-A510 能效核心&#xff0c;CPU 峰值性能较上一代提升 20%&#xff0c;功耗节省 30%。 此外&#xff0c;天玑 8300 搭载 6 核 GPU Mal…

kafka-重试和死信主题(SpringBoot整合Kafka)

文章目录 1、重试和死信主题2、死信队列3、代码演示3.1、appication.yml3.2、引入spring-kafka依赖3.3、创建SpringBoot启动类3.4、创建生产者发送消息3.5、创建消费者消费消息 1、重试和死信主题 kafka默认支持重试和死信主题 重试主题&#xff1a;当消费者消费消息异常时&…

android中调用onnxruntime框架

创建空白项目 安装Android Studio及创建空白项目参考&#xff1a;【安卓Java原生开发学习记录】一、安卓开发环境的搭建与HelloWorld&#xff08;详细图文解释&#xff09;_安卓原生开发-CSDN博客 切记&#xff1a;build configuration language 一定选择Groovy&#xff01;官…

Java——IO流(一)-(1/8):File、IO流概述、File文件对象的创建(介绍、实例演示)

目录 File IO流概述 File文件对象的创建 介绍 实例演示 File 存储数据的方案 变量 double money 9999.5 数组 int[] age new int[100];对象 Student s new Student()集合 List<Student> students new ArrayList<>()…

Chrome 源码阅读:跟踪一个鼠标事件的流程

我们通过在关键节点打断点的方式&#xff0c;去分析一个鼠标事件的流程。 我们知道chromium是多进程模型&#xff0c;那么&#xff0c;我们可以推测&#xff1a;一个鼠标消息先从主进程产生&#xff0c;再通过跨进程通信发送给渲染进程&#xff0c;渲染进程再发送给WebFrame&a…

L45---506.相对名次(java)--排序

1.题目描述 2.知识点 &#xff08;1&#xff09;String.join(" ", words) 是 Java 中的一个语法&#xff0c;用于将数组或集合中的元素连接成一个单独的字符串&#xff0c;连接时使用指定的分隔符。这里的 " " 是作为分隔符使用的一个空格字符串。 Strin…

4、后端本地环境搭建

后端本地环境搭建 4.1 安装jdk 下载完成后双击安装的 jdk &#xff0c;点下一步&#xff0c;选择安装目录&#xff0c;一直点下一步&#xff0c;直到结束。 安装完成后同样需要配置环境变量 window s 搜索查看高级系统设置—— 高级 —— 环境变量 —— 系统变量 1、新建一…

API接口测试工具:jmeter的安装、汉化、Jmeter桌面快捷图标和基本使用

文章目录 测试工具&#xff1a;JmeterJmeter安装和配置Jmeter汉化设置中文语言&#xff1a;永久方式设置中文语言&#xff1a;临时方式 设置Jmeter桌面快捷图标jmeter基本用法Jmeter无法保存测试问题解决 测试工具&#xff1a;Jmeter Jmeter依赖于JDK&#xff0c;所以必须确保…

第十一届蓝桥杯C++青少年组中/高级组国赛2020年10月真题解析

一、单选题 第1题 在数组中&#xff0c;数组名表示&#xff08; &#xff09;. A:数组第1个元素的首地址 B:数组第2个元素的首地址 C:数组所有元素的首地址&#xff0c; D:数组最后1个元素的首地址 答案&#xff1a;A 数组名是一个地址&#xff0c;指向第一个元素 第2题 …

中继器、集线器、网桥、交换机、路由器和网关

目录 前言一、中继器、集线器1.1 中继器1.2 集线器 二、网桥、交换机2.1 网桥2.1.1 认识网桥2.1.2 网桥的工作原理2.1.3 生成树网桥 2.2 交换机2.2.1 交换机的特征2.2.2 交换机的交换模式2.2.3 交换机的功能 三、路由器、网关3.1 路由器的介绍3.2 路由器的工作过程3.2.1 前置知…

多客圈子论坛系统 httpGet 任意文件读取漏洞复现

0x01 产品简介 多客圈子论坛系统是一种面向特定人群或特定话题的社交网络&#xff0c;它提供了用户之间交流、分享、讨论的平台。在这个系统中&#xff0c;用户可以创建、加入不同的圈子&#xff0c;圈子可以是基于兴趣、地域、职业等不同主题的。用户可以在圈子中发帖、评论、…

17- Redis 中的 quicklist 数据结构

在 Redis 3.0 之前&#xff0c;List 对象的底层数据结构是双向链表或者压缩列表&#xff0c;然后在 Redis 3.2 的时候&#xff0c;List 对象的底层改由 quicklist 数据结构实现。 其实 quicklist 就是【双向链表 压缩列表】组合&#xff0c;因为一个 quicklist 就是一个链表&…

【产品研发】NPDP价值作用概述

导读&#xff1a;本文结合个人实践和思考对NPDP的价值和作用做了概述说明&#xff0c;对于产品经理而言掌握NPDP的知识体系并且应用到实际工作中&#xff0c;这是非常有必要的。走出以往狭隘的产品研发工作认知&#xff0c;以开放心态学习国际化产品创新开发流程将极大提升产品…

深度学习的舌象诊断:从舌头上了解系统性疾病!

首先 深度学习算法能否解决东方医学中依靠医生经验的诊断问题&#xff1f;而要实现这个目标&#xff0c;需要什么呢&#xff1f; 用舌头诊断被称为口腔健康的指标&#xff0c;但在东方医学中&#xff0c;舌头也被用来评估全身的状况。换句话说&#xff0c;通过分析舌头的图像…

Java学习-JDBC(一)

JDBC 概念 JDBC(Java Database Connectivity)Java数据库连接JDBC提供了一组独立于任何数据库管理系统的APIJava提供接口规范&#xff0c;由各个数据库厂商提供接口的实现&#xff0c;厂商提供的实现类封装成jar文件&#xff0c;也就是我们俗称的数据库驱动jar包JDBC充分体现了…

C#上位机开发

目录 一、上位机简介二、C#语法三、新建VS工程四、WinForm控件4.1 属性4.2 事件4.3 窗体方法4.4 常用控件4.5 布局 五、Serial上位机5.1 UI界面设计5.2 功能设计 六、项目打包成安装包6.1 前提准备6.2 打包步骤 一、上位机简介 在单片机项目开发中&#xff0c;上位机也是一个很…

SwiftUI六组合复杂用户界面

代码下载 应用的首页是一个纵向滚动的地标类别列表&#xff0c;每一个类别内部是一个横向滑动列表。随后将构建应用的页面导航&#xff0c;这个过程中可以学习到如果组合各种视图&#xff0c;并让它们适配不同的设备尺寸和设备方向。 下载起步项目并跟着本篇教程一步步实践&a…