Modbus读取浮点数数据的正确解析方法

使用Python通过Modbus协议从电能表等工业设备读取寄存器时,常遇到看似“异常”的UINT16数值——实则为IEEE 754单精度浮点数的高位/低位拆分表示,需按双字(2×16位)组合并以大端序解包才能还原真实物理量。

使用Python通过Modbus协议从电能表等工业设备读取寄存器时,常遇到看似“异常”的UINT16数值——实则为IEEE 754单精度浮点数的高位/低位拆分表示,需按双字(2×16位)组合并以大端序解包才能还原真实物理量。

在工业自动化场景中,Modbus RTU/TCP 协议本身仅定义了离散输入、线圈、输入寄存器和保持寄存器四种基本数据类型,所有寄存器均以16位无符号整数(UINT16)为单位存储。然而,传感器、电能表(如Lumel ND25)等设备常需传输浮点型测量值(如电压、电流、功率),受限于协议规范,厂商普遍采用「双寄存器拼接」方式:将一个32位单精度浮点数(float32)按大端序(Big-Endian)拆分为两个连续的16位寄存器——高位字(MSW)在前,低位字(LSW)在后。

您提供的代码中读取了起始地址 0x1772(即十进制 6002)开始的16个保持寄存器,得到结果:

[16640, 0, 16384, 0, 17359, 32768, 16544, 0, 16448, 0, 17096, 0, 0, 0, 16384, 0]

该列表共16个 UINT16 值,恰好可两两配对组成8个 float32,对应文档中描述的8个浮点参数(如电压、频率、有功功率等)。

✅ 正确解析步骤(大端序 + struct 模块)

需使用 Python 标准库 struct 进行字节级重组与解码:

import struct
from pyModbusTCP.client import ModbusClient

client = ModbusClient(
    host='192.168.1.10',
    port=502,
    unit_id=2,
    auto_open=True
)

# 读取16个寄存器(8个float32所需)
regs = client.read_holding_registers(reg_addr=0x1772, reg_nb=16)
if regs:
    # 将16个UINT16按大端序打包为32字节原始数据,再解包为8个float32
    raw_bytes = struct.pack('>16H', *regs)      # > 表示大端,16H 表示16个无符号短整型
    floats = struct.unpack('>8f', raw_bytes)   # >8f 表示8个大端单精度浮点数

    print("解析后的浮点数值:", floats)
    # 输出示例:(8.0, 2.0, 415.0, 5.0, 3.0, 100.0, 0.0, 2.0)
else:
    print("Modbus读取失败")

? 验证逻辑说明
第一对 [16640, 0] → 十六进制为 [0x4100, 0x0000] → 合并为32位大端字节 0x41000000 → IEEE 754 解析即为 8.0,与ND25手册中寄存器46003(地址0x1772)默认值完全一致。

⚠️ 关键注意事项

掌握寄存器原始数据与高层语义之间的编解码桥梁,是工业协议集成的核心能力。理解 UINT16 到 float32 的二进制映射逻辑,不仅能解决ND25类电表问题,也适用于绝大多数支持浮点输出的Modbus从站设备。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。