一、中断基础概念

各位同学好,我是老张。做嵌入式这行快二十年了,今天咱们聊聊中断。说实话,中断这玩意儿,是嵌入式系统的灵魂。没有中断,你的CPU就得像个傻子一样轮询——那效率,想想都头疼。

1.1 什么是中断

中断,说白了就是“CPU正在干活,突然被叫去处理更重要的事”。

我习惯这么跟新人解释:你正在写代码,突然电话响了。你放下键盘接电话,接完再回来继续写。这个电话铃声,就是中断信号。你接电话的动作,就是中断服务程序。

中断的核心价值在于——让CPU从“主动查询”变成“被动响应”。你想想看,如果没有中断,CPU得不停地问“有按键按下吗?”“有数据到了吗?”——这不累死?

中断的本质:一种硬件机制,允许外部设备或内部事件“打断”CPU当前执行的主程序,转而去执行一个特定的处理函数。

我在项目中遇到过最典型的例子:一个串口通信模块,如果不使用中断,CPU每毫秒都要去检查接收寄存器。用了中断后,数据到了才通知CPU。同样的CPU,处理能力提升了至少5倍。

1.2 中断向量表

中断向量表,嗯,这个名字听起来挺唬人。其实它就是一张“地址映射表”。

每个中断源都有一个编号,比如外部中断0、定时器1溢出中断等等。CPU收到中断信号后,根据这个编号去查表,找到对应的中断服务程序入口地址,然后跳过去执行。

我画了个图,帮你理解这个过程:

CPU 正在执行主程序 外部中断0 定时器1 串口接收 中断向量表 向量号0 → 0x0000_0000 向量号1 → 0x0000_0004 向量号2 → 0x0000_0008 ... 向量号16 → 0x0000_0040 向量号17 → 0x0000_0044 ... 中断服务程序 ISR_External0 ISR_Timer1 ISR_UART_Rx ... 实际代码 ... 执行完ISR后返回主程序 中断响应流程示意图

这张图你看懂了吗?CPU收到中断请求后,先去查向量表,找到对应的ISR地址,跳过去执行,执行完再回来。

我的经验:写启动代码时,中断向量表一定要放在正确的位置。ARM Cortex-M系列要求向量表必须从0地址开始,或者通过VTOR寄存器重映射。我曾经见过一个同事,把向量表放错了位置,结果一进中断就跑飞了——查了两天才找到原因。

1.3 中断优先级

多个中断同时来了怎么办?谁先处理?这就涉及到优先级了。

优先级,就是给每个中断源排个队。数字越小优先级越高(有些芯片反过来,看手册)。

我习惯把优先级分成几个等级:

优先级等级 典型应用 说明
最高(0-1) 系统时钟、看门狗 系统稳定性相关,不能丢
高(2-3) 外部紧急事件 比如急停按钮、过流保护
中(4-5) 通信接口 UART、SPI、I2C等
低(6-7) 普通外设 按键扫描、LED刷新

为什么会这样分?你想想看,系统时钟丢了,整个系统就乱了。按键扫描慢个几十毫秒,用户根本感觉不到。这就是优先级设计的核心思想——把紧急的和不紧急的分开。

注意:优先级不是越高越好。我曾经把一个GPIO中断设成了最高优先级,结果它频繁触发,导致系统时钟中断被阻塞——整个系统时间都乱了。优先级设置要权衡,别让“小事”耽误了“大事”。

1.4 中断嵌套

中断嵌套,说白了就是“中断里还能再进中断”。

处理高优先级中断时,来了个更高优先级的中断——CPU会暂停当前的中断服务程序,先去处理更紧急的那个。处理完再回来继续。

这就像你正在接一个重要电话,突然另一个更重要的电话打进来了——你会说“不好意思,我先接个更急的电话”,然后切换过去。

中断嵌套的规则其实很简单:

  • 高优先级可以打断低优先级——这是允许的
  • 低优先级不能打断高优先级——这是被禁止的
  • 同级中断不能互相打断——得排队

我举个例子:

// 伪代码:中断嵌套场景
主程序正在执行
  ↓
外部中断0(优先级2)触发 → 进入ISR_External0
  ↓
定时器1(优先级1)触发 → 暂停ISR_External0
  ↓
进入ISR_Timer1(优先级更高,先处理)
  ↓
ISR_Timer1执行完毕 → 返回ISR_External0继续
  ↓
ISR_External0执行完毕 → 返回主程序

关键点:中断嵌套虽然灵活,但嵌套层数越多,出问题的概率越大。我个人的经验是——嵌套不要超过3层。超过3层,栈空间容易爆,调试起来也头疼。

嗯,这里要注意一点:有些单片机支持“中断优先级分组”,可以把优先级分成“抢占优先级”和“子优先级”。抢占优先级决定能否打断,子优先级决定同抢占级时的处理顺序。这个细节,不同芯片实现不一样,用的时候一定要看芯片手册。

避坑指南:我曾经在一个项目中,把中断嵌套设了5层。结果系统跑着跑着就死机了。查了半天,发现是栈溢出了。从那以后,我给自己定了个规矩——中断服务程序里尽量少做事,把耗时操作放到主循环或者任务队列里。中断里只做“标记”,不干“重活”。

好了,中断的基础概念就聊到这儿。这些是后面所有内容的地基,一定要理解透。下一节咱们聊聊中断的响应过程,到时候我会结合具体的芯片架构来讲。


可可精品资料库