如何从串行数据包中提取字节序列并将其更改为 python 中的正确整数表示形式?

How to extract and change a sequence of bytes from a serial packet to the correct integer representation in python?

374c4f4f00000800ff74**d102**29190300006f00fffffffffffffffffffff

这是我用pyserial处理的串口数据包。粗体的两个字节实际上对应于真实世界的测量值,对应于 721(十进制)或 02d1(十六进制)。我如何提取 python 中的那些字节并获得正确的 int 值 721?

使用 struct 库函数 pack/pack_tounpack/unpack_from 可以快速轻松地处理此类字节串:

虽然 unpack/unpack 整个数据包通常是最佳做法,但您可以使用 _from 和 _to 版本来选择性地处理数据包。

你的情况:

>>> import struct
>>> val # Generated using  binascii.unhexlify
 b'7LOO\x00\x00\x08\x00\xfft\xd1\x02)\x19\x03\x00\x00o\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
>>> struct.unpack_from('<H', val, 10)
(721,) # Note the return is a tupple so you need the 0th element
>>> struct.unpack_from('<H', val, 10)[0]
721

更多信息

>>> import struct
>>> help (struct.unpack)
Help on built-in function unpack in module _struct:

unpack(...)
    unpack(fmt, buffer) -> (v1, v2, ...)

    Return a tuple containing values unpacked according to the format string
    fmt.  Requires len(buffer) == calcsize(fmt). See help(struct) for more
    on format strings.
>>> help (struct.pack)
Help on built-in function pack in module _struct:

pack(...)
    pack(fmt, v1, v2, ...) -> bytes

    Return a bytes object containing the values v1, v2, ... packed according
    to the format string fmt.  See help(struct) for more on format strings.

>>> help(struct)
Help on module struct:

NAME
    struct

DESCRIPTION
    Functions to convert between Python values and C structs.
    Python bytes objects are used to hold the data representing the C struct
    and also as format strings (explained below) to describe the layout of data
    in the C struct.

    The optional first format char indicates byte order, size and alignment:
      @: native order, size & alignment (default)
      =: native order, std. size & alignment
      <: little-endian, std. size & alignment
      >: big-endian, std. size & alignment
      !: same as >

    The remaining chars indicate types of args and must match exactly;
    these can be preceded by a decimal repeat count:
      x: pad byte (no data); c:char; b:signed byte; B:unsigned byte;
      ?: _Bool (requires C99; if not available, char is used instead)
      h:short; H:unsigned short; i:int; I:unsigned int;
      l:long; L:unsigned long; f:float; d:double.
    Special cases (preceding decimal count indicates length):
      s:string (array of char); p: pascal string (with count byte).
    Special cases (only available in native format):
      n:ssize_t; N:size_t;
      P:an integer type that is wide enough to hold a pointer.
    Special case (not in native mode unless 'long long' in platform C):
      q:long long; Q:unsigned long long
    Whitespace between formats is ignored.

    The variable struct.error is an exception raised on errors.

您的十六进制编码字符串的长度是奇数,所以我不知道填充从哪里丢失,见下文

In [18]: s = '374c4f4f00000800ff74d10229190300006f00fffffffffffffffffffff0' # a nibble of padding at the end

In [19]: buffer = binascii.unhexlify(s)

In [20]: buffer
Out[20]: b'7LOO\x00\x00\x08\x00\xfft\xd1\x02)\x19\x03\x00\x00o\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0'

In [21]: struct.unpack('<10BH18B', buffer)
Out[21]:
(55,
 76,
 79,
 79,
 0,
 0,
 8,
 0,
 255,
 116,
 721,
 ...

有关 packunpack 中格式字符串的更多信息,请参阅 documentation。简而言之,<代表little-endian,B代表unsigned char(假设8位宽),H简称(假设16位宽)。

由于实际的格式字符串乍一看有些奇怪,我已经根据上面的答案给了你一个解决方案:

  • 命令 unhexlify 会将 4 字节的 ascii 表示形式转换回整数的两字节二进制表示形式。
  • “<”处理整数中的反转字节顺序 (Formatting details)
  • 'i'表示我们面对的是一个二字节整数

希望对您有所帮助。

import struct 
from binascii import unhexlify

s ="374c4f4f00000800ff74d10229190300006f00fffffffffffffffffffff"
s1= s[20:24]

print struct.unpack('<h', unhexlify(s1))[0]