赞
踩
文档:
https://pymodbus.readthedocs.io/en/latest/
源码:
https://github.com/riptideio/pymodbus/
Modbus是一种工业领域广泛使用的通信协议,而PyModbus是一个在Python中实现Modbus通信的库。它支持多种Modbus模式,包括RTU(通过串行线路),ASCII和TCP/IP。本教程将重点介绍如何使用PyModbus库进行Modbus RTU通信。
在开始编写代码之前,需要确保已经安装了PyModbus库。可以使用pip命令轻松地安装:
pip install pymodbus
首先,需要从pymodbus
库中导入必要的模块:
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
不知道是不是改版了,我用上面导入报错,用下面的可以:
from pymodbus.client import ModbusSerialClient as ModbusClient
接下来,创建一个ModbusClient
实例,用于建立与Modbus设备的RTU通信:
client = ModbusClient(method='rtu', port='/dev/ttyUSB0', baudrate=9600)
在这里,method
参数设置为'rtu'
以指定通信协议,port
参数根据实际连接的串行端口进行设置(例如Linux系统中可能是'/dev/ttyUSB0'
,Windows中可能是'COM3'
),baudrate
参数设置传输速率,这些参数应与设备文档或配置相匹配。
在配置好客户端实例后,尝试连接到Modbus设备:
if client.connect():
print("Modbus RTU Client Connected")
else:
print("Failed to connect to Modbus RTU Client")
Modbus协议定义了几种类型的寄存器,最常见的是保持寄存器和输入寄存器。以下示例展示了如何读取保持寄存器:
response = client.read_holding_registers(address=1, count=10, unit=1)
if not response.isError():
print("Register Values: ", response.registers)
else:
print("Failed to read registers")
在这个例子中,read_holding_registers
方法用于读取地址为1的起始位置、数量为10的连续寄存器。unit
参数表示从哪个单元(即设备ID)读取数据。
注意:pymodbus某个版本已将unit字段改为slave。使用时即使写错也不会报错,注意查看你的pymodbus文档。
首先应该先通过厂商文档,看传感器要求用什么功能码去读取寄存器数据,拿到功能码后,转换成响应的函数,比如0x03是“输入寄存器(Input Register)”,0x04是“保持寄存器(Holding Register)”,这在这里可以查到。
然后可以到python modbus库中搜源码,我用的虚拟环境,直接在ide里还链接不过去,所以我用fileLocator pro工具直接搜源码,搜到这两个玩意:
接下来就能知道函数该怎么调用了。
要向设备的单个寄存器写入数据,可以使用以下代码:
write_response = client.write_register(address=1, value=25, unit=1)
if not write_response.isError():
print("Written successfully")
else:
print("Failed to write register")
这里使用了write_register
方法,它接受地址、要写入的值以及目标设备的单元ID。
如果要写入多个寄存器,可以使用write_registers
方法:
values = [20, 40, 60, 80, 100]
write_response = client.write_registers(address=1, values=values, unit=1)
if not write_response.isError():
print("Multiple registers written successfully")
else:
print("Failed to write multiple registers")
这里values
列表包含了要写入寄存器的值序列。
处理Modbus通信过程中可能出现的异常非常重要,可以使用try-except语句捕获这些异常:
from pymodbus.exceptions import ModbusException
try:
# 尝试执行Modbus操作
response = client.read_holding_registers(address=1, count=10, unit=1)
except ModbusException as ex:
print("An error occurred:", str(ex))
在完成所有Modbus通信后,应该关闭与设备的连接:
client.close()
print("Modbus RTU Client Connection Closed")
调用close()
方法将关闭串行端口,并释放相关资源。
除了同步客户端,PyModbus还提供了异步客户端选项,可以使用Twisted或Asyncio框架。异步客户端允许程序在等待响应时执行其他任务,对于需要同时处理多个Modbus请求的应用非常有用。
有时候,标准的Modbus函数不足以满足特定的需求。PyModbus允许创建自定义消息和事务处理器,使得可以扩展协议以适应特殊用例。
调试和监控Modbus通信过程中,日志记录功能至关重要。PyModbus提供了详细的日志记录机制,可以帮助分析问题所在。
# 请先安装 pymodbus 和 pyserial # pip install pymodbus # pip install pyserial # from pymodbus.client.sync import ModbusSerialClient as ModbusClient # 报错,说找不到 sync from pymodbus.client import ModbusSerialClient as ModbusClient from pymodbus.exceptions import ModbusException, ConnectionException import logging # 配置日志记录 logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG) # 初始化Modbus串行客户端 # client = ModbusClient(method='rtu', port='/dev/ttyUSB0', baudrate=9600, timeout=3) # [Errno 2] could not open port /dev/ttyUSB0: [Errno 2] No such file or directory: '/dev/ttyUSB0' # client = ModbusClient(method='rtu', port='/dev/ttyTHS1', baudrate=9600, timeout=3) # ttyTHS4 ttyS0 ttyS1 ttyS2 ttyS4 # client = ModbusClient(method='rtu', port='/dev/ttyTHS1', baudrate=9600, timeout=3) # client = ModbusClient(method='rtu', port='/dev/ttyTHS0', baudrate=9600, timeout=3, stopbits=1, bytesize=8, parity='N') client = ModbusClient(port='/dev/ttyTHS0', baudrate=9600, timeout=3, stopbits=1, bytesize=8, parity='N') # 看文档,method='rtu'貌似没用 def read_temperature_and_humidity(client): try: # 读取寄存器地址0和1上的4个字节(两个寄存器) # result = client.read_input_registers(address=0, count=3, unit=1) # 这个错了,这是读取输入寄存器的)0x04 # result = client.read_holding_registers(address=0, count=3, unit=1) # 这个才是读取输入寄存器的0x03 # unit参数错了,当前pymodbus版本没有这个参数,搞乌龙了,要不是用filelocator搜索函数用法,还真不知道- - result = client.read_holding_registers( address=0, count=2, slave=1) # 读取输入寄存器的0x03 # 读两个寄存器就ok,卖家说第三个寄存器是预留的,不用读 if result.isError(): # 处理错误 print("读取错误:", result) return None, None # 将读取到的结果转换为温度和湿度 registers = result.registers temperature_reg = registers[0] humidity_reg = registers[1] # 检查是否有探头错误 if temperature_reg == 0x8000 or humidity_reg == 0x8000: print("探头错误") return None, None # 计算实际的温度和湿度值 temperature = temperature_reg * 0.1 humidity = humidity_reg * 0.1 # 格式化温度和湿度值,保留一位小数 temperature = round(temperature, 1) humidity = round(humidity, 1) return temperature, humidity except ModbusException as e: print("Modbus异常:", e) return None, None except Exception as e: # 捕获除ModbusException之外的所有异常 print(f"An error occurred: {e}") return None, None def main(): try: if client.connect(): # 尝试连接到Modbus服务器/设备 temperature, humidity = read_temperature_and_humidity(client) if temperature is not None and humidity is not None: print(f"温度: {temperature}°C, 湿度: {humidity}%RH") client.close() # 关闭连接 else: print("无法连接到Modbus设备") except ConnectionException as e: print("连接异常:", e) if __name__ == "__main__": main()
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。