Значения с плавающей запятой одинарной точности с плавающей точкой в ​​Python (двойная точность, с прямым порядком байтов) - PullRequest
2 голосов
/ 30 ноября 2010

Мне нужно получить закодированные в шестнадцатеричном формате значения с плавающей запятой с одинарной точностью, поступающие из Arduino по последовательной линии (RS-232). Как преобразовать их в число с плавающей точкой Python, которые являются порядковыми номерами с двойной точностью?

Arduino отправляет что-то вроде "8192323E", а в Python я хотел бы иметь 0,174387. Я нашел « Преобразовать гекс в число с плавающей точкой », но кажется, что все они не работают с плавающей точкой одинарной точности.

На связанной странице это выглядит многообещающе:

from ctypes import *

def convert(s):
    i = int(s, 16)                   # convert from hex to a Python int
    cp = pointer(c_int(i))           # make this into a c integer
    fp = cast(cp, POINTER(c_float))  # cast the int pointer to a float pointer
    return fp.contents.value         # dereference the pointer, get the float

Но это все равно не работает с моими поплавками одинарной точности.

В Java ( Обработка ) я смог сделать это:

float decodeFloat(String inString) {
  byte [] inData = new byte[4];

  inString = inString.substring(2, 10); // discard the leading "f:"
  inData[0] = (byte) unhex(inString.substring(0, 2));
  inData[1] = (byte) unhex(inString.substring(2, 4));
  inData[2] = (byte) unhex(inString.substring(4, 6));
  inData[3] = (byte) unhex(inString.substring(6, 8));

  int intbits = (inData[3] << 24) | ((inData[2] & 0xff) << 16) | ((inData[1] & 0xff) << 8) | (inData[0] & 0xff);
  //unhex(inString.substring(0, 8));
  return Float.intBitsToFloat(intbits);
}

Для справки, это код C, работающий на Arduino, реализующий шестнадцатеричное кодирование.

void serialFloatPrint(float f) {
  byte * b = (byte *) &f;
  Serial.print("f:");
  for(int i=0; i<4; i++) {

    byte b1 = (b[i] >> 4) & 0x0f;
    byte b2 = (b[i] & 0x0f);

    char c1 = (b1 < 10) ? ('0' + b1) : 'A' + b1 - 10;
    char c2 = (b2 < 10) ? ('0' + b2) : 'A' + b2 - 10;

    Serial.print(c1);
    Serial.print(c2);
  }
}

Ответы [ 4 ]

5 голосов
/ 30 ноября 2010

Опираясь на Ответ Игнасио Васкеса-Абрамса ,

import binascii
import struct

text='8192323E'
print(struct.unpack('<f',binascii.unhexlify(text))[0])
# 0.17438699305057526
4 голосов
/ 30 ноября 2010
>>> struct.unpack('<f', '\x81\x92\x32\x3e')
(0.17438699305057526,)
0 голосов
/ 01 декабря 2010

Похоже, что последовательность данных в шестнадцатеричных строковых значениях сначала имеет младшие байты (little-endian?).По крайней мере, так работает ваш Java-код, который, как вы говорите, работает:

  inData[0] = (byte) unhex(inString.substring(0, 2));  // gets _first_ two bytes
  inData[1] = (byte) unhex(inString.substring(2, 4));  // and the next two
  inData[2] = (byte) unhex(inString.substring(4, 6));  // etc...
  inData[3] = (byte) unhex(inString.substring(6, 8));

  // this shifts the bytes at the end of the hex string more the the leading ones
  int intbits = (inData[3] << 24) | ((inData[2] & 0xff) << 16) | 
                ((inData[1] & 0xff) << 8) | (inData[0] & 0xff);

Функция Python * int() ожидает, что байты высшего порядка будут появляться первыми при передаче (шестнадцатеричный или десятичный)строка.Таким образом, вы должны иметь возможность исправить вашу convert() функцию, добавив что-то вроде:

def convert(s):
    s = ''.join(s[i:i+2] for i in range(8,-2,-2)) # put low byte pairs first
    i = int(s, 16)                   # convert from hex to a Python int
      ...

в начале, чтобы исправить это.

Обновление

Или вы можете исправить функцию serialFloatPrint(), работающую на Arduino, чтобы правильно выполнять шестнадцатеричное кодирование для архитектуры с прямым порядком байтов.

0 голосов
/ 30 ноября 2010

Действительно, вам нужно инвертировать порядок байтов. Посмотрите:

>>> convert('8192323E')
-5.370402375965945e-38
>>> convert('3E329281')
0.17438699305057526
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...