风筝
发表于: 2022-11-3 19:32:32 | 显示全部楼层

通常,在一个项目中,您希望ESP8266在不断监视某种事件的同时执行其正常程序。一个广泛采用的解决方案是使用中断。


中断可以分为两种类型。

●    硬件中断 - 这些是针对外部事件而发生的。例如,GPIO中断(按下键时)。

●    软件中断 - 这些是根据软件指令而发生的。例如,简单的计时器中断或看门狗计时器中断(计时器超时)。


ESP8266 GPIO中断

当GPIO引脚更改其逻辑电平时,您可以配置ESP8266以生成中断。


ESP8266开发板上的所有GPIO引脚都可以配置为中断输入,除GPIO16外。

ESP8266-Interrupt-Pins.jpg


将中断连接到GPIO引脚

在Arduino IDE中,我们使用称为artactInterRupt()函数来设置一个GPIO中断。语法看起来像下面。

  1. attachInterrupt(GPIOPin, ISR, Mode);
复制代码

此函数有三个参数:

●    GPIOPin - 将GPIO引脚设置为中断引脚,该引脚告诉ESP8266要监测哪个引脚。

●    ISR  - 是每次中断时都会调用的函数的名称。

●    Mode - 定义何时应触发中断。


中断服务例程

中断服务例程(ISR)是每次在GPIO引脚上发生中断时都会调用的函数。


它的语法看起来像下面。

  1. void ICACHE_RAM_ATTR ISR() {
  2.     Statements;
  3. }
复制代码

ESP8266中的ISR是具有一些其他函数没有的独特规则的特殊功能。

●    ISR不能具有任何参数,它们不应返回任何参数。

●    ISR应该尽可能快,快速,因为它们阻止了普通程序执行。

●    根据ESP8266文档,他们应该具有ICACHE_RAM_ATTR属性。


硬件连接

理论足够了!让我们看看一个实用的例子。


将按钮连接到ESP8266上的GPIO#12(D6)。您将不需要上拉电阻,因为我们将启用内部的上拉。

Wiring-Push-Buttons-to-ESP8266-For-GPIO-Interrupt.jpg


示例代码:简单中断

以下草图说明了中断的使用以及编写中断服务例程的正确方法。


该程序监测GPIO#12(D6)的下边沿。换句话说,它监测从按下按钮时会发生从逻辑高到逻辑低的电压变化。发生这种情况时,函数ISR被调用。此函数中的代码计算按钮已按下按钮的次数。

  1. struct Button {
  2.   const uint8_t PIN;
  3.   uint32_t numberKeyPresses;
  4.   bool pressed;
  5. };

  6. Button button1 = {D6, 0, false};

  7. void ICACHE_RAM_ATTR isr() {
  8.   button1.numberKeyPresses++;
  9.   button1.pressed = true;
  10. }

  11. void setup() {
  12.   Serial.begin(115200);
  13.   pinMode(button1.PIN, INPUT_PULLUP);
  14.   attachInterrupt(button1.PIN, isr, FALLING);
  15. }

  16. void loop() {
  17.   if (button1.pressed) {
  18.       Serial.printf("Button has been pressed %u times\n", button1.numberKeyPresses);
  19.       button1.pressed = false;
  20.   }
  21. }
复制代码

上传草图后,使用波特率115200打开串口监视器。按下按钮时,您将获得以下输出。

ESP8266-GPIO-Interrupt-Output-On-Serial-Monitor.jpg


代码说明

在草图的开头,我们创建一个名为Button的结构体。该结构体有三个成员 - 引脚编号、按键钥匙按下的次数和按压状态。仅供参考,一个结构体是单个名称下不同类型(但在逻辑上相关)的变量的集合。

  1. struct Button {
  2.   const uint8_t PIN;
  3.   uint32_t numberKeyPresses;
  4.   bool pressed;
  5. };
复制代码

然后,我们创建一个Button结构体的实例,并将引脚编号初始化为D6,按键的次数为0,并将默认的按状态按状态为false。

  1. Button button1 = {D6, 0, false};
复制代码

以下代码是中断服务例程。如前所述,ESP8266中的ISR必须具有ICACHE_RAM_ATTR属性。

在ISR中,我们只需通过1将按键计数器汇总,然后将按钮按状态设置为true。

  1. void ICACHE_RAM_ATTR isr() {
  2.   button1.numberKeyPresses++;
  3.   button1.pressed = true;
  4. }
复制代码

setup()函数中,我们首先将串口通信与PC初始化,然后启用D6 GPIO PIN的内部上拉。

接下来,我们告诉ESP8266监视D6引脚,并在引脚从高到低点(即下降沿)时调用Interrupt服务例程ISR。

  1. void setup() {
  2.   Serial.begin(115200);
  3.   pinMode(button1.PIN, INPUT_PULLUP);
  4.   attachInterrupt(button1.PIN, isr, FALLING);
  5. }
复制代码

在loop()函数中,我们只需检查按钮是否已按下,然后打印到到目前为止已按下键的次数,并将按钮按状态设置为false,以便我们可以继续接收中断。

  1. void loop() {
  2.   if (button1.pressed) {
  3.       Serial.printf("Button has been pressed %u times\n", button1.numberKeyPresses);
  4.       button1.pressed = false;
  5.   }
  6. }
复制代码

处理开关抖动

中断的一个普遍问题是,它们通常会在同一事件中多次触发。如果您查看上面示例的串口输出,您会注意到,即使仅按下一次按钮,计数器也会增加几次。

ESP8266-GPIO-Interrupt-Bounce-Problem.gif


要找出发生这种情况的原因,您必须查看信号。如果在按下按钮时监视信号分析器上的引脚的电压,则会收到这样的信号:

Switch-Bounce-Signal.jpg


您可能会觉得立即进行触发,但实际上,按钮中的机械零件在定居于特定状态之前几次触发。这会导致多个中断。它纯粹是一种被称为开关抖动(switch bounce)的机械现象,就像掉球一样 - 它弹跳了几次,然后最终降落在地面上。


信号稳定的时间非常快,对我们来说几乎是瞬时的,但是对于ESP8266来说,这是一段巨大的时间。它可以在该时间段内执行多个指令。


消除开关抖动的过程称为消抖。有两种方法可以实现这一目标。

●   通过硬件:通过添加适当的RC过滤器来平滑过渡。

●   通过软件:通过暂时忽略第一次中断后的短时间内的中断。

跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 54 | 回复: 107



手机版|

GMT+8, 2024-3-29 23:54 , Processed in 0.102305 second(s), 6 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表