跳到主要内容

【中断】外部中断

为什么需要中断?

  • 轮询代码:
    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参数一致
    • 中断服务程序执行应该短,不应该把耗时的在里面,避免影响逻辑