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

STM32F103C8T6中断式I2C重复起始位无法发送问题求助

STM32F103C8T6 I2C中断模式下重复起始位无法触发的问题

问题描述

使用STM32F103C8T6的I2C2外设,通过中断实现通信,仅启用ITEVFEN中断,禁用ITBUFEN中断。通信序列为:
起始位→发送设备地址→发送待读取的寄存器地址→发送重复起始位(每步均通过中断触发执行)

发送第二个起始位后无任何反应,程序卡住,但调试时读取I2C相关寄存器状态显示正常。已尝试添加延时,无效果;确认发送起始位的中断代码已执行,但硬件未生成起始位。

临时可行的规避操作

  1. 发送重复起始位前读取DR寄存器:
(void)I2C2->DR;
I2C2->CR1|=I2C_CR1_START;
  1. 设置起始位后向DR写入任意无效数据(无效数据不会被传输):
I2C2->CR1|=I2C_CR1_START;
I2C2->DR=0x55;
  1. 在发送寄存器地址的最后一字节后立即写入起始位,进入中断后再次发送起始位可成功。

问题根源与解决方法

核心原因

你的问题出在I2C发送完寄存器地址后,外设仍处于等待从机ACK的状态,此时直接设置START位会被硬件忽略。

STM32F1的I2C外设逻辑:发送完最后一个字节(寄存器地址)后,TXE(发送寄存器空)标志会先置位,但硬件要等到收到从机的ACK信号后,才会触发EV8_2事件(BTF置位,代表字节发送完成且ACK已接收)。如果在TXE触发的中断里直接设置START,硬件因处于等待ACK的状态,不会响应重复起始位请求。

规避操作有效的原因

  1. 读取DR寄存器:读取操作会清除TXE标志,迫使外设等待EV8_2事件(ACK收到),此时再设置START,硬件处于正确状态,能响应请求。
  2. 写入DR无效数据:写入操作让外设重新进入发送流程,覆盖之前的等待ACK状态,START请求会被硬件优先处理(重复起始位会中断当前发送)。
  3. 提前写入START:此时外设还未进入等待ACK的阶段,START请求能被及时响应。

正确操作流程

必须等待EV8_2事件(BTF置位,确认从机已ACK寄存器地址)触发中断后,再设置重复起始位。

中断处理核心逻辑示例

void I2C2_EV_IRQHandler(void)
{
    uint32_t sr1 = I2C2->SR1;
    uint32_t sr2 = I2C2->SR2; // 读取SR2会自动清除ADDR等标志

    if(sr1 & I2C_SR1_SB) // 起始位发送完成
    {
        I2C2->DR = DEVICE_ADDR_W; // 发送写方向设备地址
    }
    else if(sr1 & I2C_SR1_ADDR) // 地址发送完成并收到ACK
    {
        // 无需额外操作,读取SR2已清除ADDR标志
    }
    else if(sr1 & I2C_SR1_TXE) // 发送寄存器空,发送寄存器地址
    {
        I2C2->DR = REG_ADDR;
    }
    else if(sr1 & I2C_SR1_BTF) // 字节发送完成,已收到ACK
    {
        I2C2->CR1 |= I2C_CR1_START; // 发送重复起始位
    }
}

注意事项

  • 确保中断中完整处理所有I2C事件,不要遗漏BTF触发的EV8_2事件
  • 禁用ITBUFEN后,BTF属于ITEVFEN覆盖的EV事件范畴,会正常触发中断
  • 不要在TXE事件触发时直接发送重复起始位,必须等待BTF确认ACK已接收

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 02:40:21