【中断】外部中断
为什么需要中断?
- 轮询代码:
while (1) {
// 轮询方式:不断检查设备状态
if (key_pressed()) {
// 处理按键事件
handle_key_press();
}
}
- 轮询的缺点:
-
CPU 需要不断检查设备状态(如按键是否按下),占用大量计算资源。
-
高延迟:事件发生后无法立即响应(需等待轮询检测到)。
-
中断
-
基于轮询的问题,单片机引入了中断功能。
-
中断(Interrupt) 是嵌入式系统的核心机制,允许处理器暂停当前任务,优先响应外部事件(如按键按下、定时器溢出),处理完成后自动恢复原任务。
提示
想象这样的场景:你在看书,收到微信消息,这时:
- 轮询:每隔5秒,看一次手机(低效)
- 中断:手机响了(触发中断),你回复消息(处理中断),处理完消息后继续看书(恢复现场)。
中断的优势
- 设备主动通知CPU(如按下按键触发中断),CPU 立即处理。
中断流程
-
1.中断触发:硬件(如定时器、GPIO)发送中断信号。
-
2.保存现场:CPU 压栈当前执行的上下文(PC、寄存器等)。
-
3.跳转到中断服务程序(ISR):执行预设的处理函数。
-
4.恢复现场:弹出栈数据,继续原任务。

中断类型
- 外部中断:外部硬件信号 触发的,通常是 GPIO 引脚的电平变化(如按键按下)。
- 触发方式:
- 边沿触发(上升沿、下降沿、双边沿)
- 电平触发(高电平、低电平)
- 触发方式:
- 定时器中断:定时器中断是由 MCU 内部定时器(TIM)溢出 触发的,其核心用途是 计时、延时、周期任务调度(如定时测量、PWM 生成、任务调度)。
- 触发方式:
- 固定频率(周期性)(如每 1ms 触发一次)
- 单次触发(仅执行一次)
- 触发方式:
- 其他中断类型
中断优先级
-
中断优先级:高优先级中断可以打断低优先级中断,确保关键任务及时响应。
-
中断嵌套:同一优先级的中断可以嵌套执行,确保顺序执行。

中断实验
下降沿中断实验
-
原理:下降沿触发中断,当 GPIO 输入电平从高到低变化时(按键按下),产生中断。
-
关键函数:
-
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)-
pin:中断引脚 -
intRoutine:中断服务程序(ISR)- 中断服务程序是一个函数,定义传入即可
- 中断服务程序的参数和返回值必须为void,不能有参数
- 中断服务程序可以自定义,但必须与 attachInterrupt 函数的 intRoutine 参数类型一致
-
-
mode:中断触发方式(上升沿、下降沿、双边沿、电平触发)- mode已经提前定义 可以打开 Arduino.h 文件查看
-
信息
#define RISING 0x01 // 上升沿触发(低电平->高电平)
#define FALLING 0x02 // 下降沿触发(高电平->低电平)
#define CHANGE 0x03 // 双边沿触发(上升沿或下降沿)
#define ONLOW 0x04 // 低电平触发(持续低电平不断触发)
#define ONHIGH 0x05 // 高电平触发(持续高电平不断触发)
- 代码
#include <Arduino.h>
#define pin 0
// 定义可以在外部中断函数中使用的变量
volatile bool flag = false;
// 定义外部中断函数
void ISR()
{
flag = true;
}
void setup()
{
Serial.begin(9600);
pinMode(pin, INPUT_PULLDOWN);
/**
*
* @param pin 中断引脚 0号引脚
* @param ISR 中断函数 ISR:中断服务函数
* @param FALLING 中断类型 FALLING:下降沿触发中断
*/
attachInterrupt(pin, ISR, FALLING);
}
void loop()
{
if (flag)
{
Serial.println("外部中断触发,按键按下");
flag = false;
}
}
- 注意点:
- 中断标志位,变量需要volatile修饰,防止编译器优化
- 中断服务程序(ISR)的函数名和参数必须与attachInterrupt函数中intRoutine参数一致
- 中断服务程序执行应该短,不应该把耗时的在里面,避免影响逻辑