1. 中断系统基础:中断的概念、中断的作用、中断的优先级、中断嵌套
各位同学,咱们今天正式进入中断系统的学习。说实话,中断这个概念,是嵌入式开发里最核心、也最容易让人迷糊的东西之一。我当年刚入行时,就因为没搞懂中断优先级,让一个电机控制项目在高速运行时频繁“抽风”,查了整整三天才找到原因。嗯,从那以后,我对中断就再也不敢马虎了。
1.1 中断到底是什么?
先问大家一个问题:你正在厨房炒菜,突然门铃响了,你会怎么做?
正常人都会——关小火、去开门、处理完门铃的事、再回来继续炒菜。对吧?
单片机里的中断,本质上就是这套逻辑。CPU 正在执行主程序(炒菜),突然某个外设或内部事件触发了信号(门铃响了),CPU 暂停当前工作,保存现场(关小火),跳去执行一个专门的服务程序(开门处理),处理完再回来接着干(继续炒菜)。
这个“暂停-处理-恢复”的机制,就是中断。
中断的核心三要素:
- 触发源:谁发起的请求?比如定时器溢出、外部引脚电平变化、串口收到数据。
- 中断服务函数(ISR):CPU 跳过去执行的那段专用代码。
- 返回机制:执行完 ISR 后,CPU 能准确回到原来的位置继续跑。
你想想看,如果没有中断,CPU 就得不停地轮询检查每个外设的状态——“定时器到了没?按键按了没?数据来了没?”这得多浪费算力。中断让 CPU 从“主动问”变成了“被动等”,效率直接翻倍。
1.2 中断的作用——为什么非用不可?
我个人习惯把中断的作用归纳为四点,咱们用表格来看,更清楚:
| 作用 | 说明 | 实际场景举例 |
|---|---|---|
| 实时响应 | 对外部事件做出毫秒级甚至微秒级的反应 | 电机堵转检测、急停按钮触发 |
| 并行处理 | CPU 可以“同时”处理多个任务(宏观并行) | 一边采集传感器,一边输出 PWM |
| 降低功耗 | CPU 没事时可以休眠,有中断才唤醒 | 电池供电设备,按键唤醒系统 |
| 简化编程 | 不用在主循环里写一堆轮询代码 | 串口接收数据,中断自动处理 |
我记得有一次做无刷电机驱动,主循环里跑着 PID 运算和通信协议,如果不用中断去捕获霍尔传感器的跳变沿,电机换相时机根本跟不上转速。用了中断后,霍尔信号一来,CPU 立刻响应换相,主循环该干嘛干嘛,互不干扰。
小提示:中断服务函数要短、要快、不能阻塞。我见过有人把延时函数直接写在 ISR 里,结果整个系统卡死。记住:ISR 里只做最必要的事,比如置个标志位、读个寄存器,复杂处理放主循环。
1.3 中断的优先级——谁先谁后?
当多个中断同时发生时,CPU 该先处理谁?这就涉及到优先级了。
每个中断源都有一个优先级编号。数值越小,优先级越高(具体看芯片手册,有些是数值越大越高)。高优先级的中断可以打断低优先级的中断,但反过来不行。
咱们用一张图来理解:
这张图展示的就是中断嵌套的典型场景。主程序跑得好好的,突然来了个低优先级中断,CPU 进去处理。处理到一半,一个更高优先级的中断来了——CPU 二话不说,先挂起当前 ISR,去处理高优先级的,处理完再回来把低优先级的收尾。
为什么会这样设计?说白了,有些事件就是等不得。比如电机过流保护,必须立即响应,晚一毫秒都可能烧 MOSFET。而串口发个数据,晚几毫秒完全没问题。
注意:中断优先级不是越多越好。有些低端单片机只有两级优先级(高/低),高端的有 8 级甚至 16 级。我建议你:能用两级解决的,别用四级。优先级层级越多,嵌套越深,出 bug 的概率越大。我曾经在一个项目里用了 6 级嵌套,结果某个极端条件下栈溢出了,系统直接死机。从那以后,我给自己定了个规矩——嵌套不超过 3 层。
1.4 中断嵌套——深入理解
中断嵌套,说白了就是“中断里套中断”。
要实现嵌套,硬件上需要满足两个条件:
- CPU 支持多级优先级——硬件能区分哪个中断更重要。
- 中断控制器允许嵌套——在处理低优先级中断时,还能响应更高优先级的中断请求。
咱们用一段伪代码来模拟嵌套过程:
// 主程序
void main() {
while(1) {
do_something(); // 正常干活
}
}
// 低优先级中断(优先级 2)
void ISR_Low(void) {
// 保存现场(硬件自动做)
flag_low = 1; // 标记:低优先级开始
delay_ms(10); // 模拟处理时间
// 就在这 10ms 里,高优先级中断来了!
flag_low_done = 1; // 标记:低优先级完成
// 恢复现场(硬件自动做)
}
// 高优先级中断(优先级 1)
void ISR_High(void) {
// 保存现场
flag_high = 1; // 标记:高优先级开始
// 紧急处理,比如关闭电机
motor_stop();
// 恢复现场
}
实际执行顺序是:
- 主程序跑
do_something() - 低优先级中断触发 → CPU 跳进
ISR_Low - 执行到
delay_ms(10)时,高优先级中断触发 - CPU 暂停
ISR_Low,跳进ISR_High ISR_High执行完毕,返回ISR_Low继续ISR_Low执行完毕,返回主程序
关键点:中断嵌套时,CPU 会自动把当前 ISR 的断点地址和寄存器状态压入栈中。嵌套越深,栈消耗越大。如果你的栈空间分配不够,就会出现“栈溢出”——程序跑飞,查都查不出来。我建议你:每个中断嵌套层级预留至少 64 字节的栈空间。
1.5 实际项目中的优先级分配策略
说了这么多理论,咱们来点实际的。在电机控制项目里,我一般这样分配中断优先级:
| 优先级 | 中断源 | 原因 |
|---|---|---|
| 最高(1) | 过流/过温保护 | 硬件安全,必须立即响应,否则烧器件 |
| 高(2) | 霍尔传感器跳变 / 编码器 Z 信号 | 电机换相时机,错过就丢步 |
| 中(3) | PWM 定时器溢出 / 比较匹配 | 控制周期定时,允许微秒级延迟 |
| 低(4) | 串口接收 / ADC 转换完成 | 数据通信和采样,延迟几毫秒无影响 |
| 最低(5) | 按键扫描 / LED 刷新 | 人机交互,几十毫秒延迟用户根本感觉不到 |
这个分配原则我用了很多年,基本没出过问题。核心思路就一条:对时间敏感、影响安全的,优先级给高;对时间不敏感的,优先级给低。
避坑指南:我曾经在一个项目中,把串口接收中断优先级设得比 PWM 定时器还高。结果串口数据一多,PWM 周期被频繁打断,电机转速出现明显抖动。后来把优先级调回来,问题立刻解决。记住:中断优先级不是越高越好,合理分配才是关键。
1.6 本章小结
中断系统是单片机开发的基石。咱们这一章讲了四个核心概念:
- 中断的概念——CPU 暂停当前任务,去处理紧急事件,处理完再回来。
- 中断的作用——实时响应、并行处理、降低功耗、简化编程。
- 中断的优先级——谁更重要谁先处理,高优先级可以打断低优先级。
- 中断嵌套——中断里套中断,注意栈空间和嵌套深度。