1. Modbus RTU 从站数据采集
任务目标
本案例实现一个基于 Python 的 Modbus RTU 主站程序,通过串口读取从站保持寄存器(Holding Register)数据,并将原始寄存器值按量程与偏移量解析为实际工程值(如温度、压力等)。程序使用 pymodbus 库完成协议帧封装与 CRC 校验,适用于工业现场对 PLC、仪表等从站设备的周期数据采集。
环境依赖
- Python 3.8+
- 安装依赖:
pip install pymodbus==3.6.9 pyserial - 硬件准备:USB 转 RS485 适配器(或开发板自带串口),从站设备地址已知(本案例使用 0x01)
关键完整代码
from pymodbus.client import ModbusSerialClient
import time
# 从站配置
SLAVE_ID = 0x01
REGISTER_ADDR = 0x0000 # 起始寄存器地址
REGISTER_COUNT = 2 # 读取寄存器个数(32位浮点占用2个寄存器)
BAUDRATE = 9600
PORT = '/dev/ttyUSB0' # Windows 下改为 'COM3' 等实际串口号
# 工程值换算参数(示例:量程 0~100℃,偏移 0)
SCALE_MAX = 100.0
SCALE_MIN = 0.0
RAW_MAX = 65535.0
RAW_MIN = 0.0
def raw_to_engineering(raw_value):
"""将16位无符号原始值线性映射为工程值"""
if raw_value > RAW_MAX or raw_value < RAW_MIN:
raise ValueError(f"原始值 {raw_value} 超出范围")
ratio = (raw_value - RAW_MIN) / (RAW_MAX - RAW_MIN)
return SCALE_MIN + ratio * (SCALE_MAX - SCALE_MIN)
def read_holding_registers(client):
"""读取保持寄存器并返回解析后的工程值列表"""
try:
result = client.read_holding_registers(
address=REGISTER_ADDR,
count=REGISTER_COUNT,
slave=SLAVE_ID
)
if result.isError():
raise RuntimeError(f"Modbus 读取错误: {result}")
raw_values = result.registers
# 将两个16位寄存器组合为32位整数(大端序)
combined = (raw_values[0] << 16) | raw_values[1]
# 转换为 IEEE 754 浮点数(若从站存储的是浮点数)
import struct
engineering_value = struct.unpack('>f', combined.to_bytes(4, 'big'))[0]
return engineering_value
except Exception as e:
raise RuntimeError(f"读取失败: {e}")
def main():
client = ModbusSerialClient(
port=PORT,
baudrate=BAUDRATE,
parity='N',
stopbits=1,
bytesize=8,
timeout=2
)
if not client.connect():
raise ConnectionError(f"无法连接串口 {PORT}")
print(f"开始采集从站 {SLAVE_ID} 保持寄存器数据...")
try:
for i in range(5): # 连续采集5次
value = read_holding_registers(client)
print(f"第 {i+1} 次采集: {value:.2f} °C")
time.sleep(1)
finally:
client.close()
print("串口已关闭")
if __name__ == "__main__":
main()
运行与验证
- 连接设备:将从站设备(如 Modbus 模拟器或真实仪表)的 A/B 线接入 RS485 适配器,确认串口号。
- 修改配置:根据实际从站地址、寄存器地址和串口号修改代码顶部配置常量。
- 执行程序:
python modbus_rtu_collect.py - 预期输出:若从站地址 0x01 的保持寄存器 0x0000 处存储 IEEE 754 浮点数 25.5,程序将连续打印 5 次
25.50 °C。
验证方法
- 无硬件验证:使用
pymodbus自带的ModbusSerialClient连接虚拟串口对(如socat创建的 PTY),配合pymodbus.server启动一个模拟从站,可验证程序逻辑正确性。 - 判定标准:程序能连续读取并打印出与从站设定值一致的工程值,且无 CRC 校验错误或超时异常,即视为通过。
- 常见问题:若出现
Modbus IOException,检查串口号、波特率、从站地址是否匹配;若解析值异常,确认从站数据字节序(大端/小端)与代码一致。