开发笔记1.0 如何通过python与西门子1500plc进行通讯anaconda与snap7的安装snap7库使用详解read_area()地址信息:DB块地址:字节地址:字节长度: 示例如下: write_area()读字节:修改位数据:写入修改后的数据: 扩展内容
如何通过python与西门子1500plc进行通讯
入行自动化小半年,因为有图像处理和plc控制两方面协调的需求,而笔者之前主用python,因此对此进行了一段时间的探索,也走了很多弯路,写个笔记给自己也给后来者。
anaconda与snap7的安装在寻找可用的通讯模块这方面,笔者陆陆续续试了很多,最后还是选择了snap7,如果有更方便的模块,欢迎讨论。
开发环境的配置是老生常谈了,相关博客非常多,不再赘述,只说几点需要注意的事项:
首先,snap7的安装,我不是太清楚怎么修改anaconda的库源,反正使用pip可以安装snap7,但是使用conda就找不到,解决方法是使用anaconda自带的Anaconda Prompt输入:
pip install python-snap7注意python字段不要落下
其次,snap7安装结束后需要把snap7-full-1.4.2releaseWindowsWin64目录下的dll文件和lib文件放至Anaconda的安装目录和系统windows下的SysWOW64下。
snap7库使用详解这一步踩了很多坑,我也不是想针对某些博客,但是很多人压根就没有实验过代码,把别人的复制一遍就成了一篇技术博客,断章取义,以讹传讹,对后来者造成了很大的麻烦。
本段只说方法,由于项目特殊性,不便截图。
开门见山:
三句话建立对象,之后我们就可以使用read_area与write_area对plc内存数据进行读写,实现通讯。
在进行以下工作之前,必须着重强调一点:基于python的snap7只能对内存里整段的字节进行读写,而不可以直接操作具体的位。
read_area()示例:
i_pre = my_plc.read_area(129,0,20,1)四个参数分别代表地址信息,DB块地址,字节地址,字节长度
地址信息:129 – I区,130 – Q区,131–M区,132–DB块,目前主要用的是这四块。
DB块地址:对于IQM区,该数字为0,对于db块,该数字为db块的地址。
字节地址:整数字节起始地址。
字节长度:指向后读取的字节长度,一般针对位读取的话,填1即可,针对整数字节int32或int64等,需要酌情增加。
示例如下: i_pre = my_plc.read_area(129,0,20,1)#表示I20.0为起点,向后读取1个字节q_pre = my_plc.read_area(130,0,20,2)#表示Q20.0为起点,向后读取2个字节m_pre = my_plc.read_area(131,0,20,3)#表示M20.0为起点,向后读取3个字节db_pre = my_plc.read_area(132,20,2,1)#表示DB20为起点,地址偏移量为2,向后读取1个字节通过字节读取之后的数据需要进行转换,转换之后会得到一个数组,拿出数组内相应的数字就是能够被处理的8位整数:
import structi = struct.unpack('!B',i_pre)[0]再通过字节位读取得到我们想要的开关量,笔者并没有找到字节位读取相关的模块,所以采用以下方法:
右移–取模
如果有更方便的做法,欢迎讨论
至此,read_area()模块用法的坑几乎都填上了,基于以上流程,可以完成I、Q、M、BD区所有数据的字节读取与位读取及其相关函数编写。
write_area()模块要比read_area()模块复杂些,由于python-snap7无法对位进行操作,因此int数据的写相对容易,而位数据写的操作就必须遵循以下流程:读字节–修改位数据–写字节
首先我们先理解write_area()函数的参数含义,示例:
my_plc.write_area(129,0,20,out_pre)四个参数分别代表地址信息、DB地址、字节地址、写入数据
前三个参数同read_area(),写入数据则是打包后的字节数据。
在对write_area()模块参数了解后,我们继续完善开关量写入数据的全部流程:
读字节:没啥好说的,利用前文的read_area()模块读取字节数据并使用unpack方法获得整数数据
修改位数据:拿到8位整数之后,我们需要对其中的某个位进行修改而不改变其余字节的数据,笔者依旧是没找到相应的模块,采用的以下方法:
#输入字节数据,需要修改的位地址,需要修改的位参数,输出修改后的字节数据def write_int(num,bit,boolnum): out = num>>bit if boolnum == False: if out%2 ==0: return num else: return num - 2**bit else: if out%2 ==0: return num + 2**bit else: return num如果有更加方便的做法,欢迎讨论
写入修改后的数据:拿到修改后的数据,采用pack()方法将数据打包再发回plc:
out_pre = struct.pack('!B',byte_num)my_plc.write_area(131,0,20,out_pre)以上就是位数据写入的流程,如果是整数数据的话,只需要进行第三步即可,如果是好几个字节的数据,那就依次右移8位,依次写入
扩展内容主要模块read_area()和write_area()掌握之后,就可以对plc内存区进行读写。
此外,笔者在开发期间,遇到了负数的传输,plc里负数按照补码存储,在传输之前需要对数据进行补码计算。
笔者经验尚浅,所有内容均为自学,若有错漏,还请各位小伙伴们及时提醒。