嵌入式MCU的中断系统工作流程及其原理



哈哈,这个问题非常经典,也是很多嵌入式新手和老鸟都很关心的坑。我们就用 STM32F103C8T6 来讲,顺便解释底层原理。咱一步步分析。


1️⃣ 场景设定

  • 定时器:10ms 自动重装载(ARR),也就是每 10ms 触发一次中断。
  • ISR 内容:里面做了大量操作 + 延时,总共耗时 1.3 秒(1300ms)。
  • CPU:STM32F103C8T6 是 Cortex-M3,单核,单线程,没有操作系统。

2️⃣ STM32 中断基本规则

  • Cortex-M3 内核 中断嵌套是允许的,但有条件:

    • 默认 同优先级中断不嵌套
    • 高优先级中断可以打断低优先级中断
  • 同一个定时器的中断默认同优先级,也就是:

    • 如果前一次中断还在执行,下一次中断触发时不会立即执行 ISR。
    • 内核会把"中断挂起"状态标记为 pending
    • ISR 执行完之后,CPU 才会去处理 pending 的中断。

3️⃣ 你这个例子会发生什么

情况:
  1. 第一次中断触发:

    • ISR 开始执行,执行了 1.3 秒。
  2. 10ms 后,定时器再次到期:

    • 中断挂起标志被设置(pending)。
    • ISR 还没结束,所以这次中断不会立即打断 ISR。
  3. ISR 执行完 1.3 秒后:

    • CPU 会检测到 pending 标志。
    • ISR 会立即被再次执行一次。
  4. 期间定时器继续计数:

    • 如果 10ms 又触发,pending 标志再次置位。
    • ISR 结束后又会再次执行。

⚠️ 结果:ISR 永远跑不完"实时",定时器节奏完全失效


4️⃣ 实际影响总结

影响 解释
定时器无法保持准确周期 ISR 太长导致定时事件被积压,每次执行完 ISR 才处理下一次,周期不再是 10ms,而是 1.3s+积压次数
系统响应变慢 CPU 被 ISR 占满,其他任务几乎无机会执行(特别是没有 RTOS)
堆积中断 pending 如果 ISR 内部又有延时,可能造成更严重的"卡死"
可能触发 watchdog 重置 MCU 的看门狗可能认为系统"死循环"

5️⃣ 解决方案建议

  1. 不要在定时器 ISR 里做耗时操作

    • ISR 里只做 标记、采样、清计数器等轻量操作
    • 把重任务放在主循环或者 RTOS 任务里执行。
    c 复制代码
    volatile uint8_t flag = 0;
    
    void TIMx_IRQHandler(void) {
        if (TIM_GetITStatus(TIMx, TIM_IT_Update) != RESET) {
            TIM_ClearITPendingBit(TIMx, TIM_IT_Update);
            flag = 1; // 只设置标志
        }
    }
    
    int main(void) {
        while (1) {
            if (flag) {
                flag = 0;
                heavy_processing(); // 耗时操作放主循环
            }
        }
    }
  2. 缩短 ISR 执行时间

    • ISR 内不要调用 delay(),不要打印日志。
    • 只处理必要硬件操作。
  3. 使用 RTOS 任务代替

    • 定时器 ISR 发信号/设置标志。
    • 重任务在低优先级任务中执行。
    • 保证高优先级 ISR 快速退出,防止打断积压。

💡 总结一句话:

在 STM32 上,如果 ISR 执行时间远超定时周期,定时器中断会积压,系统节奏彻底失效,而且可能让 MCU 看起来"卡死"。


我可以帮你画一张 "ISR 太长导致中断积压的时间轴图" ,用 STM32 的例子标注 pending 状态,非常直观。

你想要我画吗?




好啊,这个概念在 Cortex-M 系列 MCU 上很关键,也和你之前提的"ISR 太长"问题直接相关。咱用 STM32F103C8T6(Cortex-M3) 来讲。


1️⃣ 中断嵌套(Nested Interrupt)是什么?

中断嵌套就是:

当一个中断正在执行时,如果另一个中断发生,并且优先级比当前中断高,CPU 可以"打断"当前中断去处理新的高优先级中断,处理完再回来继续执行原来的中断。

简单比喻:

  • 你正在厨房煮饭(中断A正在执行)
  • 电话响了(中断B发生)
  • 如果电话比饭重要(中断B优先级更高),你先接电话,接完再回来继续煮饭

2️⃣ Cortex-M3 的中断嵌套机制

STM32F103C8T6 是 Cortex-M3 ,它有一个叫 NVIC(Nested Vectored Interrupt Controller) 的中断控制器。

NVIC 特性:
  • 支持 优先级分组:可以配置 preemption 优先级和子优先级

  • 当 ISR 执行时:

    • 如果新中断 优先级高 → ISR 被"打断",执行高优先级 ISR
    • 如果新中断 优先级低或相同 → 挂起,等当前 ISR 结束再处理
默认行为:
  • 同一个定时器的中断默认同优先级
  • 所以 ISR 执行时,下一次中断不会立即打断,必须等 ISR 结束

3️⃣ 实例说明

假设:

  • TIM2 中断优先级 = 2
  • USART1 中断优先级 = 1 (更高)

时间轴:

复制代码
t=0ms: TIM2 中断触发 → ISR_TIM2 开始
t=1ms: USART1 接收到数据 → ISR_USART1 打断 ISR_TIM2
t=1.5ms: ISR_USART1 执行完 → 返回 ISR_TIM2
t=... 继续执行 ISR_TIM2

⚠️ 如果 TIM2 和 USART1 同优先级

复制代码
t=0ms: TIM2 ISR开始
t=10ms: TIM2 再次触发 → 设 pending
t=1300ms: ISR_TIM2 结束 → CPU 检查 pending → 再执行 ISR_TIM2

✅ 这个就是你前面说的"ISR太长导致中断积压"的典型场景


4️⃣ 为什么要中断嵌套?

  • 高优先级任务快速响应

    • 例如:电机过流保护、紧急停止信号必须立刻处理
  • 实时性保证

    • 允许关键中断不被低优先级中断拖慢

5️⃣ 注意事项

  1. 嵌套会增加 栈使用

    • 每个 ISR 都会把寄存器压入栈
    • 嵌套太深 → 可能造成 栈溢出
  2. ISR 仍要尽量短:

    • 即使支持嵌套,也不意味着可以在 ISR 内做"1.3秒处理"
  3. 优先级分组设置:

    • Cortex-M3 可以划分 preemption 优先级和子优先级
    • 决定哪些中断可以打断哪些

💡 小总结:

  • 中断嵌套 = 高优先级 ISR 可以打断低优先级 ISR
  • 同优先级 ISR 不会打断自己 → 累积 pending
  • ISR 太长 → 定时器节奏彻底失效 → 可能让系统"卡死"

如果你愿意,我可以帮你画一张 Cortex-M3 中断嵌套示意图,直观地看到 pending、打断、返回的过程,非常容易理解。

你想让我画吗?




好,这个问题非常关键,你问的正是 STM32/Cortex-M 系列 MCU 中断底层执行流程 的核心,理解了这些,ISR 太长、嵌套、挂起这些问题就都能看明白了。咱用 STM32F103C8T6(Cortex-M3) 来讲。


1️⃣ 中断挂起(Pending)标志位什么时候清除?

每个中断在 NVIC外设寄存器里都有一个挂起标志(Pending Bit),它的作用是记录"这个中断已经触发了,但还没被处理"。

清除时机:

  1. 手动清除(软件清除)

    • 大多数 STM32 外设都有中断挂起清除寄存器(例如 TIMx->SRUIF 位)。
    • ISR 内通常第一步就是清除这个标志,否则同一次中断会被"反复触发"。
    c 复制代码
    void TIM2_IRQHandler(void) {
        if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
            TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除挂起标志
            // 用户处理代码
        }
    }
  2. 自动清除

    • 某些外设中断,例如 STM32F1 的 EXTI(外部中断),某些配置下可以硬件自动清除。
    • 大多数情况下还是 软件清除更安全

⚠️ 如果不清除挂起位

  • ISR 执行完后 NVIC 会发现挂起位仍然置位 → ISR 会立即再次执行 → 造成"无限循环"中断

2️⃣ Cortex-M3 中断处理流程(简化版)

假设外设 TIM2 触发中断:

复制代码
1️⃣ 中断触发
   - 外设产生中断请求
   - 对应的 NVIC Pending 位被置 1

2️⃣ NVIC 响应中断
   - CPU 检查中断优先级
   - 如果当前没有更高优先级的 ISR 在执行 → 准备进入 ISR

3️⃣ ISR 入口(硬件自动操作)
   - 自动保存寄存器 r0-r3, r12, lr, pc, xPSR 到栈
   - PC 跳转到 ISR 入口地址

4️⃣ ISR 执行(软件操作)
   - 用户代码开始执行
   - **第一步通常清除中断挂起标志**
   - 执行实际业务逻辑(采样、标志置位、发送数据等)

5️⃣ ISR 退出(硬件自动操作)
   - 执行 `BX LR` 返回
   - Cortex-M3 自动弹出栈上的寄存器
   - 如果有 pending 中断且优先级合适 → CPU 自动跳转去处理

6️⃣ 返回主程序或下一个中断

3️⃣ 图示化理解

text 复制代码
时间轴 (ms)
|---------------------------|
t=0    TIM2中断触发  → pending=1
t=0.1  CPU进入ISR
t=0.1~0.2 ISR执行   → 清除挂起标志
t=0.2  ISR结束      → 栈恢复,pending=0
t=0.25  有其他中断触发

注意点:

  • 挂起标志位必须清除,否则 ISR 会重复执行
  • NVIC 会根据优先级决定是否立即打断当前 ISR
  • 嵌套中断会增加栈使用,深度太深可能溢出

💡 总结一句话

中断挂起标志位在 ISR 执行期间由软件(通常第一步)清除,清除后 ISR 才能顺利退出;CPU 执行中断时,硬件自动保存现场,处理完 ISR 再恢复现场,检查是否有 pending 中断并决定是否立即进入下一次中断。


我可以帮你画一张 STM32F1 中断执行+挂起标志清除的流程图,能直观看到 pending、NVIC、ISR 执行顺序,非常容易理解。

你想让我画吗?

相关推荐
LCG元2 小时前
STM32实战:基于STM32F103的智慧教室环境监控系统(CO₂+光照+人数统计)
前端·stm32·嵌入式硬件
振南的单片机世界2 小时前
推挽输出:上管推、下管拉,驱动强但不“合群”
arm开发·stm32·单片机·嵌入式硬件
森利威尔电子-3 小时前
森利威尔SL7140|2.5–24V 宽压 / 10mA–2A / PWM 调光 线性 LED 恒流驱动
单片机·嵌入式硬件·集成电路·芯片·电源芯片
VALENIAN瓦伦尼安教学设备3 小时前
填补国内空白!瓦伦尼安发布首台船机机械故障诊断振动实验台
大数据·人工智能·嵌入式硬件
踏着七彩祥云的小丑4 小时前
嵌入式测试学习第 12天:串口基础概念:UART、波特率、数据位、校验位
单片机·嵌入式硬件
夜阑寄语4 小时前
基础元器件
单片机·嵌入式硬件
北山有鸟4 小时前
常用的快捷键
linux·前端·chrome·单片机·学习
QH139292318805 小时前
R&S®SMBV100B 矢量信号发生器 5G/Wi-Fi/GNSS 主力源
网络·科技·嵌入式硬件·集成测试·信息与通信
方山子哦6 小时前
软硬件uart、iic、spi、can,及蓝牙和usb的区别及应用场景
单片机·嵌入式硬件