2010-11-30 2 views
2

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

Arduino отправить что-то вроде "8192323E", а на Python я бы хотел иметь 0.174387. Я нашел «Convert hex to float», но кажется, что все они не работают для одиночных прецизионных поплавков.

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

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 (Processing) Я был в состоянии сделать это:

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); 
    } 
} 
+0

Можете ли вы привести несколько примеров того, как поплавки декодируются кодом ctypes? Мое первое подозрение было бы байтом. Возможно, вам придется поменять байты, чтобы получить право на декодирование. – 2010-11-30 15:13:21

+0

На проводе она течет: F: FFFF7F7F F: FFFF7FFF е: 8192323E е: 00000000 Хотя код ctypes гласит: 'FFFF7F7F' нан 'FFFF7FFF' нан '8192323E' -5.37040237597e-38 '00000000' 0.0 – 2010-11-30 15:20:41

+1

Поскольку процессор Arduino имеет малоконечный код (AFAICT), код C, выполняющийся на нем, выполняет шестнадцатеричное кодирование, сначала обрабатывает низкие байты - поэтому, когда все четыре байта объединяются вместе в указанном порядке, они возвращаются к нормальному пути многобайтовые шестнадцатеричные (и многозначные десятичные) числа записываются и интерпретируются. Это согласуется с тем, почему код Java-декодера «работает» (см. Мой ответ). – martineau 2010-12-01 11:53:21

ответ

4
>>> struct.unpack('<f', '\x81\x92\x32\x3e') 
(0.17438699305057526,) 
0

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

>>> convert('8192323E') 
-5.370402375965945e-38 
>>> convert('3E329281') 
0.17438699305057526 
0

Похоже последовательности данных в шестигранной строковых значений имеет низший порядок байтов первой (прямой порядок байтов?). По крайней мере, так, как ваш 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); 

int() функция Python ожидает байты высшего порядка появляться первыми, когда был приняты (шестнадцатеричной или десятичной) строка. Таким образом, вы должны быть в состоянии исправить вашу 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 
     ... 

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

Update

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

Смежные вопросы