Как преобразовать шестнадцатеричное значение в float32 с прямым порядком байтов в PyModbus

В настоящее время я кодирую modbus rtu в python, используя пакет pymodbus. В этом случае я буду считывать данные с датчика TDS с помощью функционального кода 4/Read Input Registers (см. техническое описание Aquas SMR-08). Данные были успешно получены, и я конвертирую их в hex, но данные должны быть преобразованы снова в правильное значение. Я пытаюсь преобразовать шестнадцатеричное значение с помощью scadacore (онлайн-конвертер шестнадцатеричных данных) и вижу правильные данные в Float Big Endian (ABCD)

Шестнадцатеричное значение равно 41FB:

Шестнадцатеричное значение: 41FB

результат преобразования 31,375 (это значение температуры):

результат преобразования 31,375 (это значение температуры)

Итак, как алгоритм или какой код pymodbus преобразовать, как scadacore (онлайн-преобразование гекса)?

кто-нибудь может помочь? Заранее спасибо, и извините за мой плохой английский, хи-хи-хи

это мой код

import time
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
from pymodbus.constants import Defaults
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
Defaults.RetryOnEmpty = True
Defaults.Timeout = 5
Defaults.Retries = 5

client = ModbusClient(method='rtu', port='/dev/ttyUSB0', timeout=2, stopbits=1, bytesize=8, 
parity='N', baudrate=19200)
client.connect()


while True:

tds1 = client.read_input_registers(address=0, count=2, unit=1)

bacatds1 = tds1.registers[0]
bacatds2 = tds1.registers[1]

tds1hex = hex(bacatds1)
tds2hex = hex(bacatds2)

print(tds1hex)
print(tds2hex)

decoder1 = BinaryPayloadDecoder.fromRegisters(tds1.registers, Endian.Little)
hasil1 = decoder1.decode_32bit_float()

print(hasil1)
print('==================================')
time.sleep(1)

# ----------------------------------------------------------------
tds2 = client.read_input_registers(address=1, count=2, unit=1)

bacatds3 = tds2.registers[0]
bacatds4 = tds2.registers[1]

tds3hex = hex(bacatds3)
tds4hex = hex(bacatds4)

print(tds3hex)
print(tds4hex)

decoder2 = BinaryPayloadDecoder.fromRegisters(tds2.registers, Endian.Big)
hasil2 = decoder2.decode_32bit_float()
print(hasil2)
print('===================================')
time.sleep(1)

person Ibnu    schedule 16.10.2020    source источник
comment
Можете ли вы опубликовать ссылку на информацию о регистрах Modbus используемого вами датчика?   -  person Bosz    schedule 20.10.2020
comment
есть техническое описание SMR08, Ссылка   -  person Ibnu    schedule 21.10.2020


Ответы (2)


У меня мало знаний о питоне, но я видел аналогичный вопрос в java.

Я думаю, что вы не используете шестигранную базу. Я даю вам шаги для достижения вашего требования.

  1. Рассматривайте свой hex как string.
  2. преобразовать string в float с основанием 16.

Выполнив эти два шага, вы получите результат.

Я предоставляю вам ссылку ниже для примера.

Записать шестнадцатеричные значения в регистр с ведущими нулями

Преобразовать шестнадцатеричный формат в число с плавающей запятой

Я надеюсь, это поможет вам.

person Kumar Anil Chaurasiya    schedule 20.10.2020

Я столкнулся с аналогичной проблемой при преобразовании полученных значений в значение с плавающей запятой.

После проверки внутренней кодовой базы для pymodbus

Я придумал следующую функцию

import struct

def decodeRegisters_float(in_registers,bit_size=32,step=2):

    n = len(in_registers)

    float_res = []
    for i in range(0,n,step):
        if bit_size == 32:
            pack_string = '!2H'
            unpack_string = '!f'
            raw = struct.pack(pack_string, in_registers[i] ,in_registers[i+1])
        elif bit_size == 64:
            pack_string = '!4H'
            unpack_string = '!d'
            raw = struct.pack(pack_string, in_registers[i] ,in_registers[i+1],in_registers[i+2],in_registers[i+3])
        value = struct.unpack(unpack_string, raw)[0]
        float_res += [value]

    return float_res

Аргументы функции следующие:

in_registers - Register values read from holding/input resistors

bit_size - 32,64

step - 2 for 32 and 4 for 64

Приведенную выше функцию можно рассматривать как оболочку после того, как вы прочитали значения и неявно должны преобразовать их в соответствующие значения с плавающей запятой.

Ниже приведен пример использования -

def _read_register_dtype_float(client,unit,nreg,registers=2,type='holding',bit_size=32,step=2):

        assert bit_size in [32,64],"Only 32 and 64 bit size is allowed to be read"

        if bit_size == 32:
            registers = nreg * registers
        elif bit_size == 64:
            registers = nreg * registers * 2
            step = 4

        if type == 'holding':
            res = client.read_holding_registers(0,registers,unit=unit)

        if type == 'input':
            res = client.read_input_registers(0,registers,unit=unit)

        return decodeRegisters_float(res.registers,bit_size=bit_size,step=step)

person Vaebhav    schedule 26.10.2020