1、中断基础概念:什么是中断、中断的作用、中断与轮询的对比
1.1 到底什么是中断?
先问大家一个问题:你正在写代码,突然有人拍你肩膀,你会怎么做?
正常人会先停下手里的活,转头看看是谁,处理完这件事,再回头继续写代码。对吧?
中断,说白了就是这个道理。
中断是CPU处理异步事件的一种硬件机制。当外设或内部模块需要CPU关注时,它会发送一个电信号——我们叫它“中断请求”。CPU收到这个信号后,会暂停当前正在执行的程序,保存好现场(就是各种寄存器的值),然后跳到一个专门的处理函数里去干活。干完了,再回来接着刚才断掉的地方继续执行。
我刚开始做嵌入式开发时,总觉得中断很神秘。后来自己写了一个按键中断的程序,按下按键,LED灯亮,松开就灭。那一刻我才真正理解——中断就是CPU的“临时插队”机制。
核心要点:
- 中断是硬件触发的,不是软件轮询的
- CPU会暂停当前任务,去处理紧急事件
- 处理完后,CPU会回到原来的任务继续执行
1.2 中断到底有什么用?
你想想看,如果没有中断,CPU怎么知道外设发生了什么事?
只能不停地去问:“嘿,按键你按了吗?”“嘿,串口你收到数据了吗?”“嘿,定时器你到时间了吗?”
这就是轮询。CPU像个焦虑症患者,每隔几微秒就去检查一次。大部分时候,外设根本没动静,CPU白白浪费了时间。
中断的作用,就是让外设主动通知CPU。
我做过一个项目,需要同时处理串口接收、按键检测、定时器溢出三个任务。如果用轮询,主循环里全是if判断,代码又臭又长,还容易漏掉事件。改用中断后,每个外设都有自己的中断服务函数,代码清晰多了,响应也快。
总结一下中断的几个核心作用:
- 提高CPU利用率:不用傻等,该干嘛干嘛
- 实时响应:紧急事件来了,立刻处理
- 支持多任务:多个外设可以“同时”工作
- 降低功耗:CPU可以休眠,有事件再唤醒
我的经验:在低功耗项目中,中断几乎是必须的。让CPU大部分时间处于睡眠模式,只有中断来了才醒来干活。这样电池能用很久。
1.3 中断 vs 轮询:到底选哪个?
很多新手会纠结这个问题。我直接说结论:没有绝对的好坏,看场景。
咱们来做个对比:
| 对比项 | 中断 | 轮询 |
|---|---|---|
| CPU利用率 | 高,有事才处理 | 低,一直在检查 |
| 响应速度 | 快,事件触发立即响应 | 慢,取决于轮询周期 |
| 编程复杂度 | 较高,需处理临界区、嵌套等 | 简单,就是循环加判断 |
| 适用场景 | 事件不频繁、要求实时性 | 事件频繁、对实时性要求不高 |
| 功耗 | 低,可休眠 | 高,CPU一直跑 |
举个例子:
- 按键检测:用中断好。人按一下,几百毫秒才松开,CPU没必要一直盯着。
- ADC连续采样:用轮询好。每秒采样几千次,中断进进出出反而浪费开销。
- 串口接收:看情况。数据来得慢用中断,数据流很大用DMA+中断。
避坑指南:我曾经在一个项目中,把所有的外设都开了中断。结果中断嵌套太多,CPU大部分时间都在处理中断,主循环反而跑不动了。后来我把一些不紧急的事件改成了轮询,系统才稳定下来。
记住:中断不是越多越好。每个中断都有开销——保存现场、跳转、恢复现场。中断太频繁,系统性能反而会下降。
1.4 中断的基本流程
搞懂了概念,咱们看看中断到底是怎么跑的。我习惯把它分成五步:
- 中断请求:外设拉高中断引脚,或者写中断标志位
- 中断响应:CPU检测到中断信号,判断优先级,决定是否响应
- 保护现场:CPU自动把PC、状态寄存器等压栈
- 中断处理:跳转到中断向量表,执行对应的ISR(中断服务函数)
- 恢复现场:执行完ISR,出栈恢复寄存器,继续执行原程序
这里有个细节:中断向量表。每个中断源都有一个固定的入口地址。CPU根据中断号,去向量表里找到对应的ISR地址,然后跳过去。
以ARM Cortex-M系列为例,中断向量表长这样:
; 中断向量表示例(简化版)
__Vectors DCD __initial_sp ; 栈顶指针
DCD Reset_Handler ; 复位中断
DCD NMI_Handler ; 不可屏蔽中断
DCD HardFault_Handler ; 硬错误
DCD MemManage_Handler ; 内存管理
DCD BusFault_Handler ; 总线错误
DCD UsageFault_Handler ; 用法错误
...
DCD TIM2_IRQHandler ; 定时器2中断
DCD USART1_IRQHandler ; 串口1中断
小技巧:写ISR时,一定要快进快出。我一般只在ISR里设置标志位,真正的处理逻辑放在主循环里。这样能减少中断占用时间,避免影响其他中断的响应。
1.5 中断的优先级与嵌套
多个中断同时来了怎么办?谁先处理?
这就涉及到中断优先级了。每个中断源都有一个优先级数值。数值越小,优先级越高(具体看芯片手册,有的芯片是反的)。
高优先级的中断可以打断低优先级的中断,这叫中断嵌套。
举个例子:
- 系统正在处理串口中断(优先级3)
- 突然来了一个定时器中断(优先级1)
- CPU会暂停串口中断,先去处理定时器中断
- 定时器中断处理完,再回来继续处理串口中断
听起来很合理对吧?但这里有个坑:中断嵌套太深,栈空间会爆炸。
我曾经踩过的坑:在一个项目中,我设置了5级中断嵌套。结果某个极端情况下,中断一层套一层,栈空间直接溢出,系统跑飞了。后来我把中断嵌套限制在3级以内,并且给每个任务分配了独立的栈空间,问题才解决。
建议:中断嵌套不要超过3层。能用轮询解决的,就别用中断。
1.6 小结
中断是嵌入式系统的核心机制。它让CPU从“傻等”变成了“随叫随到”。
记住几个关键点:
- 中断是硬件事件触发的,不是软件轮询的
- 中断能提高CPU利用率,但也要付出代价(保存现场、嵌套风险)
- 中断和轮询各有适用场景,别盲目追求中断
- ISR要短小精悍,别在里面干重活
下一章,咱们聊聊中断的具体实现——中断控制器、中断向量表、以及如何配置一个中断。到时候我会拿STM32和RISC-V两个平台做对比,看看它们的中断机制有什么不同。