2、中断处理流程:中断请求、中断响应、中断服务程序、中断返回
中断处理,说白了就是CPU被“打断”后,怎么去处理紧急事件,再回来继续干活。我刚开始接触嵌入式时,总觉得中断很神秘。后来调了几年驱动,踩了不少坑,才真正摸透这四步流程。
这四步分别是:中断请求 → 中断响应 → 中断服务程序 → 中断返回。每一步都有讲究,咱们一个一个说。
2.1 中断请求
中断请求,就是外设告诉CPU:“嘿,我有事找你!”
这个请求信号,可以是电平触发,也可以是边沿触发。我个人习惯用边沿触发,尤其是下降沿。为什么?因为电平触发容易出问题——如果外设一直拉着这个电平,CPU就会一直被中断,根本干不了别的活。
中断请求的来源,一般分三类:
- 外部中断:来自GPIO引脚,比如按键、传感器
- 内部中断:来自片内外设,比如定时器、UART、ADC
- 软件中断:程序自己触发的,比如系统调用
你想想看,如果多个外设同时发中断请求,CPU怎么知道先处理谁?这就涉及到中断优先级了。嗯,这里要注意,优先级高的中断可以打断优先级低的,但反过来不行。
2.2 中断响应
CPU收到中断请求后,不会立刻就去处理。它得先把手头的事“保存好”,才能去响应中断。这个过程,我们叫中断响应。
中断响应做了三件事:
- 关中断:防止在响应过程中被另一个中断打断
- 保存断点:把当前正在执行的指令地址(PC指针)压入栈中
- 跳转到中断向量表:找到对应的中断服务程序入口地址
我记得有一次调试,发现中断响应后程序跑飞了。查了半天,原来是中断向量表地址配错了。说白了,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. 退出(硬件自动完成)
}
}
2.4 中断返回
中断服务程序执行完后,CPU要回到之前被打断的地方,继续执行原来的代码。这个过程叫中断返回。
中断返回做了三件事:
- 恢复断点:从栈中弹出之前保存的PC指针
- 恢复现场:恢复之前保存的寄存器值
- 开中断:重新允许CPU响应新的中断请求
说白了,中断返回就是“从哪里来,回哪里去”。如果现场没恢复好,程序就会跑偏。我记得有一次,ISR里修改了一个全局变量,但没恢复,结果主程序就乱了。
2.5 中断处理流程总览
为了让你更直观地理解整个流程,我画了一张图:
从图中可以看出,整个流程是一个闭环。主程序执行时,收到中断请求,然后响应、处理、返回,最后继续执行主程序。嗯,这个流程看起来简单,但实际项目中,每一步都可能出问题。
2.6 避坑指南
我总结了几条实战经验,希望能帮你少走弯路:
- 中断标志位一定要清:不清的话,CPU会反复进中断,系统就卡死了
- ISR里不要用延时:延时会让CPU空转,其他中断就进不来了
- 注意中断嵌套:高优先级中断可以打断低优先级,但别让嵌套太深,否则栈会爆
- 保护共享资源:如果ISR和主程序共用同一个变量,记得加锁或关中断保护
中断处理流程,说白了就是“打断-保存-处理-恢复”这四个动作。理解了这个流程,你就能写出稳定可靠的中断程序。嗯,这部分内容就到这里,下一节我们聊聊中断优先级和嵌套,那才是真正考验设计能力的地方。
可可精品资料库