【ESP32最全学习笔记(基础篇)——8.ESP32 中断定时器】

关于本教程:

ESP32 基础篇                                

1.ESP32简介                                                                

2.ESP32 Arduino 集成开发环境

3.VS 代码和 PlatformIO

4.ESP32 引脚

5.ESP32 输入输出

6.ESP32 脉宽调制

7.ESP32 模拟输入

8.ESP32 中断定时器 ☑

9.ESP32 深度睡眠

ESP32 协议篇

ESP32 网络服务器

ESP32 LoRa

ESP32 BLE

ESP32 BLE 客户端-服务器

ESP32 蓝牙

ESP32 MQTT

ESP32 ESP-NOW

ESP32 Wi-Fi

ESP32 WebSocket

ESP32 ESP-MESH

ESP32 邮箱

ESP32 短信

ESP32 HTTP 获取 POST

HTTP GET Web APIs

HTTP POST Web APIs

 ESP32 服务器篇

持续更新,关注博主不迷路!!!

 ESP32 传感器模块篇

持续更新,关注博主不迷路!!!

ESP32 终极实战篇

百余项ESP32实战项目,敬请关注!!!

带有使用中断和定时器的 PIR 运动传感器的 ESP32

本教程介绍如何使用 PIR 运动传感器通过 ESP32 检测运动。在此示例中,当检测到运动(触发中断)时,ESP32 启动定时器并打开 LED 并持续预定义的秒数。当定时器完成倒计时时,LED 自动关闭。

通过这个例子,我们还将探索两个重要的概念:中断和定时器。

在继续本教程之前,您应该在 Arduino IDE 中安装 ESP32 插件。

所需零件

要学习本教程,您需要以下部分

ESP32 DOIT DEVKIT V1 板
迷你 PIR 运动传感器 (AM312) 或 PIR 运动传感器 (HC-SR501)
5mm LED
330欧姆电阻
跳线
面包板

引入中断

要使用 PIR 运动传感器触发事件​​,您可以使用中断。中断对于使微控制器程序中的事情自动发生很有用,并且可以帮助解决时序问题。

使用中断,您不需要经常检查引脚的当前值。对于中断,当检测到变化时,会触发一个事件(调用一个函数)。

要在 Arduino IDE 中设置中断,您可以使用attachInterrupt()函数,它接受以下参数:GPIO 引脚、要执行的函数的名称和模式:

attachInterrupt(digitalPinToInterrupt(GPIO), function, mode);

GPIO 中断

第一个参数是 GPIO 编号。通常,你应该使用数字引脚中断(GPIO)将实际的 GPIO 设置为中断引脚。例如,如果你想使用GPIO 27作为中断,使用:

digitalPinToInterrupt(27)

对于 ESP32 开发板,下图中所有用红色矩形突出显示的管脚都可以配置为中断管脚。在这个例子中我们将使用GPIO 27作为连接到 PIR 运动传感器的中断。

要触发的函数

的第二个参数attachInterrupt()中function 是每次触发中断时将调用的函数的名称。

模式

                第三个参数是模式。有5种不同的模式:

  • LOW:每当引脚为LOW时触发中断;
  • HIGH:每当引脚为高电平时触发中断;
  • CHANGE:每当引脚值发生变化时触发中断——例如从高电平变为低电平或从低电平变为高电平;
  • FALLING:当引脚从高电平变为低电平时;
  • RISING: 当引脚从低电平变为高电平时触发。

        对于此示例,将使用 RISING 模式,因为当 PIR 运动传感器检测到运动时,它所连接的 GPIO 从低电平变为高电平。

引入定时器

        在这个例子中,我们还将介绍定时器。我们希望 LED 在检测到运动后保持预定的秒数。而不是使用delay()阻止您的代码并且不允许您在确定的秒数内执行任何其他操作的功能,我们应该使用计时器。

延迟()函数

        您应该熟悉delay()功能,因为它被广泛使用。这个函数使用起来非常简单。它接受一个 int 数字作为参数。这个数字表示程序必须等待直到移动到下一行代码的时间(以毫秒为单位)。

delay(time in milliseconds)

当你做delay(1000)您的程序在该行停止 1 秒钟。

delay()是阻塞函数。阻塞函数阻止程序在特定任务完成之前执行任何其他操作。如果您需要同时执行多个任务,则不能使用delay().对于大多数项目,您应该避免使用延迟,而是使用计时器。

millis() 函数

使用一个名为毫秒()您可以返回自程序首次启动以来经过的毫秒数。

millis()

        为什么这个功能有用?因为通过使用一些数学,您可以轻松地验证已经过去了多少时间而不会阻塞您的代码。

用 millis() 闪烁 LED

        下面的代码片段展示了如何使用millis()创建闪烁 LED 项目的函数。它打开 LED 1000 毫秒,然后将其关闭。

// constants won't change. Used here to set a pin number :
const int ledPin =  26;      // the number of the LED pin

// Variables will change :
int ledState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the
  // difference between the current time and last time you blinked
  // the LED is bigger than the interval at which you want to
  // blink the LED.
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

代码如何工作

        让我们仔细看看这个无需delay()功能(它使用millis()代替功能)。

基本上,这段代码减去之前记录的时间(previousMillis) 从当前时间 (currentMillis). 如果余数大于间隔(在本例中为 1000 毫秒),程序将更新previousMillis变量为当前时间,然后打开或关闭 LED。

if (currentMillis - previousMillis >= interval) {
  // save the last time you blinked the LED
  previousMillis = currentMillis;
  (...)

因为这个片段是非阻塞的,任何位于第一个之外的代码如果声明应该可以正常工作。

        您现在应该能够理解您可以将其他任务添加到您的loop()功能,您的代码仍然会每隔一秒闪烁一次 LED。

你可以将这段代码上传到你的ESP32中,组装成如下原理图进行测试,修改毫秒数,看看效果如何。

带 PIR 运动传感器的 ESP32

        理解了这几个概念:中断和定时器,我们继续做项目。

原理图

        我们将构建的电路易于组装,我们将使用带电阻器的 LED。LED连接到GPIO 26. 我们将使用工作电压为 3.3V 的Mini AM312 PIR 运动传感器。它将连接到GPIO 27. 只需按照下一个示意图进行操作即可。

 重要提示:  本项目中使用的Mini AM312 PIR 运动传感器在3.3V 下运行。但是,如果您使用的是另一个 PIR 运动传感器,如 HC-SR501,它的工作电压为 5V。您可以 将其修改为在 3.3V 下运行 ,或者简单地使用 Vin 引脚为其供电。

下图显示了 AM312 PIR 运动传感器引脚排列。

上传代码

按照示意图所示连接电路后,将提供的代码复制到您的 Arduino IDE。

您可以按原样上传代码,也可以修改检测到运动后 LED 点亮的秒数。只需更改时间秒变量与你想要的秒数。

#define timeSeconds 10

// Set GPIOs for LED and PIR Motion Sensor
const int led = 26;
const int motionSensor = 27;

// Timer: Auxiliary variables
unsigned long now = millis();
unsigned long lastTrigger = 0;
boolean startTimer = false;

// Checks if motion was detected, sets LED HIGH and starts a timer
void IRAM_ATTR detectsMovement() {
  Serial.println("MOTION DETECTED!!!");
  digitalWrite(led, HIGH);
  startTimer = true;
  lastTrigger = millis();
}

void setup() {
  // Serial port for debugging purposes
  Serial.begin(115200);
  
  // PIR Motion Sensor mode INPUT_PULLUP
  pinMode(motionSensor, INPUT_PULLUP);
  // Set motionSensor pin as interrupt, assign interrupt function and set RISING mode
  attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);

  // Set LED to LOW
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
}

void loop() {
  // Current time
  now = millis();
  // Turn off the LED after the number of seconds defined in the timeSeconds variable
  if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
    Serial.println("Motion stopped...");
    digitalWrite(led, LOW);
    startTimer = false;
  }
}

让我们看一下代码。首先将两个 GPIO 引脚分配给LED运动传感器变量。

// Set GPIOs for LED and PIR Motion Sensor
const int led = 26;
const int motionSensor = 27;

然后,创建允许您设置定时器以在检测到运动后关闭 LED 的变量。

// Timer: Auxiliar variables
long now = millis();
long lastTrigger = 0;
boolean startTimer = false;

now变量保存当前时间。这lastTrigger变量保存 PIR 传感器检测到运动的时间。这startTimer是一个布尔变量,它在检测到运动时启动计时器。

setup()

在里面setup(), 首先以 115200 波特率初始化串口。

Serial.begin(115200);

将 PIR 运动传感器设置为输入上拉。

pinMode(motionSensor, INPUT_PULLUP);

要将 PIR 传感器引脚设置为中断,请使用attachInterrupt()功能如前所述。

attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);

        将检测运动的引脚是GPIO 27它会调用函数检测运动()在上升模式。LED 是一个 OUTPUT,其状态从 LOW 开始。

pinMode(led, OUTPUT);
digitalWrite(led, LOW);

loop()

loop()功能不断地一遍又一遍地运行。在每个循环中,now变量用当前时间更新。

now = millis();

没有做任何其他事情loop().

        但是,当检测到运动时,detctsMovement()函数被调用是因为我们之前已经在setup().

detctsMovement()函数在串行监视器中打印一条消息,打开 LED,设置startTimer布尔变量到真的并更新lastTrigger随当前时间变化。

void IRAM_ATTR detectsMovement() {
  Serial.println("MOTION DETECTED!!!");
  digitalWrite(led, HIGH);
  startTimer = true;
  lastTrigger = millis();
}

笔记: IRAM_ATTR用于在 RAM 中运行中断代码,否则代码存储在闪存中并且速度较慢。

在这一步之后,代码返回到loop().

        这一次,startTimer变量为真。因此,当以秒为单位定义的时间过去后(自检测到运动以来),以下if声明将是真实的。

if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
  Serial.println("Motion stopped...");
  digitalWrite(led, LOW);
  startTimer = false;
}

“Motion stopped...”消息将打印在串行监视器中,LED 熄灭,startTimer 变量设置为 false。

示范

        将代码上传到您的 ESP32 开发板。确保选择了正确的板和 COM 端口。

以 115200 的波特率打开串行监视器。

将您的手移到 PIR 传感器前面。LED 应该亮起,串行监视器中会打印一条消息,提示“检测到运动!!!”。10 秒后 LED 应该熄灭。

 总结

        总而言之,中断用于检测 GPIO 状态的变化,而无需不断读取当前 GPIO 值。对于中断,当检测到变化时,将触发一个函数。您还学习了如何设置一个简单的计时器,它允许您检查是否已经过了预定义的秒数,而不必阻塞您的代码。

猜你喜欢

转载自blog.csdn.net/m0_46509684/article/details/129112789