Python中的十进制转十六进制

5

我有一个可能有点无知的问题。我第一次尝试编写向串行设备写入数据的程序。我有一个帧[12, 0, 0, 0, 0, 0, 0, 0, 7, 0, X, Y],我需要发送它。其中X和Y是校验和值。在使用pyserial模块时,我的理解是需要将这个帧转换为字符串表示形式。好的,那很好,但我对事物应该采用什么格式感到困惑。我尝试过

a = [12, 0, 0, 0, 0, 0, 0, 0, 7, 0, X, Y]
send = "".join(chr(t) for t in a)

但我的困惑来自于使用chr时,X和Y会转换成奇怪的字符串(假设它们的ASCII表示)。例如,如果X是36,则chr(x)为“$”,而不是“\x24”。是否有一种方法可以获得表示“\xnn”值而不是ASCII代码的字符串?令我困惑的是,12和7正确地转换为“\x0b”和“\x07”。我错过了什么吗?
更新: 所以可能是我没有完全理解串行写入是如何进行或者我的设备对我期望什么。这是我的C代码的一部分,正在工作:
fd=open("/dev/ttyS2",O_RDWR|O_NDELAY); char buff_out[20] //下一行是伪代码 for i in buff_out print("%x ",buff_out[i]); // 打印 b 0 0 0 0 0 0 0 9 b3 36 write(fd,buff_out,11); sleep() read(fd,buff_in,size); for i in buff_in print("%x ",buff_in[i]); // 打印我期望的正确帧
Python:
frame = [11, 0, 0, 0, 0, 0, 0, 0, 9] + [crc1, crc1]
senddata = "".join(chr(x) for x in frame)
IEC = serial.Serial(port='/dev/ttyS2', baudrate=1200, timeout=0) IEC.send(senddata)
IEC.read(18) # 要读取的字节数无所谓,它总是0
我是否正在正确进行?显然,由于它是特定于设备的,因此您无法确定确切情况,而且我不能真正提供太多细节。但是,serial.send()期望数据的格式是否正确?

从Python文档中可以看到,chr()函数将输入的数字转换为ASCII字符。在ASCII码中,12和7分别代表响铃和进纸控制符,这些字符可能无法被Python打印(不确定)。因此,Python可能会默认使用十六进制表示这些字符,因为它们无法显示。 - Joel
抱歉,我是指\x0c。我有另一个以11开头的框架。 - Falmarri
4个回答

3

如果可以打印,ASCII字节通常由单个字符表示,否则使用\x??符号。 在这两种情况下,它们都代表一个字节,并且您可以以任何方式编写字符串:

>>> '\x68\x65\x6c\x6c\x6f'
'hello'

然而,如果您使用的是Python 2.6或更高版本,则可能会发现使用内置的bytearray比使用ordstruct更容易和更自然。

>>> vals = [12, 0, 0, 0, 0, 0, 0, 0, 7, 0, 36, 100]
>>> b = bytearray(vals)
>>> b
bytearray(b'\x0c\x00\x00\x00\x00\x00\x00\x00\x07\x00$d')

您可以通过转换类型将其转换为str(或Python 3中的bytes),并且可以对bytearray进行索引以获取整数。
>>> str(b)
'\x0c\x00\x00\x00\x00\x00\x00\x00\x07\x00$d'
>>> b[0]
12
>>> b[-1]
100

关于你的Python串行代码,我认为它看起来很好 - 我不确定你为什么认为有问题...


2
+1 bytearray在处理字节串时是更自然的选择。 - John La Rooy
有问题,因为它在 C 中可以工作但在 Python 中不行 ;) 我会继续研究。C 代码真的很复杂,可能我漏掉了什么。 - Falmarri

1

ASCII码为36的字符'$'。在任何ASCII表中查找它。如果字符不可打印(控制字符等),Python只显示十六进制转义。

在最低层次上,无论Python将其作为十六进制转义还是具有该ASCII值的字符打印出来,它都是相同的位模式。

但是您可能想使用struct模块,它会为您处理此类转换。


我也尝试了结构体。我想我不确定模块希望我如何提供数据。 - Falmarri

0
我猜你想要 结构体
>>> import struct
>>> struct.pack('>B', 12)
'\x0c'
>>> vals = [12, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0xa, 0xb]
>>> ''.join(struct.pack('>B', x) for x in vals)
'\x0c\x00\x00\x00\x00\x00\x00\x00\x07\x00\n\x0b'

2
不要在可以使用生成器表达式的情况下使用列表推导式。 - user395760

0

你所做的是完全正确的:你的send是你想要的:一个具有你想要的值(a)的字节序列。

如果你想看看send中字符的十六进制代码是什么,可以这样做:

import binascii
print binascii.hexlify(send)

或者

print ''.join(r'\x%02x' % ord(char) for char in send)

(如果你想要 \x 前缀)。

当直接打印 repr(send) 时,你看到的是 send 的一个 表示,它使用 ASCII:65 表示 'A',但字符 12 是 '\x0c'。这只是 Python 使用的一种约定,当字符串包含单词时很方便,例如:显示 'Hello' 要比 \x48\x65\x6c\x6c\x6f 更好!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接