踩坑实录:Python对西门子PLC(S7-200_SMART)寄存器的读写(VB区)

2020.11.09更新VD和VW区读写代码

问题描述

网上有很多关于如何用Python读写plc的I、Q、M、DB区的文章和代码,但是如果实践中需要用到V区,那些文章将不太可行。
他们的方法都是使用def read_area(self, area, dbnumber, start, size)和write_area(self, area, dbnumber, start, data):函数读写I\Q\M区不同类型寄存器的值,但是如果我们想读写VB区的值呢?

解决办法

据测试,VB区即为DB寄存器中的B区(就是在DB区以一个字节为单位进行读取),即V区即为DB区

在snap7中的源码关于寄存器的描述:

    def db_read(self, db_number, start, size):
        """This is a lean function of Cli_ReadArea() to read PLC DB.

        :returns: user buffer.
        """
        logger.debug("db_read, db_number:%s, start:%s, size:%s" %
                     (db_number, start, size))

        type_ = snap7.snap7types.wordlen_to_ctypes[snap7.snap7types.S7WLByte]
        data = (type_ * size)()
        result = (self.library.Cli_DBRead(
            self.pointer, db_number, start, size,
            byref(data)))
        check_error(result, context="client")
        return bytearray(data)

    @error_wrap
    def db_write(self, db_number, start, data):
        """
        Writes to a DB object.

        :param start: write offset
        :param data: bytearray
        """
        wordlen = snap7.snap7types.S7WLByte
        type_ = snap7.snap7types.wordlen_to_ctypes[wordlen]
        size = len(data)
        cdata = (type_ * size).from_buffer_copy(data)
        logger.debug("db_write db_number:%s start:%s size:%s data:%s" %
                     (db_number, start, size, data))
        return self.library.Cli_DBWrite(self.pointer, db_number, start, size,
                                        byref(cdata))

经过测试,db_number和size这两个参数只能设置为1可行,设置为其他会报错,因此在之后调用的时候,直接把这两个参数赋值1。

因为在写入时,对data的格式有要求,因此写了一个函数把原函数封装了起来:


def read_VB(client, offset):
	""" :param client: client
		:param offset: int 
		:returns: str.
	"""
	vb_data = client.db_read(1, offset, 1)
	return vb_data[0]

def write_VB(client, offset, data):
	""" :param client: client
		:param offset: int 
		:param data: str
	"""
	data = int(data)
	temp = hex(int(data))[2:]
	if data < 0 or data > 255:
		print("请输入0-255之间的数")
	else:
		if data < 16:
			temp = "0"+ temp
		client.db_write(1, offset, bytes.fromhex(temp))
		print("向寄存器VB"+str(offset)+"写入"+str(data)+"成功")


在连接plc之后直接调用即可。

整体代码:

import struct
import time
import snap7

def plc_connect(ip, type, rack=0, slot=1):
	"""
	连接初始化
	:param ip:
	:param type::param connection_type: 1 for PG, 2 for OP, 3 to 10 for S7 Basic
	:param rack: 通常为0	
	:param slot: 根据plc安装,一般为0或1
	:return:client
	"""
	client = snap7.client.Client()
	client.set_connection_type(type)
	client.connect(ip, rack, slot)
	return client

def plc_con_close(client):
	"""
	连接关闭
	:param client:
	:return:
	"""
	client.disconnect()


def read_VB(client, offset):
	""" :param client: client
		:param offset: int 
		:returns: str.
	"""
	vb_data = client.db_read(1, offset, 1)
	return vb_data[0]

def write_VB(client, offset, data):
	""" :param client: client
		:param offset: int 
		:param data: str
	"""
	data = int(data)
	temp = hex(int(data))[2:]
	if data < 0 or data > 255:
		print("请输入0-255之间的数")
	else:
		if data < 16:
			temp = "0"+ temp
		client.db_write(1, offset, bytes.fromhex(temp))
		print("向寄存器VB"+str(offset)+"写入"+str(data)+"成功")

if __name__ == "__main__":

	client_fd = plc_connect('192.168.2.1', 2)
	print("connect success")	
	write_VB(client_fd, 1, "16")
	data = read_VB(client_fd, 1)
	print(data)
	plc_con_close(client_fd)

运行结果:
运行成功

def write_VD(client, offset, data):

	temp = hex(int(data))
	temp = temp[2:].zfill(8)
	# print(type(temp))
	try:
		client.write_area(snap7.snap7types.areas.DB, 1, offset, bytes.fromhex(temp))
		print("向寄存器VB"+str(offset)+"写入"+str(data)+"成功")
	except Exception as e:
		time.sleep(0.003)
		write_VD(client, offset, data)

def read_VD(client, offset):
	"""This is a lean function of Cli_ReadArea() to read PLC DB.
		:param client: client
		:param offset
		:returns: data int.
	"""
	try:
		v_data = client.read_area(snap7.snap7types.areas.DB, 1, offset, 4)
		data = int.from_bytes(v_data, byteorder='big', signed=False)
	except Exception as e:
		time.sleep(0.003)
		data = read_VD(client, offset)
	return data
def write_VW(client, offset, data):

	temp = hex(int(data))
	temp = temp[2:].zfill(4)
	# print(type(temp))
	try:
		client.write_area(snap7.snap7types.areas.DB, 1, offset, bytes.fromhex(temp))
		print("向寄存器VB"+str(offset)+"写入"+str(data)+"成功")
	except Exception as e:
		time.sleep(0.003)
		write_VW(client, offset, data)

def read_VW(client, offset):
	"""This is a lean function of Cli_ReadArea() to read PLC DB.
		:param client: client
		:param offset
		:returns: data int.
	"""
	try:
		v_data = client.read_area(snap7.snap7types.areas.DB, 1, offset, 2)
		data = int.from_bytes(v_data, byteorder='big', signed=False)
	except Exception as e:
		time.sleep(0.003)
		data = read_VW(client, offset)
	return data

你可能感兴趣的:(Python,plc,西门子,通信,寄存器读写)