一、Modbus 协议简介
Modbus 是一种串行通信协议,用于电子设备之间的通信。它是工业领域中常用的通信协议,可实现设备之间的数据交换。Modbus 有几种传输模式,常见的是 Modbus RTU(通过串口)和 Modbus TCP(通过以太网)。
二、PyModbus 简介
PyModbus 是一个用 Python 实现的 Modbus 协议库,支持 Modbus RTU、Modbus TCP 等多种模式,方便开发者在 Python 环境中进行 Modbus 通信开发。
三、安装 PyModbus
使用 pip 可以轻松安装 PyModbus:
pip install pymodbus
四、入门:基本的 Modbus TCP 通信示例
- Modbus TCP 服务器示例
以下是一个简单的 Modbus TCP 服务器示例,它模拟了一个 Modbus 设备,存储了一些保持寄存器的值:
from pymodbus.server.sync import StartTcpServer
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
def run_modbus_server():
初始化数据块,这里模拟了 100 个保持寄存器,初始值都为 0
store = ModbusSlaveContext(
di=ModbusSequentialDataBlock(0, [0]*100),
co=ModbusSequentialDataBlock(0, [0]*100),
hr=ModbusSequentialDataBlock(0, [0]*100),
ir=ModbusSequentialDataBlock(0, [0]*100))
context = ModbusServerContext(slaves=store, single=True)
启动 Modbus TCP 服务器,监听本地的 5020 端口
StartTcpServer(context, address=("localhost", 5020))
if name == "main":
run_modbus_server()
代码解释:
● ModbusSequentialDataBlock 用于创建一个连续的数据块,这里分别为离散输入( di )、线圈( co )、保持寄存器( hr )和输入寄存器( ir )创建了初始值都为 0 的数据块。
● ModbusSlaveContext 表示从站的上下文,包含了各种寄存器的数据块。
● ModbusServerContext 表示服务器的上下文,管理从站的上下文。
● StartTcpServer 用于启动 Modbus TCP 服务器。
- Modbus TCP 客户端示例
以下是一个简单的 Modbus TCP 客户端示例,用于读取服务器的保持寄存器的值:
from pymodbus.client.sync import ModbusTcpClient
def run_modbus_client():
创建 Modbus TCP 客户端,连接到本地的 5020 端口
client = ModbusTcpClient('localhost', port=5020)
连接到服务器
if client.connect():
读取从地址 0 开始的 10 个保持寄存器的值
result = client.read_holding_registers(address=0, count=10, unit=1)
if not result.isError():
print("读取到的保持寄存器的值:", result.registers)
else:
print("读取失败:", result)
else:
print("无法连接到服务器")
关闭连接
client.close()
if name == "main":
run_modbus_client()
代码解释:
● ModbusTcpClient 用于创建一个 Modbus TCP 客户端。
● client.connect() 用于连接到 Modbus 服务器。
● client.read_holding_registers 用于读取保持寄存器的值, address 表示起始地址, count 表示要读取的寄存器数量, unit 表示从站地址。
● result.isError() 用于检查读取是否成功。
● client.close() 用于关闭客户端连接。
五、进阶:写入寄存器值
- 写入单个保持寄存器
from pymodbus.client.sync import ModbusTcpClient
def write_single_register():
client = ModbusTcpClient('localhost', port=5020)
if client.connect():
向地址为 0 的保持寄存器写入值 100
result = client.write_single_register(address=0, value=100, unit=1)
if not result.isError():
print("写入成功")
else:
print("写入失败:", result)
client.close()
else:
print("无法连接到服务器")
if name == "main":
write_single_register()
- 写入多个保持寄存器
from pymodbus.client.sync import ModbusTcpClient
def write_multiple_registers():
client = ModbusTcpClient('localhost', port=5020)
if client.connect():
向从地址 0 开始的保持寄存器写入值 [1, 2, 3, 4, 5]
values = [1, 2, 3, 4, 5]
result = client.write_multiple_registers(address=0, values=values, unit=1)
if not result.isError():
print("写入成功")
else:
print("写入失败:", result)
client.close()
else:
print("无法连接到服务器")
if name == "main":
write_multiple_registers()
六、Modbus RTU 通信
- Modbus RTU 服务器示例
from pymodbus.server.sync import StartSerialServer
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
def run_modbus_rtu_server():
store = ModbusSlaveContext(
di=ModbusSequentialDataBlock(0, [0]*100),
co=ModbusSequentialDataBlock(0, [0]*100),
hr=ModbusSequentialDataBlock(0, [0]*100),
ir=ModbusSequentialDataBlock(0, [0]*100))
context = ModbusServerContext(slaves=store, single=True)
启动 Modbus RTU 服务器,使用串口 COM1(Windows)或 /dev/ttyUSB0(Linux)
StartSerialServer(context, method='rtu', port='COM1', baudrate=9600)
if name == "main":
run_modbus_rtu_server()
- Modbus RTU 客户端示例
from pymodbus.client.sync import ModbusSerialClient
def run_modbus_rtu_client():
client = ModbusSerialClient(method='rtu', port='COM1', baudrate=9600)
if client.connect():
result = client.read_holding_registers(address=0, count=10, unit=1)
if not result.isError():
print("读取到的保持寄存器的值:", result.registers)
else:
print("读取失败:", result)
client.close()
else:
print("无法连接到服务器")
if name == "main":
run_modbus_rtu_client()
七、精通:异常处理和日志记录
- 异常处理
在实际应用中,需要对各种异常情况进行处理,例如连接失败、读取或写入错误等。以下是一个带有异常处理的客户端示例:
from pymodbus.client.sync import ModbusTcpClient
from pymodbus.exceptions import ConnectionException
def run_modbus_client_with_error_handling():
client = ModbusTcpClient('localhost', port=5020)
try:
if client.connect():
result = client.read_holding_registers(address=0, count=10, unit=1)
if not result.isError():
print("读取到的保持寄存器的值:", result.registers)
else:
print("读取失败:", result)
else:
print("无法连接到服务器")
except ConnectionException as e:
print("连接异常:", e)
finally:
client.close()
if name == "main":
run_modbus_client_with_error_handling()
- 日志记录
PyModbus 支持日志记录,可以方便地调试和监控程序的运行情况。以下是一个启用日志记录的示例:
import logging
from pymodbus.client.sync import ModbusTcpClient
配置日志记录
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def run_modbus_client_with_logging():
client = ModbusTcpClient('localhost', port=5020)
if client.connect():
result = client.read_holding_registers(address=0, count=10, unit=1)
if not result.isError():
print("读取到的保持寄存器的值:", result.registers)
else:
print("读取失败:", result)
client.close()
else:
print("无法连接到服务器")
if name == "main":
run_modbus_client_with_logging()
通过以上步骤,你可以从入门到精通掌握 PyModbus 的使用,实现 Modbus 通信的各种功能。在实际应用中,还可以根据具体需求进行更复杂的开发,例如与数据库结合、实现多线程通信等。