嵌入式MCU的中断系统工作流程及其原理
哈哈这个问题非常经典也是很多嵌入式新手和老鸟都很关心的坑。我们就用STM32F103C8T6来讲顺便解释底层原理。咱一步步分析。1️⃣ 场景设定定时器10ms 自动重装载ARR也就是每 10ms 触发一次中断。ISR 内容里面做了大量操作 延时总共耗时 1.3 秒1300ms。CPUSTM32F103C8T6 是 Cortex-M3单核单线程没有操作系统。2️⃣ STM32 中断基本规则Cortex-M3 内核中断嵌套是允许的但有条件默认同优先级中断不嵌套。高优先级中断可以打断低优先级中断。同一个定时器的中断默认同优先级也就是如果前一次中断还在执行下一次中断触发时不会立即执行 ISR。内核会把“中断挂起”状态标记为pending。ISR 执行完之后CPU 才会去处理 pending 的中断。3️⃣ 你这个例子会发生什么情况第一次中断触发ISR 开始执行执行了 1.3 秒。10ms 后定时器再次到期中断挂起标志被设置pending。ISR还没结束所以这次中断不会立即打断 ISR。ISR 执行完 1.3 秒后CPU 会检测到 pending 标志。ISR 会立即被再次执行一次。期间定时器继续计数如果 10ms 又触发pending 标志再次置位。ISR 结束后又会再次执行。⚠️结果ISR 永远跑不完“实时”定时器节奏完全失效。4️⃣ 实际影响总结影响解释定时器无法保持准确周期ISR 太长导致定时事件被积压每次执行完 ISR 才处理下一次周期不再是 10ms而是 1.3s积压次数系统响应变慢CPU 被 ISR 占满其他任务几乎无机会执行特别是没有 RTOS堆积中断 pending如果 ISR 内部又有延时可能造成更严重的“卡死”可能触发 watchdog 重置MCU 的看门狗可能认为系统“死循环”5️⃣ 解决方案建议不要在定时器 ISR 里做耗时操作ISR 里只做标记、采样、清计数器等轻量操作。把重任务放在主循环或者 RTOS 任务里执行。volatileuint8_tflag0;voidTIMx_IRQHandler(void){if(TIM_GetITStatus(TIMx,TIM_IT_Update)!RESET){TIM_ClearITPendingBit(TIMx,TIM_IT_Update);flag1;// 只设置标志}}intmain(void){while(1){if(flag){flag0;heavy_processing();// 耗时操作放主循环}}}缩短 ISR 执行时间ISR 内不要调用delay()不要打印日志。只处理必要硬件操作。使用 RTOS 任务代替定时器 ISR 发信号/设置标志。重任务在低优先级任务中执行。保证高优先级 ISR 快速退出防止打断积压。总结一句话在 STM32 上如果 ISR 执行时间远超定时周期定时器中断会积压系统节奏彻底失效而且可能让 MCU 看起来“卡死”。我可以帮你画一张“ISR 太长导致中断积压的时间轴图”用 STM32 的例子标注 pending 状态非常直观。你想要我画吗好啊这个概念在 Cortex-M 系列 MCU 上很关键也和你之前提的“ISR 太长”问题直接相关。咱用STM32F103C8T6Cortex-M3来讲。1️⃣ 中断嵌套Nested Interrupt是什么中断嵌套就是当一个中断正在执行时如果另一个中断发生并且优先级比当前中断高CPU 可以“打断”当前中断去处理新的高优先级中断处理完再回来继续执行原来的中断。简单比喻你正在厨房煮饭中断A正在执行电话响了中断B发生如果电话比饭重要中断B优先级更高你先接电话接完再回来继续煮饭2️⃣ Cortex-M3 的中断嵌套机制STM32F103C8T6 是Cortex-M3它有一个叫NVICNested Vectored Interrupt Controller的中断控制器。NVIC 特性支持优先级分组可以配置 preemption 优先级和子优先级当 ISR 执行时如果新中断优先级高→ ISR 被“打断”执行高优先级 ISR如果新中断优先级低或相同→ 挂起等当前 ISR 结束再处理默认行为同一个定时器的中断默认同优先级所以 ISR 执行时下一次中断不会立即打断必须等 ISR 结束3️⃣ 实例说明假设TIM2 中断优先级 2USART1 中断优先级 1 更高时间轴t0ms: TIM2 中断触发 → ISR_TIM2 开始 t1ms: USART1 接收到数据 → ISR_USART1 打断 ISR_TIM2 t1.5ms: ISR_USART1 执行完 → 返回 ISR_TIM2 t... 继续执行 ISR_TIM2⚠️ 如果 TIM2 和 USART1同优先级t0ms: TIM2 ISR开始 t10ms: TIM2 再次触发 → 设 pending t1300ms: ISR_TIM2 结束 → CPU 检查 pending → 再执行 ISR_TIM2✅ 这个就是你前面说的“ISR太长导致中断积压”的典型场景4️⃣ 为什么要中断嵌套高优先级任务快速响应例如电机过流保护、紧急停止信号必须立刻处理实时性保证允许关键中断不被低优先级中断拖慢5️⃣ 注意事项嵌套会增加栈使用每个 ISR 都会把寄存器压入栈嵌套太深 → 可能造成栈溢出ISR 仍要尽量短即使支持嵌套也不意味着可以在 ISR 内做“1.3秒处理”优先级分组设置Cortex-M3 可以划分 preemption 优先级和子优先级决定哪些中断可以打断哪些 小总结中断嵌套 高优先级 ISR 可以打断低优先级 ISR同优先级 ISR 不会打断自己 → 累积 pendingISR 太长 → 定时器节奏彻底失效 → 可能让系统“卡死”如果你愿意我可以帮你画一张Cortex-M3 中断嵌套示意图直观地看到 pending、打断、返回的过程非常容易理解。你想让我画吗好这个问题非常关键你问的正是 STM32/Cortex-M 系列 MCU中断底层执行流程的核心理解了这些ISR 太长、嵌套、挂起这些问题就都能看明白了。咱用STM32F103C8T6Cortex-M3来讲。1️⃣ 中断挂起Pending标志位什么时候清除每个中断在NVIC和外设寄存器里都有一个挂起标志Pending Bit它的作用是记录“这个中断已经触发了但还没被处理”。清除时机手动清除软件清除大多数 STM32 外设都有中断挂起清除寄存器例如TIMx-SR的UIF位。ISR 内通常第一步就是清除这个标志否则同一次中断会被“反复触发”。voidTIM2_IRQHandler(void){if(TIM_GetITStatus(TIM2,TIM_IT_Update)!RESET){TIM_ClearITPendingBit(TIM2,TIM_IT_Update);// 清除挂起标志// 用户处理代码}}自动清除某些外设中断例如 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️⃣ 图示化理解时间轴 (ms) |---------------------------| t0 TIM2中断触发 → pending1 t0.1 CPU进入ISR t0.1~0.2 ISR执行 → 清除挂起标志 t0.2 ISR结束 → 栈恢复pending0 t0.25 有其他中断触发注意点挂起标志位必须清除否则 ISR 会重复执行NVIC 会根据优先级决定是否立即打断当前 ISR嵌套中断会增加栈使用深度太深可能溢出总结一句话中断挂起标志位在 ISR 执行期间由软件通常第一步清除清除后 ISR 才能顺利退出CPU 执行中断时硬件自动保存现场处理完 ISR 再恢复现场检查是否有 pending 中断并决定是否立即进入下一次中断。我可以帮你画一张STM32F1 中断执行挂起标志清除的流程图能直观看到 pending、NVIC、ISR 执行顺序非常容易理解。你想让我画吗

相关新闻

最新新闻

日新闻

周新闻

月新闻