搭建PLC模拟仿真环境——Python使用python-snap7实现西门子PLC通讯

什么是上位机

上位机,通常是指在数据采集与控制系统中位于较高层级、具有较强数据处理能力和控制功能的计算机设备。它通过通信接口(如串口、网口等)与下位机(如PLC、单片机或其他智能设备)进行数据交换和指令传达,实现对下位机的监控、配置、数据收集和分析等功能。

简单理解,就是对PLC进行监控和数据采集分析。

1. 做上位机开发的必备软件

建议下载和安装下列软件:

  • Windows下网络工具 - WinPcap
  • 西门子PLC模拟软件 - PLCSIM Advanced v3.0 (有实体机可以不安装)
  • 西门子博途软件套件 - TIA Portal

在EdisonTalk公众号内回复“上位机”,可以获得我整理好的下载链接。

建议按照WinPcap -> PLCSIM -> TIA Portal的顺序安装。

至于安装过程,可以自行搜索,或参考下列文章。

  • 常哥说编程《西门子软件安装指南》: https://www.cnblogs.com/xiketang/p/15392317.html
  • https://blog.csdn.net/weixin_44543463/article/details/122782191

2. 配置虚拟网卡

安装完成PLCSIM Advanced后,会多一个虚拟网卡出来。
在这里插入图片描述
这里我们点开这个虚拟网卡,设置一下静态IP。
在这里插入图片描述
在这里插入图片描述

3. 创建一个虚拟PLC(有实体机跳过这里,直接看4)

打开PLCSIM Advanced,按照下列步骤创建一个PLC实例。这里需要注意的实,PLC实例的IP地址需要和刚刚设置的虚拟网卡在同一个网段,这里是192.168.10.x。
在这里插入图片描述

创建完成后,由于PLC实例并未正式启动,因此亮黄灯。

4. 创建博途自动化项目

接下来就是最为关键的步骤,打开博途TIA Portal,进行以下操作:

(1)创建一个项目
在这里插入图片描述

(2)添加PLC设备

点击组态设备
在这里插入图片描述
在这里插入图片描述

(3)添加完成后得到项目视图
在这里插入图片描述
(4)为设备设置“允许来自远程对象的PUT/GET通信访问”
在这里插入图片描述
在这里插入图片描述
(5)为项目设置“块编译时支持仿真”
在这里插入图片描述
(6)为设备设置IP地址
在这里插入图片描述
在这里插入图片描述
(7)为设备添加一个数据块,取名“DB01”
在这里插入图片描述

(8)添加一些字段,并点击编译按钮,编译完成后得到偏移量
在这里插入图片描述

(9)点击下载到设备的按钮,并选择虚拟网卡,然后搜索到我们的虚拟PLC设备,最后点击下载。
在这里插入图片描述

在这里插入图片描述

5. 验证PLC实例状态

成功装载到设备后,我们的PLC实例的状态就会由黄灯 变为 绿灯,说明已经正常启动好了。
在这里插入图片描述

那么,接下来,我们就可以通过python编写一个DEMO来读取和写入PLC的数据块中的数据了。

6. Snap7简介

snap7是一个由国外程序员开发的基于以太网与西门子S7系列PLC的通讯的开源库,类似于C#的S7.Net,但是它不单只支持Python,还支持Java、C/C++、C#等语言。

以下是snap7的官网:

http://snap7.sourceforge.net/

官网包含了使用文档、源码、历史版本等说明,可以根据需要自行查阅。

而python-snap7则是snap7的python版本,有单独的文档以及使用说明,只能用于python,以下是官方文档及GitHub链接:

python-snap7官方文档

GitHub

7. 导入python-snap7

首先需要安装python-snap7,打开cmd,输入以下命令,安装python-snap7

pip install python-snap7 -i https://pypi.tuna.tsinghua.edu.cn/simple

8. 创建连接

snap7实现通讯的时候,是将PLC作为服务端,PC以客户端的身份主动连接的,所以最开始的时候,我们应该创建通讯需要使用的客户端

# 创建通讯客户端实例
plcObj = snap7.client.Client()
 
# 连接至PLC
plcObj.connect('192.168.1.20', 0, 1)

使用PLCSIM Advanced可以仿真出PLC来进行通讯测试

测试连接功能是否正常:

import snap7
 
# 创建通讯客户端实例
plcObj = snap7.client.Client()
 
# 连接至PLC
plcObj.connect('192.168.1.20', 0, 1)
 
# 打印连接状态
print(f"连接状态:{plcObj.get_connected()}")
 
# 关闭连接
plcObj.disconnect()
 
# 打印连接状态
print(f"连接状态:{plcObj.get_connected()}")

在这里插入图片描述

9. 读取数据

python-snap7并未集成像S7.Net那样的读取即刻解析数据的功能,所以无论是读还是写,都是需要进行字节转换的。

以读取DB10的以下的五个变量为例:

打开TIA Protal,创建DB块,编号为1,并添加如下图所示的变量并赋初值,下载到仿真的PLC后打开打开数值监控:

在DBO1数据块中取消优化的块访问即可显示偏移量
在这里插入图片描述

在这里插入图片描述首先我们需要计算需要读取的总字节数,也就是最后一个变量的地址(即偏移量)加上它的数据长度。可以看到,上面的六个变量中,最后一个地址是260,WString为512字节,所以需要读取的总字节数为264+512=772个。

所以第一步,把这772个字节都读取上来:

data = plcObj.db_read(1, 0, 772)

其中,plcObj是我们刚刚创建的通讯客户端对象,db_read是它的读取DB块的方法,第一个参数是DB号,第二个是要读取的字节起始的起始地址,第三个参数是要读取的字节总数,用data这个变量来接收这些数据。

当然也可以写成这种形式:

data = plcObj.read_area(snap7.client.Areas.DB, 1, 0, 772)

read_area是读取任意区域的方法,通过第一个参数的枚举来区分读取的区域,如input、output、DB等,后面三个参数与db_read一致。

当我们需要的数据以字节的形式读取上来以后,我们就可以进行解析了。

10. 解析数据

使用python自身的数据类型转换的方法进行解析

Python自身函数
首先我们介绍第一种方法,使用python自身的数据类型转换的方法进行解析。

在python中,bool、int两个类型都有一个from_bytes的方法,可以通过这个方法来将字节数组转换为对应的数据。但是需要注意的是,在PLC中,数据是大端存储的,而PC中一般是小端存储,所以在这样进行转换的时候,需要加上byteorder=‘big’,来声明读取上来的字节是大端存储的方式。故前面的bool和int变量都可以以这种方式进行解析:

# 读取bool的值
bool.from_bytes(data[0:1], byteorder='big')
# 读取int的值
int.from_bytes(data[2:4], byteorder='big')

其中[ 数字 : 数字 ]是python截取数组的语法,左边的数字是截取的起始索引号,右边的是截取的停止的索引号,需要注意的是,右边的索引是不会被截取的,所以像上面代码的data[ 0 : 1 ],实际上截取的只有data[0],而data[ 2 : 4 ],截取的则是data[2]和data[3]。如果左边的数字不填,则默认从索引0开始截取;而如果右边的数字不填,则默认截取剩余的所有元素。

而对于字符串,python提供了decode方法,可以将字符串的字节数组按照指定的编码格式来转换为字符串。不过PLC中的字符串的头字节是字符串的变量长度和字符串的实际长度,所以需要跳过这些字节来读取实际的数据。string类型是单字节存储的ASCII编码的字符串,所以跳过前两个字节。而wstring类型则是双字节存储的UTF-16BE编码的字符串,所以需要跳过前四个字节。

# 读取string的值
data[5:260].decode(encoding="ascii")
# 读取wstring的值
data[264:].decode(encoding="utf-16be")

在python中,float类型没有像bool和int一样的from_bytes方法,这个时候我们就需要使用struct来进行解析。struct是python的模块之一,可以用以解析字节,刚刚说到的bool、int和字符串都可以用它来解析,当然float也是可以的,不过要讲的话东西就会比较多,此次就不深入讲解了。

struct有pack和unpack两个方法,分别用以将数据转换为字节流和将字节流解析为对应的数据,如下所示,即可将real数值转换为python的float类型:

# 读取real的值
struct.unpack('>f', data[4:8])[0]

第一个参数是指定需要转换成的数据类型,“f”代表float类型,前面加的“>”代表这个字节数组是大端存储的方式,第二个参数是需要转换的字节流。由于unpack是以元组的形式返回的数据,所以需要加[0]来获取它返回的第一个数据。

接下来运行一下我们的代码,来查看读取结果:

import snap7
import struct
 
 
# 创建通讯客户端实例
plcObj = snap7.client.Client()
 
# 连接至PLC
plcObj.connect('192.168.1.20', 0, 1)
 
# 读取数据
data = plcObj.db_read(1, 0, 772)
 
# 关闭连接
plcObj.disconnect()
 
# python解析
selfBool = bool.from_bytes(data[0:1], byteorder='big')
selfInt = int.from_bytes(data[2:4], byteorder='big')
selfString = data[5:260].decode(encoding="ascii")
selfWString = data[264:].decode(encoding="utf-16be")
print("python自身函数解析:")
print(
    f"bool:{selfBool}; int:{selfInt}; real:{selfReal}; string:{selfString}; wstring:{selfWString}"
)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值