Правильная интерпретация шестнадцатеричного байта, преобразование его в число с плавающей точкой
В настоящее время я пытаюсь подключиться к электросчетчику через RS485. Пока он работает довольно хорошо, за исключением того, что у меня проблемы с чтением того, что счетчик записывает на линии RS485.
Я знаю, что данные с электросчетчика верны, так как я могу прочитать их с помощью Docklight и внутренней программы производителя.
Так что моя единственная проблема - это преобразование шестнадцатеричных байтов, которые я получаю обратно.
Я получаю
>>> b'\x01\x03\x04Ce/\xec\xe2'
Это должно быть 8 или 9 шестнадцатеричных байтов. Я ожидаю получить что-то вроде
>>> b'\x01\x03\x04\x43\x67\x81\xEC\x43\x68'
Кажется, проблема в том, что python интерпретирует его в "ASCII", где только может, и я не могу преобразовать его из-за не шестнадцатеричных цифр. И ошибка, которую я получаю,
>>> binascii.Error: Non-hexadecimal digit found`
Эквивалент, когда я смотрю на это с другой стороны. Я отправляю
>>> data=bytearray([0x01,0x03,0x4A,0x38,0x00,0x02,0x53,0xDE])
который отображается как
>>> bytearray(b'\x01\x03J8\x00\x02S\xde')
когда я печатаю это
Так как же мне сказать python-3, что я хочу видеть 8 шестнадцатеричных байтов, а не какую-то интерпретацию, которую он автоматически делает? Я считаю, что мне не хватает чего-то, что действительно легко, когда вы знаете, где искать.
Я хочу конвертировать байты 4,5,6,7 в число с плавающей точкой. Но так как он показывает мне шестнадцатеричные цифры, я не могу этого сделать.
2 ответа
Ты можешь использовать struct.unpack()
чтобы получить цифры из данных. Вот путь:
In [171]: import struct
In [190]: b2
Out[190]: b'\x01\x03J8\x00\x02S\xde'
In [191]: struct.unpack('B'*len(b2), b2)
Out[191]: (1, 3, 74, 56, 0, 2, 83, 222)
In [192]: [*map(hex, struct.unpack('B'*len(b2), b2))]
Out[192]: ['0x1', '0x3', '0x4a', '0x38', '0x0', '0x2', '0x53', '0xde']
C
, e
а также /
тоже байты; это символы ASCII, поэтому их не нужно отображать с \x..
гекс убегает.
Вам не нужно декодировать \x..
и шестнадцатеричные экранированные символы, именно так Python предоставляет вам отладочное представление bytes
объект; каждый байт отображается как escape-последовательность или как печатная буква ASCII.
То же самое происходит с чем-то вроде этого примера:
>>> b'\x01\x03\x04\x43\x67\x81\xEC\x43\x68'
b'\x01\x03\x04Cg\x81\xecCh'
Это точно такое же значение, но \x68
это письмо ASCII h
, так далее.
Выход по умолчанию repr()
выход для bytes
объекты. Это не может быть изменено. Вам придется написать свой собственный код, если вам нужен другой вывод.
Вы можете отобразить все байты как шестнадцатеричные с binascii.hexlify()
функция, например:
>>> import binascii
>>> binascii.hexlify(b'\x01\x03\x04\x43\x67\x81\xEC\x43\x68')
b'010304436781ec4368'
Теперь у вас есть bytes
строка с шестнадцатеричными символами. Или вы могли бы использовать str.join()
функция с каждым отдельным байтом, преобразованным в гекс с \x
буквенный текст с префиксом:
>>> ''.join(r'\x{:02x}'.format(byte) for byte in b'\x01\x03\x04\x43\x67\x81\xEC\x43\x68')
'\ X01\x03\x04\x43\x67\x81\ XEC \x43\x68'
>>> print(''.join(r'\x{:02x}'.format(byte) for byte in b'\x01\x03\x04\x43\x67\x81\xEC\x43\x68'))
\x01\x03\x04\x43\x67\x81\xec\x43\x68
Это str
объект с \
, x
и шестнадцатеричные цифры как символы.
Обратите внимание, что это просто отображение значения. Значение не изменилось; все байты есть, но вы их отображаете. Если вам нужно преобразовать 4 байта в число с плавающей запятой, просто конвертируйте эти 4 байта:
struct.unpack('f', yourbytes[4:]) # 4 bytes for C float in native order
Это использует struct
модуль для непосредственного использования байтов. Не требуется шестнадцатеричное представление:
>>> import struct
>>> struct.unpack('f', b'\x01\x03\x04Ce/\xec\xe2'[:4])
(132.01173400878906,)