2、中断处理流程:中断请求、中断响应、中断服务程序、中断返回

中断处理,说白了就是CPU被“打断”后,怎么去处理紧急事件,再回来继续干活。我刚开始接触嵌入式时,总觉得中断很神秘。后来调了几年驱动,踩了不少坑,才真正摸透这四步流程。

这四步分别是:中断请求 → 中断响应 → 中断服务程序 → 中断返回。每一步都有讲究,咱们一个一个说。

2.1 中断请求

中断请求,就是外设告诉CPU:“嘿,我有事找你!”

这个请求信号,可以是电平触发,也可以是边沿触发。我个人习惯用边沿触发,尤其是下降沿。为什么?因为电平触发容易出问题——如果外设一直拉着这个电平,CPU就会一直被中断,根本干不了别的活。

注意: 我曾经在一个项目中,用了电平触发的中断,结果外设的“请求信号”没及时拉高,CPU就卡在中断里出不来了。后来改成边沿触发,问题解决。

中断请求的来源,一般分三类:

  • 外部中断:来自GPIO引脚,比如按键、传感器
  • 内部中断:来自片内外设,比如定时器、UART、ADC
  • 软件中断:程序自己触发的,比如系统调用

你想想看,如果多个外设同时发中断请求,CPU怎么知道先处理谁?这就涉及到中断优先级了。嗯,这里要注意,优先级高的中断可以打断优先级低的,但反过来不行。

2.2 中断响应

CPU收到中断请求后,不会立刻就去处理。它得先把手头的事“保存好”,才能去响应中断。这个过程,我们叫中断响应。

中断响应做了三件事:

  1. 关中断:防止在响应过程中被另一个中断打断
  2. 保存断点:把当前正在执行的指令地址(PC指针)压入栈中
  3. 跳转到中断向量表:找到对应的中断服务程序入口地址

我记得有一次调试,发现中断响应后程序跑飞了。查了半天,原来是中断向量表地址配错了。说白了,CPU跳到了一个错误的地方,当然会出问题。

关键点: 中断响应是硬件自动完成的,不需要我们写代码。但中断向量表的配置,必须由程序员手动完成。这个表放错了,整个中断系统就废了。

2.3 中断服务程序

中断服务程序(ISR),就是真正处理中断事件的代码。这部分是我们程序员写的。

写ISR有几个铁律,我建议你记牢:

  • 尽量短小:ISR里不要做复杂运算,不要调用printf,不要延时
  • 快进快出:处理完必要的事,立刻退出
  • 保护现场:如果ISR里要用到全局变量或寄存器,记得先保存再恢复

我曾经在一个项目中,ISR里放了个大循环,结果整个系统卡死了。你想想看,中断是最高优先级的任务,它不退出,其他任务永远没机会执行。

一个典型的ISR结构是这样的:

void TIM2_IRQHandler(void)
{
    // 1. 检查中断标志位
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
        // 2. 清除中断标志位(这一步千万不能忘!)
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        
        // 3. 处理中断事件
        // 比如:翻转一个LED,或者更新一个计数值
        
        // 4. 退出(硬件自动完成)
    }
}
提示: 很多新手容易忘掉“清除中断标志位”。如果不清除,CPU会认为中断请求还在,就会反复进入ISR。嗯,这个坑我踩过不止一次。

2.4 中断返回

中断服务程序执行完后,CPU要回到之前被打断的地方,继续执行原来的代码。这个过程叫中断返回。

中断返回做了三件事:

  1. 恢复断点:从栈中弹出之前保存的PC指针
  2. 恢复现场:恢复之前保存的寄存器值
  3. 开中断:重新允许CPU响应新的中断请求

说白了,中断返回就是“从哪里来,回哪里去”。如果现场没恢复好,程序就会跑偏。我记得有一次,ISR里修改了一个全局变量,但没恢复,结果主程序就乱了。

警告: 中断返回时,一定要确保栈指针正确。如果ISR里压栈和出栈次数不匹配,栈就会乱掉。轻则程序跑飞,重则系统崩溃。

2.5 中断处理流程总览

为了让你更直观地理解整个流程,我画了一张图:

主程序执行 中断请求 中断响应 (保存断点、关中断) 中断服务程序(ISR) (处理中断事件、清除标志位) 中断返回 (恢复断点、开中断) 主程序 中断请求 中断响应 ISR 中断返回

从图中可以看出,整个流程是一个闭环。主程序执行时,收到中断请求,然后响应、处理、返回,最后继续执行主程序。嗯,这个流程看起来简单,但实际项目中,每一步都可能出问题。

2.6 避坑指南

我总结了几条实战经验,希望能帮你少走弯路:

  • 中断标志位一定要清:不清的话,CPU会反复进中断,系统就卡死了
  • ISR里不要用延时:延时会让CPU空转,其他中断就进不来了
  • 注意中断嵌套:高优先级中断可以打断低优先级,但别让嵌套太深,否则栈会爆
  • 保护共享资源:如果ISR和主程序共用同一个变量,记得加锁或关中断保护
我的习惯: 在ISR里只做“标记”,不做“处理”。比如,ISR里只设置一个标志位,然后在主循环里检查这个标志位,再做具体处理。这样ISR就能快速退出,系统响应也更快。

中断处理流程,说白了就是“打断-保存-处理-恢复”这四个动作。理解了这个流程,你就能写出稳定可靠的中断程序。嗯,这部分内容就到这里,下一节我们聊聊中断优先级和嵌套,那才是真正考验设计能力的地方。


可可精品资料库