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

使用smbus替代i2ctransfer发送字节数组至I2C设备遇IOError求助

问题根源分析

你遇到的IOError: [Errno 121] Remote I/O error,本质是因为smbus.write_i2c_block_data的行为和你原来用i2ctransfer的纯字节写逻辑完全不匹配:

  • 你的i2ctransfer命令w12@0x03是直接向设备0x03发送12字节原始数据,没有任何额外的前置字节;
  • 但write_i2c_block_data(device_address, 0, data)会按照SMBus协议的规则,先发送一个寄存器地址字节(你传的0x00),再发送数据块的长度(0x0C,对应12字节),最后才是你要发送的12字节数据。设备实际收到的是14字节(0x00 + 0x0C + 12个数据字节),和它预期的指令完全不符,所以返回了I/O错误。

解决方案

针对你的需求(发送无寄存器地址的纯字节流),这里提供两种可靠的实现方式:

方案1:改用smbus2库(推荐,更灵活易用)

smbus2是smbus模块的增强版,支持构造原始I2C消息,完美匹配i2ctransfer的行为。先安装库:

pip install smbus2

然后用以下代码实现:

from smbus2 import SMBus, i2c_msg

# 初始化I2C总线(对应你原来的i2cbus=1)
bus = SMBus(1)
device_address = 0x03
# 你要发送的12字节数据
data = [0x23, 0x04, 0x49, 0x74, 0x24, 0x00, 0x23, 0x05, 0x49, 0x74, 0x24, 0x00]

# 构造纯写操作的I2C消息:指定设备地址和要发送的字节数组
write_msg = i2c_msg.write(device_address, data)
# 执行消息发送
bus.i2c_rdwr(write_msg)

# 记得用完后关闭总线(可选,程序退出时会自动释放)
bus.close()

这段代码会直接把12字节数据发送给设备0x03,和你原来的i2ctransfer命令逻辑完全一致。

方案2:直接操作I2C设备文件(无需额外库)

如果无法安装第三方库,你可以直接通过Linux的/dev/i2c-*设备文件发送数据,这和i2ctransfer的底层实现逻辑一致:

import os

# 对应你的i2cbus=1
device_path = "/dev/i2c-1"
device_address = 0x03
# 把数据转为字节对象
data = bytes([0x23, 0x04, 0x49, 0x74, 0x24, 0x00, 0x23, 0x05, 0x49, 0x74, 0x24, 0x00])

# 打开I2C设备文件(需要root权限或对应设备权限)
fd = os.open(device_path, os.O_RDWR)
try:
    # 设置要通信的目标设备地址(I2C_SLAVE的ioctl命令码是0x0703)
    os.ioctl(fd, 0x0703, device_address)
    # 发送数据
    os.write(fd, data)
finally:
    # 确保关闭文件描述符
    os.close(fd)

注意:这段代码需要程序拥有访问/dev/i2c-1的权限,通常需要以root用户运行,或者给设备文件添加对应权限(比如chmod 666 /dev/i2c-1)。

为什么不用内置smbus的其他方法?

内置的smbus模块所有写操作方法(比如write_bytes、write_block_data)都是基于SMBus协议设计的,强制要求先发送寄存器地址(command byte),无法直接发送纯字节流,所以无法满足你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:15:03