You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python解析经I2C传输的异构C结构体数据

Parsing Heterogeneous C Structs Over I2C in Python

Got it, let's work through how to correctly parse your Arduino-sent struct data on the Raspberry Pi. The core challenge here is matching the exact memory layout of your C struct—since I2C sends raw bytes with no type metadata, we have to replicate how the AVR architecture (Arduino Mega2560) packs the struct, then unpack those bytes in Python.

Step 1: Fix the C Struct on Arduino (Critical!)

First, ensure your Arduino struct doesn't have hidden byte alignment padding. AVR compilers automatically add padding bytes to align struct members to word boundaries, which will break your Python parsing. Add __attribute__((packed)) to force the compiler to pack the struct tightly:

// Packed struct to eliminate alignment padding
struct __attribute__((packed)) transferData {
  float latitude;
  float longitude;
  int int_val1;       // Arduino's int is 16-bit (2 bytes)
  int int_val2;
  int int_val3;
  char status_char1;  // 1 byte each
  char status_char2;
};

// Verify struct size (print this to Serial to confirm!)
void setup() {
  Serial.begin(9600);
  Serial.print("Struct size: ");
  Serial.println(sizeof(transferData)); // Should be 4+4+2+2+2+1+1 = 16 bytes
}

Note: If you meant to use 32-bit integers instead of Arduino's 16-bit int, replace int with long (or int32_t for explicit typing) in the struct. Adjust the Python parsing accordingly later.

Step 2: Parse the Bytes in Python

Use Python's built-in struct module to unpack the raw I2C bytes. We'll also use smbus2 (a modern I2C library for Raspberry Pi) to read the data.

Install Dependencies

First, install the I2C library if you haven't already:

pip install smbus2

Python Parsing Code

import struct
from smbus2 import SMBus

# Configuration (adjust these to match your setup)
I2C_BUS_NUMBER = 1  # Raspberry Pi 3+/4 uses bus 1; older models may use 0
ARDUINO_I2C_ADDRESS = 0x08  # Match the address set in your Arduino code

def parse_arduino_struct():
    # Calculate expected byte count (match the sizeof output from Arduino)
    EXPECTED_BYTES = 16  # For the 16-bit int struct; use 22 if using 32-bit longs

    with SMBus(I2C_BUS_NUMBER) as bus:
        # Read raw bytes from Arduino over I2C
        raw_byte_list = bus.read_i2c_block_data(ARDUINO_I2C_ADDRESS, 0, EXPECTED_BYTES)
        raw_bytes = bytes(raw_byte_list)

        # Unpack using struct format string:
        # < = little-endian (AVR uses little-endian)
        # f = 4-byte float (2x for latitude/longitude)
        # h = 2-byte signed int (3x for your int values)
        # c = 1-byte char (2x for status chars)
        unpacked = struct.unpack('<ffhhicc', raw_bytes)

        # Convert byte chars to ASCII strings
        status1 = unpacked[5].decode('ascii')
        status2 = unpacked[6].decode('ascii')

        # Return parsed data in a readable format
        return {
            'latitude': unpacked[0],
            'longitude': unpacked[1],
            'int_val1': unpacked[2],
            'int_val2': unpacked[3],
            'int_val3': unpacked[4],
            'status1': status1,
            'status2': status2
        }

# Test the parser
if __name__ == "__main__":
    data = parse_arduino_struct()
    print("Parsed I2C Data:")
    for key, value in data.items():
        print(f"{key}: {value}")

Adjustments for 32-bit Integers

If you switched to 32-bit long in the C struct:

  • Update the C struct to use long instead of int
  • The struct size will become 4+4+4+4+4+1+1 = 22 bytes
  • Change the Python format string to <ffiiicc and set EXPECTED_BYTES = 22

Key Pitfalls to Avoid

  • Byte Alignment: Always use __attribute__((packed)) on the C struct—without it, the compiler adds padding bytes that will throw off your Python parsing.
  • Byte Order: AVR is little-endian, so start your format string with <. Using big-endian (>) will produce garbage values.
  • Type Matching: Double-check that your Python format characters match the C types:
    • Arduino float → Python f (4 bytes)
    • Arduino int (16-bit) → Python h (2 bytes)
    • Arduino long (32-bit) → Python i (4 bytes)
    • Arduino char → Python c (1 byte)
  • Read Length: Always read exactly the number of bytes returned by sizeof(transferData) on Arduino—reading too many or too few will cause struct.unpack to fail.

内容的提问来源于stack exchange,提问作者Scott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:50:39