
本文详解如何将 modbus 读取的多个 16 位寄存器(如 `[3468, 204, 0, 2080]`)按特定十进制位置规则拼接为完整整数(如 `20434682080`),适用于电表等设备的非标准数据编码场景。
在使用 pymodbus 读取电表等工业设备时,常遇到一种非标准数值编码方式:设备并非采用常规的 IEEE 754 浮点或标准大端/小端整数格式,而是将一个长整数(如 20434682080)按十进制位数切分后,分别存入多个 16 位寄存器。例如:
- 寄存器 0 → 3468(低 4 位)
- 寄存器 1 → 204(中间 3 位)
- 寄存器 2 → 0(高位补零占位)
- 寄存器 3 → 2080(高 4 位)
最终拼接逻辑为:
20434682080 = 2080 × 10⁸ + 204 × 10⁴ + 3468 × 10⁰ + 0 × 10¹²?
但实际观察目标值 20434682080 的结构可拆解为:
204 3468 2080 ← 按空格分组(注意:中间无 0 占位) → 实际顺序是:[寄存器1][寄存器0][寄存器3],而寄存器2=0未参与显示
更准确地,从结果反推其拼接规则:
- 20434682080 共 11 位数字
- 3468(4 位)→ 位于第 4–7 位(从右往左数:个、十、百、千…)
- 204(3 位)→ 位于第 8–10 位
- 2080(4 位)→ 位于最左侧(第 11–14 位,但仅取前 3 位 204?不成立)
因此,该案例本质不是字节序(endianness)问题,而是设备厂商自定义的“十进制寄存器映射规则”。它不遵循 BinaryPayloadDecoder 所支持的 BIG/LITTLE 字节序或字序,而是一种人工拼接逻辑。
✅ 正确处理方式:直接按业务规则解析寄存器列表,用幂运算组合:
registers = [3468, 204, 0, 2080] # result_ups.registers
# 根据实测目标值 20434682080 反推:204 | 3468 | 2080 → 即 reg[1] + reg[0] + reg[3]
# 注意:reg[2] = 0 未被使用,可能是保留位或错误读取
kwh_ups = (
registers[1] * 10**8 # 204 → 占高位 3 位 → × 10^8 得 20400000000
+ registers[0] * 10**4 # 3468 → 占中位 4 位 → × 10^4 得 34680000
+ registers[3] # 2080 → 占低位 4 位 → 直接加
)
# 结果:20400000000 + 34680000 + 2080 = 20434682080 ✅⚠️ 注意事项:
- 不要强行使用 BinaryPayloadDecoder(如 decode_32bit_int()),它适用于二进制整数编码,而非十进制拼接;
- 务必结合设备手册确认寄存器映射表——不同型号电表可能顺序完全不同(如有的用 [MSB, ..., LSB],有的用 [GroupA, GroupB, ...]);
- 建议增加容错:检查寄存器值范围(如 0 ≤ reg[i]
- 若需兼容浮点(如带小数的 kWh),应先确认小数点位置(例如 2043468.2080),再统一缩放为整数处理。
? 总结:当 pymodbus 返回的 registers 无法通过标准 Endian 解码得到预期值时,请优先怀疑是否为厂商自定义的十进制分段存储。此时最可靠的方法是:*依据实测数据与寄存器值,手工建立映射公式,并用 ` 10n` 精确拼接——这比逆向字节序更高效、更准确。










