STM32 I2C中断模式下重复起始发送0x00地址问题求助
STM32 I2C重复起始条件下读地址发送异常问题
我基于STM32开发I2C中断处理程序,写入数据到总线的流程完全正常,但触发**重复起始(repeated start)**条件时出现异常:总线能检测到重复起始信号,但无论如何调整代码,STM32始终发送带读位的0x00地址,而非预期的0x71地址。
状态机定义
eIdle = 0, eSendingStart = 1, eSendingAddr = 2, eSendingValues = 3, eSendingRepeatedStart = 4, eSendingAddrForRead = 5, eReceivingValues = 6
UART输出位定义
| MSB 3位 | 4 | 3 | 2 | 1 | LSB |
|---|---|---|---|---|---|
| State | RXNE | SB | ADDR | BTF | TXE |
事件序列(含中断触发与状态机流转)
- 设置起始位,状态机切换至
eSendingStart; - 中断触发,
I2C_SR1_SB标志置位,将设备地址写入DR寄存器,状态切换至eSendingAddr; - 中断再次触发,但无任何中断标志位,直接忽略;
- 中断触发,
I2C_SR1_ADDR标志置位(表示从设备应答),状态切换至eSendingValues,此时I2C_SR1_TXE也处于置位状态; - 中断触发,处于
eSendingValues状态且I2C_SR1_TXE置位,发送第一个寄存器字节0x00; - 中断触发,处于
eSendingValues状态且I2C_SR1_TXE置位,确认所有寄存器字节发送完毕,触发重复起始条件。设置I2C_CR1_START后I2C_SR1_TXE仍保持置位,需关闭I2C_CR2_ITBUFEN避免中断泛滥,状态切换至eSendingRepeatedStart; - 0x00传输结束、重复起始发出前,
I2C_SR1_BTF标志置位,读取DR寄存器清除该标志; - 随后
I2C_SR1_SB标志置位,将带读位的设备地址(0x71)写入DR寄存器,状态切换至eSendingAddrForRead,等待I2C_SR1_ADDR标志置位(表示从设备应答); - 立即再次触发中断,但无任何中断标志位;
- 示波器确认STM32发送了0x00地址而非预期的0x71,后续读数据的
RXNE相关代码从未执行——因为eSendingAddrForRead状态下从未检测到ADDR标志。0x00地址被从设备NAK后触发错误中断,此时我设置停止位,UART输出0xEE。
已尝试的调试手段
- 调整中断处理程序中SR1与SR2寄存器的读取顺序;
- 尝试先发送停止位再触发起始位(放弃重复起始逻辑);
- 在不同代码位置写入读地址;
- 排查中断使能/禁用的时机逻辑。
我曾为其他MCU编写过I2C驱动,从未遇到此类问题,但STM32的I2C接口设计逻辑晦涩,官方手册缺乏有效细节指导,HAL库代码也未覆盖重复起始的完整处理场景,特此求助。
内容的提问来源于stack exchange,提问作者Dave Branton




