1、中断的类型

  • 硬件中断——例如,GPIO 中断(按下按键时)或触摸中断(检测到触摸时)。
  • 软件中断——例如,简单的定时器中断或看门狗定时器中断(当定时器超时时)。

      就用开车这个例子,一句话说清:

  • 硬件中断:你正常行驶时,前车突然急刹车(外部事件),你立刻踩刹车减速。(你无法预测前车何时刹车,必须紧急响应)

  • 件中断:你自己设了个导航提醒(软件指令),提示“前方2公里后转弯”,你按提示变道。
    (何时提醒完全由你提前设定)

      核心区别:硬件中断是被动应对突发状况,软件中断是主动处理计划内事件

2、ESP32中断相关函数

2.1  attachInterrupt函数

   void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)

  • pin:中断触发的中断号
  • intRoutine:中断处理函数
  • mode:中断触发的模式

参数具体说明:

  • pin:中断触发的中断号,调用digitalPinToInterrupt函数,将原始GPIO引脚转号换成中断系统中的对应编号使用,比如digitalPinToInterrupt(23)。将GPIO引脚编号23转换为对应编号。虽然对于ESP32,这个参数可以直接写GPIO引脚编号,因为是ESP32开发板,但其他开发板就不一样了。因此要调用digitalPinToInterrupt函数。
  • intRoutine:中断处理函数,即当触发中断时要执行的函数,中断处理函数必须轻量快速,只做紧急操作(如存数据、清标志),耗时任务交给主循环。否则会阻塞其他中断,严重时触发看门狗导致重启。
  • mode:中断触发的模式,一共有以下几种模式可选

中断触发模式 说明
RISING 上升沿触发
FALLING 下降沿触发
CHANGE 电平变化触发
ONLOW 低电平触发
ONHIGH 高电平触发
2.2  detattachInterrupt函数

void detachInterrupt(uint8_t pin)

  • pin:取消中断程序的中断号,调用digitalPinToInterrupt函数,将原始GPIO引脚转号换成中断系统中的对应编号使用。

3、实战演练

3.1 基本实现

        在ESP32开发板上,有一个板载LED灯,这颗灯是通过2号引脚控制的,给2号引脚高电平时,小灯点亮,给低电平时,小灯熄灭。

      代码:

#include <Arduino.h>

#define LED_PIN 2 // 板载LED灯为2号引脚

void setup()

{

  pinMode(LED_PIN, OUTPUT);

}

void loop()

{

  digitalWrite(LED_PIN, HIGH); //给2号引脚高电平时,小灯点亮。

  delay(1000);

  digitalWrite(LED_PIN, LOW);//给2号引脚低电平时,小灯熄灭。

  delay(1000);

}

3.2 中断分析

      现在增加一个按钮。按钮使用的是23号引脚。当按钮按下时,23号引脚为低电平,按钮未按下时,23号引脚为高电平,使用该开关来控制板载LED灯效果。

      首先分析每单击(按下后释放)按钮一次,即按钮按下并释放这个过程,其OUT引脚的电平方波信号如下图所示:

      根据图片分析得出:

            按下时候为低电平,松开后为高电平,电平从低到高中间过程属于上升沿。
            再次按下为低电平,从上次的高电平到低电平过程属于下降沿。

      因此,我们可以使用中断函数,中断函数中的model模式有上升沿和下降沿。只需要在捕获到波形上升沿的时候,反转一次LED灯的状态即可。

3.3 中断实现步骤

1、定义中断执行函数

     只做23号引脚信号控制,上升沿时候触发中断函数,执行此函让其在电平为低时候,执行亮灯,电平为高时候熄灯。

void reverse_led()

{

  bool voltage_level_flag = digitalRead(LED_PIN);

  Serial.print("电平为:");

  Serial.println(voltage_level_flag);

  digitalWrite(LED_PIN, !voltage_level_flag);

}

2、制定中断函数

     使用中断函数,定义引脚,指定中断执行函数名称,指定中断模式

void setup()

{

  Serial.begin(115200);

  pinMode(LED_PIN, OUTPUT);

  // 三个参数分别为:

  // 1. 中断监听引脚

  // 2. 发生中断后要执行的动作函数

  // 3. 中断触发信号(RISING:上升沿)

  attachInterrupt(digitalPinToInterrupt(PIN), reverse_led, RISING);

}

3.4 按钮抖动问题及消抖

       当我们按按钮时候,会按下灯亮,松开灯灭。但有时候会按下灭,松开亮。LED灯的状态会有多次反转的现象。因为在按按钮的过程中可能会出现多次按下释放过程,即抖动问题。

       这其实是一个非常常见的按钮抖动现象,按钮按下过程中,会可能会发生触点多次接触/断开的情况,这就导致一次按下,出现多个上升沿的现象,继而导致LED灯状态多次反转。

      解决措施:使用消抖

      消抖的逻辑为:在很短时间内(比如500ms)的多次上升沿直接去重忽略即可

void reverse_led()

{

  unsigned long current_time = millis();

  // 只有上一次按下的时间距离当前时间超过500ms,才认为是一次有效的操作

  if (current_time - last_press_time >= 500)

  {

    bool voltage_level_flag = digitalRead(LED_PIN);

    Serial.print("电平为:");

    Serial.println(voltage_level_flag);

    digitalWrite(LED_PIN, !voltage_level_flag);

    last_press_time = current_time;

  }

}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐