我需要通过串行线路(RS-232)接收来自Arduino的十六进制编码单精度大端浮点值。如何将它们转换为具有双精度的大端的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);
}
供您参考,这是在Arduino上运行的C代码,实现了十六进制编码。
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 :(得分:5)
以Ignacio Vazquez-Abrams's answer为基础,
import binascii
import struct
text='8192323E'
print(struct.unpack('<f',binascii.unhexlify(text))[0])
# 0.17438699305057526
答案 1 :(得分:4)
>>> struct.unpack('<f', '\x81\x92\x32\x3e')
(0.17438699305057526,)
答案 2 :(得分:0)
实际上,您需要反转字节顺序。看:
>>> convert('8192323E')
-5.370402375965945e-38
>>> convert('3E329281')
0.17438699305057526
答案 3 :(得分:0)
看起来十六进制字符串值中的数据序列首先是低位字节(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
...
接近开始修复它。
<强>更新强>
或者您可以修复在Arduino上运行的serialFloatPrint()
函数,以便为小端架构正确地执行十六进制编码。