|
通常,在一个项目中,您希望ESP8266在不断监视某种事件的同时执行其正常程序。一个广泛采用的解决方案是使用中断。
中断可以分为两种类型。 ● 硬件中断 - 这些是针对外部事件而发生的。例如,GPIO中断(按下键时)。 ● 软件中断 - 这些是根据软件指令而发生的。例如,简单的计时器中断或看门狗计时器中断(计时器超时)。
ESP8266 GPIO中断 当GPIO引脚更改其逻辑电平时,您可以配置ESP8266以生成中断。
ESP8266开发板上的所有GPIO引脚都可以配置为中断输入,除GPIO16外。
将中断连接到GPIO引脚 在Arduino IDE中,我们使用称为artactInterRupt()函数来设置一个GPIO中断。语法看起来像下面。 - attachInterrupt(GPIOPin, ISR, Mode);
复制代码此函数有三个参数: ● GPIOPin - 将GPIO引脚设置为中断引脚,该引脚告诉ESP8266要监测哪个引脚。 ● ISR - 是每次中断时都会调用的函数的名称。 ● Mode - 定义何时应触发中断。
中断服务例程 中断服务例程(ISR)是每次在GPIO引脚上发生中断时都会调用的函数。
它的语法看起来像下面。 - void ICACHE_RAM_ATTR ISR() {
- Statements;
- }
复制代码ESP8266中的ISR是具有一些其他函数没有的独特规则的特殊功能。 ● ISR不能具有任何参数,它们不应返回任何参数。 ● ISR应该尽可能快,快速,因为它们阻止了普通程序执行。 ● 根据ESP8266文档,他们应该具有ICACHE_RAM_ATTR属性。
硬件连接 理论足够了!让我们看看一个实用的例子。
将按钮连接到ESP8266上的GPIO#12(D6)。您将不需要上拉电阻,因为我们将启用内部的上拉。
示例代码:简单中断 以下草图说明了中断的使用以及编写中断服务例程的正确方法。
该程序监测GPIO#12(D6)的下边沿。换句话说,它监测从按下按钮时会发生从逻辑高到逻辑低的电压变化。发生这种情况时,函数ISR被调用。此函数中的代码计算按钮已按下按钮的次数。 - struct Button {
- const uint8_t PIN;
- uint32_t numberKeyPresses;
- bool pressed;
- };
- Button button1 = {D6, 0, false};
- void ICACHE_RAM_ATTR isr() {
- button1.numberKeyPresses++;
- button1.pressed = true;
- }
- void setup() {
- Serial.begin(115200);
- pinMode(button1.PIN, INPUT_PULLUP);
- attachInterrupt(button1.PIN, isr, FALLING);
- }
- void loop() {
- if (button1.pressed) {
- Serial.printf("Button has been pressed %u times\n", button1.numberKeyPresses);
- button1.pressed = false;
- }
- }
复制代码
上传草图后,使用波特率115200打开串口监视器。按下按钮时,您将获得以下输出。
代码说明 在草图的开头,我们创建一个名为Button的结构体。该结构体有三个成员 - 引脚编号、按键钥匙按下的次数和按压状态。仅供参考,一个结构体是单个名称下不同类型(但在逻辑上相关)的变量的集合。 - struct Button {
- const uint8_t PIN;
- uint32_t numberKeyPresses;
- bool pressed;
- };
复制代码然后,我们创建一个Button结构体的实例,并将引脚编号初始化为D6,按键的次数为0,并将默认的按状态按状态为false。 - Button button1 = {D6, 0, false};
复制代码
以下代码是中断服务例程。如前所述,ESP8266中的ISR必须具有ICACHE_RAM_ATTR属性。 在ISR中,我们只需通过1将按键计数器汇总,然后将按钮按状态设置为true。 - void ICACHE_RAM_ATTR isr() {
- button1.numberKeyPresses++;
- button1.pressed = true;
- }
复制代码
在setup()函数中,我们首先将串口通信与PC初始化,然后启用D6 GPIO PIN的内部上拉。 接下来,我们告诉ESP8266监视D6引脚,并在引脚从高到低点(即下降沿)时调用Interrupt服务例程ISR。 - void setup() {
- Serial.begin(115200);
- pinMode(button1.PIN, INPUT_PULLUP);
- attachInterrupt(button1.PIN, isr, FALLING);
- }
复制代码
在loop()函数中,我们只需检查按钮是否已按下,然后打印到到目前为止已按下键的次数,并将按钮按状态设置为false,以便我们可以继续接收中断。 - void loop() {
- if (button1.pressed) {
- Serial.printf("Button has been pressed %u times\n", button1.numberKeyPresses);
- button1.pressed = false;
- }
- }
复制代码
处理开关抖动 中断的一个普遍问题是,它们通常会在同一事件中多次触发。如果您查看上面示例的串口输出,您会注意到,即使仅按下一次按钮,计数器也会增加几次。
要找出发生这种情况的原因,您必须查看信号。如果在按下按钮时监视信号分析器上的引脚的电压,则会收到这样的信号:
您可能会觉得立即进行触发,但实际上,按钮中的机械零件在定居于特定状态之前几次触发。这会导致多个中断。它纯粹是一种被称为开关抖动(switch bounce)的机械现象,就像掉球一样 - 它弹跳了几次,然后最终降落在地面上。
信号稳定的时间非常快,对我们来说几乎是瞬时的,但是对于ESP8266来说,这是一段巨大的时间。它可以在该时间段内执行多个指令。
消除开关抖动的过程称为消抖。有两种方法可以实现这一目标。 ● 通过硬件:通过添加适当的RC过滤器来平滑过渡。 ● 通过软件:通过暂时忽略第一次中断后的短时间内的中断。 |