2013-12-12 50 views
3

我有一些C代碼在嵌入式處理器上運行,它使用printf("%d", my_int);通過串行端口(stdout)輸出整數(16位)。我有一些運行在PC上的python代碼,它使用pyserial讀取串行流並將其寫入文件,我可以使用ser.readline()來實現。儘管它效率不高,但它的工作非常愉快。將數據從C發送到python

由於嵌入式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]) 

不過值似乎是胡言亂語。任何人都可以指出我做錯的事情嗎?

回答

4

嘗試這樣的:

import struct 
chars = ser.readline()[:-1] 
value = struct.unpack('>h', chars) 

我認爲你的整數簽訂短,請注意,「>」的字節順序(字節順序)的存在。

但是,與您的代碼錯誤是因爲運營商的優先級: value = (ord(chars[0])<<8) + ord(chars[1])這應該工作。無論如何,最好使用結構體。

0

隨着嵌入式C派遣了很多數字,我想以減少傳輸時間,

爲了提高時間性能,您可以發送和/或接收的多個號碼一次。在我的測試中,array.fromfile()struct.unpack()快10 - 100倍。它的代價是調用array.byteswap()有時會明確考慮到字節順序。


如果C程序和Python腳本在相同機器(相同的大小,相同的字節順序)上運行;那麼您可以使用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] 

爲避免轉換爲網絡訂單,您可以改爲發送幻數。它允許在Python派在C面的本機字節順序編號(如在第一代碼示例),並檢查它來交換字節,如果必要的:

MAGIC = 1 
if a[0] != MAGIC: 
    a.byteswap() 
    if a[0] != MAGIC: 
     raise ValueError("Unexpected %d" % a[0]) 
0

struct想法是偉大的,但你的協議是錯誤的。

如果你編寫二進制數據,中間有行尾是沒有用的:其中一個「值字節」也可以有這個值--10。

所以最好不要使用這些行結束和readline()

但可能會出現問題,您可能會失去同步。因此,您應該定義一種包裝邊界,或者您可以將數據編碼爲2個以上的字節。

實施例:每個16位值編碼在3個字節,在以下的方式:

AADDDDDD BBBDDDDD CCCDDDDD 

AA10BBB110CCC111

值57723 - 0xE17B,0b1110000101111011,是由

byte1 = 0x80 + ((value >> 10) & 0x3F) # bits 10..15 
byte2 = 0xC0 + ((value >> 5) & 0x1F) # bits 5..9 
byte3 = 0xE0 + ((value)  & 0x1F) # bits 0..4 

在這些字節的接收裝置編碼爲

10111000 11001011 11111011 

B8 CB FB 

,則立即能檢測

a)它的內容是哪個字節(第1,第2或第3)和 b)。

所以,即使一個字節丟失,你可以檢測到,並可以立即恢復流的接收。

此外,這種實現是不依賴於字節序的 - 它可以在每臺機器上工作,而不管它的字節順序如何,應該設計每個協議。

如何實施,我會留給你。