Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE

El manejo de interrupciones en GPIO (General Purpose Input/Output) es esencial para optimizar el rendimiento y la eficiencia en proyectos de desarrollo con microcontroladores como el ESP8266. En este artículo aprenderás cómo configurar y manejar interrupciones GPIO en tu ESP8266 utilizando el entorno de desarrollo Arduino IDE. ¡Sigue leyendo para descubrir cómo sacarle el máximo provecho a tu dispositivo!

En un proyecto, a menudo desea que el ESP8266 ejecute su programa normal mientras monitorea continuamente un evento. Una solución común a esto es utilizar interrumpe.

Las interrupciones se pueden dividir en dos tipos.

Interrupciones de hardware – Se producen en respuesta a un evento externo. Por ejemplo, una interrupción GPIO (cuando se presiona una tecla).

Interrupciones de software – Estos ocurren en respuesta a una instrucción del software. Por ejemplo, una simple interrupción del temporizador o una interrupción del temporizador de vigilancia (cuando el temporizador expira).

ESP8266 interrupción GPIO

Puede configurar el ESP8266 para generar una interrupción cuando un pin GPIO cambia su nivel lógico.

Todos los pines GPIO en una placa ESP8266 se pueden configurar para actuar como entradas de solicitud de interrupción, excepto GPIO16.

Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE

Adjuntar una interrupción a un pin GPIO

En el IDE de Arduino usamos una función llamada adjuntoInterrupt() para configurar una interrupción pin por pin. La sintaxis se ve así.

attachInterrupt(GPIOPin, ISR, Mode);

Esta función acepta tres argumentos:

GPIOPin – Establece el pin GPIO como un pin de interrupción, lo que le indica al ESP8266 qué pin monitorear.

ISRes el nombre de la función que se llamará cada vez que ocurra la interrupción.

modo – define cuándo se debe activar la interrupción. Cinco constantes están predefinidas como valores válidos:

BAJO Activa la interrupción cuando el pin está BAJO
ALTO Activa la interrupción cuando el pin está ALTO
CAMBIAR Activa la interrupción cuando el pin cambia de valor, de ALTO a BAJO o de BAJO a ALTO
CAER Activa la interrupción cuando el pin cambia de ALTO a BAJO
CRECIENTE Activa la interrupción cuando el pin cambia de BAJO a ALTO

Interrumpir la rutina del servicio.

La Rutina de Servicio de Interrupción (ISR) es una función que se llama cada vez que ocurre una interrupción en el pin GPIO.

La sintaxis se ve así.

void ICACHE_RAM_ATTR ISR() {
    Statements;
}

Los ISR en ESP8266 son tipos especiales de funciones que tienen algunas reglas únicas que la mayoría de las otras funciones no tienen.

  • Un ISR no puede tener ningún parámetro y no debería devolver nada.
  • Los ISR deben ser lo más cortos y rápidos posible porque bloquean la ejecución normal del programa.
  • Deberían tener el atributo ICACHE_RAM_ATTR según la documentación ESP8266.

¿Qué es ICACHE_RAM_ATTR?

Cuando marcamos una sección de código con el atributo ICACHE_RAM_ATTR, el código compilado se coloca en la RAM interna (IRAM) del ESP8266. De lo contrario, el código se mantiene en Flash. Y el flash en ESP8266 es mucho más lento que la RAM interna.

Si el código que queremos ejecutar es una Rutina de Servicio de Interrupción (ISR), generalmente queremos ejecutarlo lo más rápido posible. Si tuviéramos que “esperar” a que el ISR se cargue desde Flash, las cosas podrían salir terriblemente mal.

Conexión de hardware

¡Basta de teoría! Veamos un ejemplo práctico.

Conectemos un pulsador al GPIO#12 (D6) en el ESP8266. No necesita un pullup para este pin porque estamos habilitando el pullup interno.

Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE

Código de ejemplo: interrupción simple

El siguiente esquema muestra el uso de interrupciones y la forma correcta de escribir una rutina de servicio de interrupción.

Este programa monitorea GPIO#12 (D6) para detectar el flanco DE CAÍDA. En otras palabras: busca un cambio de voltaje que va de ALTO lógico a BAJO lógico cuando se presiona el botón. Cuando esto sucede, la función isr se llama. El código en esta función cuenta cuántas veces se presionó el botón.

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 timesn", button1.numberKeyPresses);
      button1.pressed = false;
  }
}

Una vez que cargue el boceto, abra el monitor serie con velocidad de baudios 115200. Cuando presione el botón obtendrá el siguiente resultado.

Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE

Explicación del código

Al comienzo del boceto creamos una estructura llamada Button. Esta estructura consta de tres elementos: el número de pin, el número de pulsaciones de teclas y el estado de pulsación. Para su información: una estructura es una colección de variables de diferentes tipos (pero lógicamente relacionadas entre sí) bajo un solo nombre.

struct Button {
  const uint8_t PIN;
  uint32_t numberKeyPresses;
  bool pressed;
};

Luego creamos una instancia de ello. Button Estructurar e inicializar el número pin D6el número de pulsaciones de teclas hasta 0 y el estado presionado predeterminado false.

Button button1 = {D6, 0, false};

El siguiente código es una rutina de servicio de interrupción. Como ya se mencionó, el ISR en el ESP8266 debe tener esto ICACHE_RAM_ATTR Atributo.

En el ISR simplemente incrementamos el contador de KeyPresses en 1 y configuramos el estado de la tecla presionada en Verdadero.

void ICACHE_RAM_ATTR isr() {
  button1.numberKeyPresses++;
  button1.pressed = true;
}

En la sección de configuración del código, primero inicializamos la comunicación serial con la PC y luego habilitamos el pullup interno para el pin GPIO D6.

A continuación, le indicamos al ESP8266 que monitoree el pin D6 y llame a la rutina de servicio de interrupción. isr cuando el pasador va de ALTO a BAJO, es decir, borde DE CAÍDA.

void setup() {
  Serial.begin(115200);
  pinMode(button1.PIN, INPUT_PULLUP);
  attachInterrupt(button1.PIN, isr, FALLING);
}

En la parte del bucle del código, simplemente verificamos si se presionó la tecla, luego imprimimos cuántas veces se ha presionado la tecla hasta el momento y configuramos el estado de la tecla presionada en falso para que podamos continuar recibiendo interrupciones.

void loop() {
  if (button1.pressed) {
      Serial.printf("Button has been pressed %u timesn", button1.numberKeyPresses);
      button1.pressed = false;
  }
}

Administrar el rebote del interruptor

Un problema común con las interrupciones es que a menudo se activan varias veces para el mismo evento. Si observa la salida en serie del ejemplo anterior, notará que incluso si presiona el botón solo una vez, el contador aumentará varias veces.

Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE

Para saber por qué sucede esto, hay que fijarse en la señal. Si monitorea el voltaje del pin en el analizador de señal mientras presiona el botón, obtendrá una señal como esta:

Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE

Es posible que sienta que el contacto se realiza de inmediato, pero en realidad las piezas mecánicas dentro del botón entran en contacto varias veces antes de estabilizarse en un estado determinado. Esto da como resultado múltiples interrupciones.

Es un fenómeno puramente mecánico llamado interruptor de saltoEs como dejar caer una pelota: rebota hacia arriba y hacia abajo varias veces antes de aterrizar finalmente en el suelo.

El tiempo para que la señal se estabilice es muy rápido y nos parece casi instantáneo, pero para un ESP8266 es una cantidad de tiempo enorme. Puede ejecutar múltiples instrucciones durante este período.

El proceso de eliminar el rebote del interruptor se llama rebote. Hay dos formas de lograrlo.

  • Por hardware: añadiendo un filtro RC adecuado para suavizar la transición.
  • Por software: ignorando temporalmente más interrupciones durante un corto período de tiempo después de que se activa la primera interrupción.

Código de ejemplo: Rebotar una interrupción

Aquí se reescribe el boceto anterior para demostrar cómo evitar una interrupción mediante programación. En este boceto, permitimos que el ISR se ejecute solo una vez por cada pulsación de tecla, en lugar de ejecutarlo varias veces.

Los cambios en el boceto se resaltan en Verde.

struct Button {
    const uint8_t PIN;
    uint32_t numberKeyPresses;
    bool pressed;
};

Button button1 = {D6, 0, false};

//variables to keep track of the timing of recent interrupts
unsigned long button_time = 0;  
unsigned long last_button_time = 0; 

void ICACHE_RAM_ATTR isr() {
    button_time = millis();
if (button_time - last_button_time > 250)
{
        button1.numberKeyPresses++;
        button1.pressed = true;
       last_button_time = button_time;
}
}

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 timesn", button1.numberKeyPresses);
        button1.pressed = false;
    }
}

Echemos otro vistazo a la salida en serie mientras presionamos la tecla. Tenga en cuenta que el ISR solo se invoca una vez por cada pulsación de tecla.

Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE

Explicación del código:

Esta solución funciona porque cada vez que se ejecuta el ISR, se compara la hora actual devuelta por millis() La función vuelve a la hora de la última llamada al ISR.

Si está dentro de los 250 ms, ESP8266 ignora la interrupción e inmediatamente vuelve a lo que estaba haciendo. De lo contrario, se ejecutará el código que contiene. if Declaración que incrementa y actualiza el contador. last_button_time Variable para que la función tenga un nuevo valor con el que comparar cuando se active en el futuro.


Error 403 The request cannot be completed because you have exceeded your quota. : quotaExceeded






Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE

Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE

En muchos proyectos, es común que desees que el ESP8266 realice su programa normal mientras monitorea continuamente algún tipo de evento. Una solución ampliamente adoptada para esto es el uso de interrupciones.

Tipos de Interrupciones

Las interrupciones se pueden clasificar en dos tipos:

  1. Interrupciones de Hardware: Ocurren en respuesta a un evento externo, como una interrupción GPIO (cuando se presiona una tecla).
  2. Interrupciones de Software: Ocurren en respuesta a una instrucción de software, como una interrupción de temporizador simple o una interrupción de temporizador de supervisión (cuando el temporizador expira).

Interrupción GPIO ESP8266

Puedes configurar el ESP8266 para generar una interrupción cuando un pin GPIO cambia su nivel lógico. Todos los pines GPIO en una placa ESP8266 se pueden configurar como entradas de solicitud de interrupción, excepto GPIO16.

Adjuntar una Interrupción a un Pin GPIO

En el IDE de Arduino, utilizamos una función llamada attachInterrupt() para establecer una interrupción en función de un pin. La sintaxis se ve así:

attachInterrupt(GPIOPin, ISR, Modo);

Esta función acepta tres argumentos:

  • GPIOPin: establece el pin GPIO como el pin de interrupción.
  • ISR: es el nombre de la función que se llamará cada vez que ocurra la interrupción.
  • Modo: define cuándo debe activarse la interrupción.

Rutina de Servicio de Interrupción

La Rutina de Servicio de Interrupción (ISR) es una función que se invoca cada vez que ocurre una interrupción en el pin GPIO. Las ISRs en ESP8266 tienen reglas únicas que la mayoría de las otras funciones no tienen.

Es importante destacar el atributo ICACHE_RAM_ATTR, según la documentación de ESP8266, que se utiliza para colocar el código compilado en la RAM interna de ESP8266 en lugar de en la Flash, lo que lo hace mucho más rápido.

Gestión del Rebote del Interruptor

Uno de los problemas comunes con las interrupciones es que a menudo se activan varias veces para el mismo evento debido al rebote del interruptor. Para evitar esto, se puede lograr mediante hardware (agregando un filtro RC adecuado) o mediante software (ignorando temporalmente más interrupciones después de la primera).

Ejemplo de Código: Debounce de una Interrupción

A continuación se muestra un ejemplo de cómo eliminar el rebote de un botón en una interrupción de manera programática.

El código se modifica para permitir que la ISR se ejecute solo una vez en cada presión de botón, en lugar de ejecutarse múltiples veces.


5 comentarios en «Configuración y manejo de interrupciones GPIO ESP8266 en Arduino IDE»

  1. ¡Este artículo es justo lo que necesitaba para aprender a manejar las interrupciones GPIO en mi ESP8266! Gracias por la explicación clara y concisa. ¡Seguro que ahora podré configurarlas sin dificultad! 🙌🏼👍🏼

Deja un comentario