1. 中断系统概述:什么是中断、中断优先级与嵌套、STM32中断向量表
大家好,我是你们的老朋友。今天咱们来聊聊嵌入式开发里最核心、也最让人又爱又恨的一个话题——中断系统。
说实话,我刚开始学STM32那会儿,对中断的理解就是“一个东西突然跳出来打断你”。后来踩了不少坑,才真正搞明白它背后的门道。今天我就把这几年的经验掰开揉碎了讲给你听。
1.1 什么是中断?
先问个问题:你正在写代码,突然串口收到一包数据,怎么办?
最笨的办法是轮询——CPU不停地问“有数据吗?有数据吗?”。这就像你一边写作业,一边每隔两秒抬头看看有没有人敲门。效率低不说,还容易错过。
中断就是解决这个问题的。它让外设在需要的时候主动“喊”CPU一声:“嘿,我有数据了,快来处理!”
我习惯把中断比作“电话铃”。你正在干活,电话响了(中断来了),你接起来处理(中断服务函数),处理完挂电话继续干活(返回主程序)。
核心概念:中断是CPU暂停当前任务,转而去处理一个紧急事件,处理完再回来的机制。
中断的好处很明显:
- 实时响应:外设事件来了立刻处理,不用等轮询
- 节省CPU:没事的时候CPU可以干别的,不用傻等
- 模块化:每个中断处理自己的事,代码结构清晰
嗯,这里要注意:中断不是万能的。我在项目中遇到过中断处理太慢,导致后续中断丢失的情况。后面我们会详细讲怎么避免。
1.2 中断优先级与嵌套
假设你正在处理串口中断,这时候定时器又触发了中断。谁先处理?
这就引出了中断优先级的概念。STM32里,每个中断都可以设置一个优先级。数字越小,优先级越高。
我刚开始做项目时,把所有中断优先级都设成一样。结果有一次,两个中断同时触发,系统直接卡死了。后来才明白——优先级设置不当,会出大问题。
1.2.1 抢占优先级与子优先级
STM32把优先级分成两部分:
- 抢占优先级:决定能否打断正在执行的中断
- 子优先级:当抢占优先级相同时,决定谁先执行
说白了,抢占优先级是“能不能插队”,子优先级是“排队时谁站前面”。
| 抢占优先级 | 子优先级 | 行为 |
|---|---|---|
| 高 | 任意 | 可以打断低抢占优先级的中断 |
| 相同 | 高 | 不能打断,但先执行 |
| 相同 | 相同 | 按硬件编号顺序执行 |
我的经验:一般把时间敏感的中断(比如定时器)设高抢占优先级,把数据量大的中断(比如串口)设低优先级。这样既能保证实时性,又不会让CPU被频繁打断。
1.2.2 中断嵌套
中断嵌套,说白了就是一个中断正在执行,另一个更高优先级的中断来了,CPU先处理新的,处理完再回来继续旧的。
我曾经在一个项目里,把按键中断优先级设得比定时器还高。结果按键一按,定时器中断就被打断,导致PWM波形乱了。嗯,这就是典型的嵌套没设计好。
中断嵌套的规则很简单:
- 高优先级中断可以打断低优先级中断
- 同级中断不能互相打断
- 中断服务函数里要尽量短,避免影响其他中断
避坑指南:我曾经在中断服务函数里调用了printf,结果串口中断优先级设得低,被其他中断打断,打印出来的数据全是乱的。记住:中断里别做耗时操作!
1.3 STM32中断向量表
中断向量表,说白了就是一张“地址表”。每个中断对应一个地址,CPU收到中断信号后,就去这张表里查地址,然后跳过去执行。
STM32的中断向量表放在Flash的起始地址(0x08000000)。前16个是系统异常(比如复位、硬错误),后面才是外设中断。
我习惯用一张图来理解:
这张图你看懂了吗?复位向量在最前面,CPU上电后第一件事就是去0x08000004取地址,然后跳转到main函数。
1.3.1 中断向量表在代码中的体现
在STM32的启动文件(startup_stm32f4xx.s)里,你会看到这样的代码:
__Vectors DCD __initial_sp ; 栈顶地址
DCD Reset_Handler ; 复位向量
DCD NMI_Handler ; NMI
DCD HardFault_Handler ; 硬错误
DCD MemManage_Handler ; 内存管理
DCD BusFault_Handler ; 总线错误
DCD UsageFault_Handler ; 用法错误
...
DCD TIM2_IRQHandler ; TIM2中断
DCD TIM3_IRQHandler ; TIM3中断
每个DCD后面跟的就是中断服务函数的地址。你写的中断函数名必须和这里一致,否则CPU找不到入口。
小技巧:我习惯在启动文件里把不用的中断都指向一个空函数,防止意外触发导致程序跑飞。比如:
; 未使用的中断统一指向
DCD Default_Handler
1.3.2 中断向量表偏移
有时候我们需要把中断向量表放到RAM里(比如做IAP升级)。这时候就要用到向量表偏移。
STM32提供了SCB->VTOR寄存器来设置偏移量:
// 将向量表偏移到0x20000000(RAM起始地址)
SCB->VTOR = 0x20000000;
我曾经在一个OTA项目里,因为忘记设置VTOR,导致升级后中断全部失效。嗯,那一次排查了整整两天。
1.4 总结
好了,今天的内容就到这里。我们讲了:
- 中断是什么——说白了就是“电话铃”
- 优先级和嵌套——谁先谁后,能不能打断
- 中断向量表——一张地址表,CPU靠它找到中断函数
这些是中断系统的基础。后面我们会深入每个外设的中断配置,到时候你会发现,理解了今天的内容,后面的路就好走多了。
记住我的一句话:中断设计得好,系统稳如老狗;中断设计得差,调试到天亮。
下节课我们讲NVIC(嵌套向量中断控制器)的配置,那是STM32中断系统的“大脑”。到时候我会手把手教你配置优先级分组、使能中断、设置抢占优先级。准备好了吗?