能否在smbus2中自定义控制I2C的起始、重启与停止条件?
问题:smbus2中按需控制I2C起始/停止/重启条件实现自定义读流程
我用自研处理器,通过smbus2与外部设备进行I2C通信,需按以下流程读取设备IDCODE,请问能否在smbus2中按需控制起始(Start)、停止(Stop)条件?
第一阶段:
I2C起始 → 7位I2C地址+写位 → 从机ACK → 第1字节 → 从机ACK → 第2字节 → 从机ACK → 第3字节 → 从机ACK → 第4字节 → 从机ACK,不发送停止位第二阶段:
再次执行:I2C起始 → 7位I2C地址+写位 → 从机ACK → 第1字节 → 从机ACK → 第2字节 → 从机ACK → 第3字节 → 从机ACK → 第4字节 → 从机ACK,仍不发送停止位第三阶段:
I2C重启(REstart) → 7位I2C地址+读位 → 从机ACK → 第1字节 → 主机ACK → 第2字节 → 主机ACK → 第3字节 → 主机ACK → 第4字节 → 主机ACK → I2C停止
我了解write_i2c_block_data(...)方法会自动添加起始和停止条件,无法实现上述流程。尝试用read_byte()和write_byte()手动操作,但代码无法正常工作:
# start bus.write_byte(I2C_ADDRESS, 0x00) wait_for_ack() for byte in Bytes: bus.write_byte(I2C_ADDRESS, byte) wait_for_ack() # stop bus.write_byte(I2C_ADDRESS, 0xFF)
其中wait_for_ack()的实现:
ack = bus.read_byte(I2C_ADDRESS) if ack == 0x00: print("ACK received.")
解决方案:用i2c_msg和i2c_rdwr实现自定义时序
smbus2的高层API(如write_byte)会自动封装起始/停止信号,无法精准控制时序。要实现自定义流程,需用底层的i2c_msg和i2c_rdwr接口,直接构造I2C消息并控制起止、重启条件。
针对你的需求,代码示例如下:
from smbus2 import SMBus, i2c_msg I2C_ADDRESS = 0xXX # 替换为你的设备I2C地址 # 替换为两次写阶段的实际4字节数据 write_data1 = [0x01, 0x02, 0x03, 0x04] write_data2 = [0x05, 0x06, 0x07, 0x08] with SMBus(1) as bus: # 替换为你的I2C总线编号 # 第一阶段:写4字节,不发送停止位 write_msg1 = i2c_msg.write(I2C_ADDRESS, write_data1) # 第二阶段:再次写4字节,不发送停止位 write_msg2 = i2c_msg.write(I2C_ADDRESS, write_data2) # 第三阶段:读4字节,读完后发送停止位 read_msg = i2c_msg.read(I2C_ADDRESS, 4) # 批量发送消息:前两个写消息自动衔接为重启条件,读消息结束后发送停止位 bus.i2c_rdwr(write_msg1, write_msg2, read_msg) # 提取读取到的IDCODE idcode = list(read_msg) print(f"读取到的IDCODE: {[hex(b) for b in idcode]}")
关键说明
i2c_msg.write默认发送起始位,若通过i2c_rdwr连续发送多个消息,前一个消息不会发送停止位,自动生成重启条件。i2c_msg.read默认读完后发送停止位,若需调整可通过flags参数控制(如flags=0表示不发停止位)。- 无需手动处理ACK:I2C协议中从机的ACK由硬件自动处理,smbus2底层接口会自动检测,未收到ACK会直接抛出异常。
- 你之前的错误在于
write_byte每次都会自动发送起始+停止位,且手动读ACK的方式不符合I2C协议(ACK是从机应答位,不是通过读字节获取)。
内容的提问来源于stack exchange,提问作者Tahseen
相关产品推荐
相关产品推荐

