python snap7读写西门子s7-1200PLC的数据(PLC的I、Q、M、DB、V区)

Nerissa ·
更新时间:2024-11-13
· 701 次阅读

2020年02月17日更新:为了更加方便快捷地提供西门子S7 Ethernet系列(S7 200smart 、300、400、1200、1500等系列)PLC数据交换到工业云平台(WebAPP或移动端APP),作者开发了KepOPC系列PLC驱动之一的S7中间件,具体功能描述及应用介绍参照站内博文 https://blog.csdn.net/weixin_29482793/article/details/104220789

S7中间件支持S7-MQTT&MySQL&OPC
S7中间件运行实时统计和曲线展示

    感兴趣的朋友可以访问www.kepopc.com了解,同时欢迎关注作者博客和微信公众号“KepOPC工业互联”了解更多产品资讯。

2020.02.17本站提供试用下载网盘地址https://pan.baidu.com/s/1ypQEgDtBwa0Gre7UsVqGvA  提取码:rfvn

S7应用视频介绍 https://mp.weixin.qq.com/s/2BBhpMKuTC090FPc-r1bfQ

----------------------------------------------------------------------------------------------------------------------------------------

最近要开发基于TCP/IP协议的PC上位机和西门子S7系列PLC的通讯和数据采集,网上搜罗了一圈发现有python snap7这个工具,鉴于此次开发时间有限,就自己研究上手了,期间也碰到很多安装和连接、读取数据的问题,网上解决方案有限,现提供一个测试版本,该版本有如下功能:

2018-03-14 更新python s7-1200测试版程序技术特性:   

1、PC直接通过TCP网口连接S7-1200系列PLC;

2、按照PLC导出的点表地址获取I、Q、M区的地址和类型进行读取;

3、读出的值下一步可以通过MYSQL或socket的方式记录和推送;

4、目前是按照每个点逐个读取,因此效率较低,后续考虑按块读取,那样效率就很高了,基本上读一次时间控制在ms级别;

5、摆脱了OPC的束缚,之前都需要从OPC中转一下,这下PC可以直接通过网络连接PLC。

(python s7-1200测试版本打包程序)下载地址:https://pan.baidu.com/s/1cRK9vIxW4T1_sVFieUESjA

感谢(蔽月八云):https://www.jianshu.com/p/5284de40a139 的总结和分析,因为我也是个PLC小白,python snap7的优势就在于,一个PLC小白也能很快地利用python和PLC建立通讯,并获取寄存器的值,这些值为我们的数据分析提供了数据基础,基于TCP/IP方式的通讯,是它最大的优势,期间也用过modbus TCP的方式读取,但是40001和M区的对应地址关系把我搞的头晕,相比而言modbus简单更易操作,python snap7更加专业。

另附 python snap7安装常见问题和步骤:https://stackoverflow.com/questions/33697263/python-snap7-windows-cant-find-snap7-library

2018年07月31日更新:

感谢每一位关注的朋友,由于最近真的很多人问我python snap7,所以还是觉得应该分享一下微薄的经验,snap7的read_area方法和Kepserver读西门子TCP/IP Ethernet驱动的读取方法是一样的,我也是利用网络抓包工具比对着消息体格式才找到功能码、地址、类型、长度的对应关系,确实还是因为相关的介绍太少,虽说KepOPC也能更加容易实现这些功能,但是我仍坚信snap7才是最美解决方案。(下面的文字适合已经连上PLC的朋友):

1、利用def read_area(self, area, dbnumber, start, size)函数读I\Q\M区不同类型寄存器的值:

            for i in range(0,len(read_list)):
                tag_id = read_list[i]['id']
                tag_type = read_list[i]['type']
                plc_readtime = time.strftime('%Y-%m-%d %H:%M:%S')
                if tag_id[0]=='I' and tag_type=='Boolean'or tag_type=='Bool':
                    result = client.read_area(0x81, 0, int(tag_id[1]), 1)
                    for j in range(0,8):                    
                        if (int(struct.unpack('!B', result)[0]) & pow(2,j)!=0):
                            i_temp_value=1
                        else:
                            i_temp_value=0
                elif tag_id[0]=='Q' and tag_type=='Boolean'or tag_type=='Bool':
                    result = client.read_area(0x82, 0, int(tag_id[1]), 1)
                    q_query_str = ''
                    for j in range(0,8):
                        if (int(struct.unpack('!B', result)[0]) & pow(2,j)!=0):
                            q_temp_value=1
                        else:
                            q_temp_value=0
                elif tag_id[0]=='M':
                    if tag_id[1]!='B' and tag_id[1]!='D'and tag_type=='Boolean'or tag_type=='Bool':
                        m_id_res = re.findall(r'M(\d+)',tag_id)
                        result = client.read_area(0x83, 0, int(m_id_res[0]), 1)
                        for j in range(0,8):
                            if (int(struct.unpack('!B', result)[0]) & pow(2,j)!=0):
                                m_temp_value=1
                            else:
                                m_temp_value=0
                    elif tag_id[1]=='B'and  tag_type=='Byte'or  tag_type=='Boolean':
                        mb_query_str = ''
                        result = client.read_area(0x83, 0, int(tag_id[2:]), 1)
                        read_list[i]['value']=struct.unpack('!B', result)[0]
                    elif tag_id[1]=='D'and tag_type=='DWord':
                        md_query_str = ''
                        result = client.read_area(0x83, 0, int(tag_id[2:]), 4)
                        read_list[i]['value']=struct.unpack('!L', result)[0]
                    else:
                        print "tag_id !=MB\MD\M,or type error!"
                else:
                    pass

以上红色的文字为主要读取代码,用于按照I/M/Q区+地址+类型的寄存器值的读取,读取完需要利用struct.unpack方法转换成我们要的值。

2、利用write_area(self, area, dbnumber, start, data):函数写I\Q\M区不同类型寄存器的值:

      过程与read_area相逆,根据地址和数据类型,把值填到函数的data中。

      举个写的例子:client.write_area(0x82, 0,0,struct.pack('B',24)) 意思是向PLC的开关量输出口D0.3和D0.4值写1,24的二进制是00011000。

2019年12月26日更新:1、新增对S7 200smart的连接;2、新增连接号定义;3、新增V区(V\VB\VW\VD)的读写值。

3、SiemensTCPIP测试工具的使用和下载方法:

(1)下载测试工具 SiemensTCPIP.exe

         下载地址:https://pan.baidu.com/s/18JgupJKUcM7qCHNHhes87A

(2)程序运行        

       运行前请将snap7.dll和snap7.lib拷贝到你的操作系统对应的版本的System32或SysWOW64下。

(3)程序运行

备注:  不同PLC的CPU机架号、插槽号和功能码0x81,0x82,0x83及值类型长度如下表:


                                               

公众号往期文章回顾:

智能制造还有多远,KepOPC又能解决哪些问题呢?

S7中间件如何通过MySQL与PLC读写交互?

西门子S7系列PLC数据采集及交换平台功能介绍

西门子S7系列PLC数据采集及交换平台使用说明

KepOPC工业互联网数据交换平台

OPC实时数据发布到MQTT及存储MySQL关系数据库

OPC实时数据发布到MQTT及存储IfluxDB时序数据库

KepOPC不止是OPC客户端那么简单

如何利用Socket和COM通迅实现非标协议设备的工业互联?


作者:KepOPC



plc 数据 snap Python

需要 登录 后方可回复, 如果你还没有账号请 注册新账号