如何用Python读取大端字节序(BIG Endian)数据?Modbus电表场景
问题:如何用PyModbus读取大端字节序并转换为目标电表数值
我正在开发一套监控系统,使用PyModbus读取电表数据。读取寄存器地址后得到字节列表:result_ups.registers = [3468, 204, 0, 2080],希望将其转换为电表显示的数值20434682080。当前代码如下:
from pymodbus.client import ModbusTcpClient from pymodbus.constants import Endian from pymodbus.payload import BinaryPayloadDecoder import time client_tcp = ModbusTcpClient('10.123.133.100',port=502) while True: try: client_tcp.connect() while True: result_ups = client_tcp.read_holding_registers(1716,4,units=1,slave=1) decoder_ups = BinaryPayloadDecoder.fromRegisters(result_ups.registers,byteorder=Endian.BIG,wordorder=Endian.LITTLE) kwh_ups = decoder_ups.decode_32bit_int() print(kwh_ups) time.sleep(1) except Exception as e: print(e) time.sleep(1)
请问如何实现读取大端字节序(BIG Endian)并转换为目标数值?
解决方案
你的核心问题在于:原代码用decode_32bit_int()解析32位整数,但目标数值是64位范围的拼接/BCD格式,且电表采用大端字序存储(高位字在前),需要调整寄存器顺序后再解析。以下是两种可行实现:
方式一:直接按字序拼接(明确映射规则时使用)
如果已确认电表数值由寄存器2(204)、寄存器1(3468)、寄存器4(2080)拼接而成,直接调整顺序后拼接十进制字符串:
from pymodbus.client import ModbusTcpClient import time client_tcp = ModbusTcpClient('10.123.133.100', port=502) while True: try: client_tcp.connect() while True: result_ups = client_tcp.read_holding_registers(1716, 4, units=1, slave=1) # 按大端字序重新排列寄存器:高位到低位 reordered_regs = [ result_ups.registers[1], result_ups.registers[0], result_ups.registers[3], result_ups.registers[2] ] # 每个寄存器补前导零到4位,拼接后转整数并去除末尾无效零 kwh_ups = int(''.join(f"{reg:04d}" for reg in reordered_regs).rstrip('0')) print(kwh_ups) time.sleep(1) except Exception as e: print(e) time.sleep(1)
方式二:解析BCD码(符合电表通用存储规范)
多数电表采用BCD码存储电量,每个16位寄存器对应4位BCD码。按大端字节序解析:
from pymodbus.client import ModbusTcpClient from pymodbus.constants import Endian from pymodbus.payload import BinaryPayloadDecoder import time def bcd_to_int(bcd_bytes): """将BCD字节数组转换为整数""" result = 0 for byte in bcd_bytes: # 拆分字节的高4位和低4位,转换为十进制 result = result * 100 + ((byte >> 4) & 0x0F) * 10 + (byte & 0x0F) return result client_tcp = ModbusTcpClient('10.123.133.100', port=502) while True: try: client_tcp.connect() while True: result_ups = client_tcp.read_holding_registers(1716, 4, units=1, slave=1) # 按大端字序调整寄存器顺序,确保高位在前 decoder = BinaryPayloadDecoder.fromRegisters( [result_ups.registers[1], result_ups.registers[0], result_ups.registers[3], result_ups.registers[2]], byteorder=Endian.BIG, wordorder=Endian.BIG ) # 读取8字节原始数据 raw_bytes = decoder.decode_bytes(8) # 转换为BCD整数 kwh_ups = bcd_to_int(raw_bytes) print(kwh_ups) time.sleep(1) except Exception as e: print(e) time.sleep(1)
关键说明
- 原代码的
decode_32bit_int()仅能处理32位整数,无法匹配目标数值的格式和范围,因此失效。 - 调整寄存器顺序是因为电表采用大端字序:原始读取的
[3468,204]是低位字在前,需反转成[204,3468]作为数值的高位部分,同理[0,2080]反转成[2080,0]作为低位部分。
内容的提问来源于stack exchange,提问作者Joshe Danianta
相关产品推荐
相关产品推荐

