我在嵌入式处理器上运行了一些C代码,它使用printf("%d", my_int);
在串行端口(stdout)上输出整数(16位)。我在PC上运行一些python代码,使用pyserial读取串行流并将其写入文件,我可以使用ser.readline()
来实现。尽管效率不高,但这很愉快。
由于嵌入式C发送了相当多的数字并且我想减少传输时间,我想发送格式为二进制而不是ascii的数据(即两个字节/字符而不是几个字节/字符。)我试着这样做:
char msbs = my_int>>8;
char lsbs = my_int;
printf("%c%c\n", msbs, lsbs)
然后在我的python代码中:
chars = ser.readline()
value = ord(chars[0])<<8 + ord(chars[1])
但价值似乎是胡言乱语。任何人都可以指出我做错了吗?
答案 0 :(得分:4)
试试这个:
import struct
chars = ser.readline()[:-1]
value = struct.unpack('>h', chars)
我假设你的整数是短的,请注意'&gt;'的存在for endianness(字节顺序)。
然而,您的代码错误是由于运算符优先级:
value = (ord(chars[0])<<8) + ord(chars[1])
这应该有效。但是最好还是使用struct。
答案 1 :(得分:0)
由于嵌入式C发送了大量数据,我想减少传输时间,
为了提高时间性能,您可以一次发送和/或接收多个号码。在我的测试中,array.fromfile()
比struct.unpack()
快10到100倍。它的代价是有时会调用array.byteswap()
来明确地考虑字节序。
如果C程序和Python脚本在同一台机器上运行(相同大小,相同的endianess);然后你可以使用fwrite
在C端写入短整数作为平台值,并array.fromfile()
on Python side以原始格式读回它们。
例如,打印短整数为二进制:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
short a[] = {31415, 9265, 3589, 793};
size_t n = sizeof a / sizeof *a;
if (fwrite(&n, sizeof n, 1, stdout) != 1) exit(EXIT_FAILURE); /* send size */
return (fwrite(a, sizeof *a, n, stdout) < n) ? EXIT_FAILURE : EXIT_SUCCESS;
}
用Python阅读:
#!/usr/bin/env python3
import sys
import array
import struct
# make stdin binary
file = sys.stdin.detach()
# read size
size_format = 'N' # size_t
n, = struct.unpack(size_format, file.read(struct.calcsize(size_format)))
print(n)
a = array.array('h') # native short int
a.fromfile(file, n)
print(a.tolist()) # -> [31415, 9265, 3589, 793]
array.fromfile
在时间和记忆方面都应该有效。如果您不知道尺寸,请致电a.fromfile
,直到EOFError
被提出。
如果C程序和Python脚本在不同的机器上,那么您可以按网络字节顺序发送整数:
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h> /* htons() */
int main(void) {
short a[] = {31415, 9265, 3589, 793};
/* print one integer at a time */
short *p = a, *end = &a[sizeof a / sizeof *a];
for ( ; p != end; ++p) {
uint16_t s = htons(*p); /* convert from native to network byte order */
if (fwrite(&s, sizeof s, 1, stdout) != 1) exit(EXIT_FAILURE);
}
return 0;
}
如果需要,在Python端交换字节顺序:
#!/usr/bin/env python
import array
import sys
a = array.array('h') # short int in native byte order, byte swap might be needed
for i in range(15, 128):
try: # double size to avoid O(n**2) behaviour
a.fromfile(sys.stdin, 2 << i)
except EOFError:
break
if sys.byteorder != 'big': # if not network order
a.byteswap() # swap byte order
print(a.tolist()) # -> [31415, 9265, 3589, 793]
为避免转换为网络订单,您可以发送一个幻数。它允许在C端以本机字节顺序发送数字(如第一个代码示例中所示),并在Python中检查它以在必要时交换字节:
MAGIC = 1
if a[0] != MAGIC:
a.byteswap()
if a[0] != MAGIC:
raise ValueError("Unexpected %d" % a[0])
答案 2 :(得分:0)
struct
想法很棒,但你的协议有问题。
如果您编写二进制数据,则在其间使用行结尾是没有用的:其中一个&#34;值字节&#34;也可以有这个值 - 10 - 。
所以最好不要使用这些行结尾和readline()
。
但是可能会出现您可能不同步的问题。因此,您应该定义一种包边界,或者您可以用超过2个字节对数据进行编码。
示例:每个16位值以3个字节编码,采用以下方式:
AADDDDDD BBBDDDDD CCCDDDDD
AA
为10
,BBB
为110
,CCC
为111
。
值57723 - 0xE17B,0b1110000101111011,编码为
10111000 11001011 11111011
或
B8 CB FB
通过
byte1 = 0x80 + ((value >> 10) & 0x3F) # bits 10..15
byte2 = 0xC0 + ((value >> 5) & 0x1F) # bits 5..9
byte3 = 0xE0 + ((value) & 0x1F) # bits 0..4
收到这些字节后,您可以立即检测到
a)它是哪个字节(第1个,第2个或第3个)和 b)其内容。
因此,即使一个字节丢失,您也可以检测到该字节并立即恢复流的接收。
另外,这种实现与字节序无关 - 它可以在每台机器上运行,无论其字节顺序如何,都应该设计每种协议。
如何实施,我将留给您。