要在Python中与PLC建立通信,通常需要进行以下步骤流程:
1. 确定PLC的通信协议:不同的PLC厂商和型号可能采用不同的通信协议,例如Modbus、OPC UA、Profinet等。请先确定您的PLC使用的是哪种通信协议(本文为modbustcp)。
2. 安装相应的Python库:根据您所选择的PLC通信协议,在Python中安装相应的库。例如,如果使用Modbus协议,可以安装`pymodbus`库;如果使用OPC UA协议,可以安装`opcua`库。
3. 连接到PLC:使用相应的库和代码,在Python中建立与PLC的连接。具体的连接方式和代码会因通信协议而异,以下是一个示例:
4. 读取或写入数据:根据您的需求,使用相应的库和方法来读取或写入PLC的数据。以下是一个示例:
from pymodbus.client import ModbusTcpClient
import struct
#负数int
def convert_signed_integer(data):
# 将数据转换为有符号整数
# result = (data & 0xffff) - (data & 0x8000)
# return result
if data > 0x7FFF:
data -= 0x10000
return data
#16整数转32实数
def int_to_real(data1,data2):
int_data = data1 << 16 | data2
real_data = struct.unpack('!f', struct.pack('!I', int_data))[0]
return real_data
# PCL 设备的 IP 地址和端口号
ip_address = '192.168.1.88'
port = 502
# 建立 Modbus TCP 连接
client = ModbusTcpClient(ip_address, port)
if client.connect():
# 读取保持寄存器中的数据(示例:地址 0 到 9)
slave_address = 1 # 设备的从站地址
start_address = 12288 # 起始地址
num_registers = 100 # 要读取的寄存器数量
realdata_x = []
for i in range(12288, 12688, 100):
start_address = i
try:
response = client.read_holding_registers(start_address, num_registers, unit=slave_address)
# print(response)
if not response.isError():
data = response.registers
# print("读取到的数据:", data)
# print(len(data))
for i in range(0, 100, 2):
realdata_x.append(int_to_real(data[i + 1], data[i]))
else:
print("读取数据时出错:", response)
except Exception as e:
print("发生异常:", str(e))
# print(realdata_x)
# print(len(realdata_x))
realdata_y=[]
for i in range(14288, 14688, 100):
start_address = i
try:
response = client.read_holding_registers(start_address, num_registers, unit=slave_address)
# print(response)
if not response.isError():
data = response.registers
# print("读取到的数据:", data)
# print(len(data))
for i in range(0, 100, 2):
realdata_y.append(int_to_real(data[i + 1], data[i]))
# d=[]
# for i in data:
# d.append(convert_signed_integer(i))
# print("读取到的数据:", d)
# print(len(d))
# int_data = d[3] << 16 | data[2]
# print(int_data)
# real_data = struct.unpack('!f', struct.pack('!I', int_data))[0]
# print(real_data)
else:
print("读取数据时出错:", response)
except Exception as e:
print("发生异常:", str(e))
# print(realdata_y)
# print(len(realdata_y))
# 关闭连接
client.close()
else:
print("无法连接到设备")
Modbus协议中的寄存器是用于存储和传输数据的内存区域,它们被分为两种类型:线圈寄存器和保持寄存器。Modbus协议中的寄存器协议如下:
1. 线圈寄存器(Coil Register):线圈寄存器用于存储开关量数据,只能读取或写入单个线圈,其地址从0开始。以下是线圈寄存器相关的协议:
- 功能码01H:读取多个线圈
- 功能码05H:写单个线圈,只能写入0或1
2. 保持寄存器(Holding Register):保持寄存器用于存储模拟量数据或控制信息,可以读取或写入单个或多个保持寄存器,其地址从0开始。以下是保持寄存器相关的协议:
- 功能码03H:用于读取保持寄存器的值,可以读取一个或多个连续的保持寄存器。
- 功能码04H:用于读取输入寄存器的值,可以读取一个或多个连续的输入寄存器。
- 功能码06H:用于写入单个保持寄存器的值。
- 功能码10H:用于写入多个保持寄存器的值,可以写入一个或多个连续的保持寄存器。
以上是Modbus协议中常用的寄存器协议,它们允许设备读取或写入不同类型和数量的寄存器数据,以满足各种应用需求。Modbus协议还有其他类型的寄存器,如输入寄存器(Input Register)和离散输入寄存器(Discrete Input Register),它们用于读取、存储和传输不同类型的数据。这些寄存器的详细信息可以在Modbus协议规范中找到。
IEEE 754是一种用于浮点数表示和计算的国际标准。它定义了浮点数的二进制表示形式、舍入规则和基本运算规则,旨在实现可移植性和一致性。寄存器中的数据以字节形式存储。在Python中,内置的struct
模块提供了对IEEE 754浮点数的打包和解包功能。你可以使用struct.pack()
函数将浮点数打包为字节序列,使用struct.unpack()
函数将字节序列解包为浮点数。
根据IEEE 754标准,一个浮点数由三个主要组成部分构成:
-
符号位(Sign):用于表示数值的正负,0表示正数,1表示负数。
-
指数位(Exponent):用于表示浮点数的指数部分。指数位可以是一个有符号整数,也可以是一个无符号整数。指数位的范围决定了浮点数的可表示范围。
-
尾数位(Significand/Mantissa):用于表示浮点数的尾数部分。尾数位是一个二进制小数,通常为规范化形式(Normalized Form),即首位为1(除非表示的是零或非规范化数)
在pymodbus
库中,根据操作的不同,可以使用以下函数来执行相应的Modbus功能码操作:
# read_coils(address, count): 读取线圈寄存器(功能码01H),参数address表示起始地址,count表示数量。
# read_discrete_inputs(address, count): 读取离散输入寄存器(功能码02H),参数address表示起始地址,count表示数量。
# read_holding_registers(address, count): 读取保持寄存器(功能码03H),参数address表示起始地址,count表示数量。
# read_input_registers(address, count): 读取输入寄存器(功能码04H),参数address表示起始地址,count表示数量。
# write_coil(address, value): 写入单个线圈寄存器(功能码05H),参数address表示地址,value表示要写入的值(0或1)。
# write_register(address, value): 写入单个保持寄存器(功能码06H),参数address表示地址,value表示要写入的值。
# write_registers(address, values): 写入多个保持寄存器(功能码10H),参数address表示起始地址,values表示要写入的值列表。