Configuraci贸n y manejo de las interrupciones del ESP32 GPIO en el IDE de Arduino

Interrupciones en el ESP32

A menudo en un proyecto necesitas el ESP32 para ejecutar tu programa normal, mientras que continuamente necesitas que se monitorize para alg煤n tipo de evento. Una soluci贸n ampliamente adoptada es el uso de una interrupci贸n.

El ESP32 ofrece hasta 32 ranuras de interrupci贸n para cada n煤cleo. Cada interrupci贸n tiene un cierto nivel de prioridad y se puede clasificar en dos tipos.

  • Interrupciones de hardware – Estas ocurren en respuesta a un evento externo. Por ejemplo, una interrupci贸n de GPIO (cuando se pulsa una tecla) o una interrupci贸n de toque o pulsaci贸n (cuando se detecta el pulsar)
  • Interrupciones de software – Estas ocurren en respuesta a una instrucci贸n de software. Por ejemplo, una simple interrupci贸n de temporizador o una interrupci贸n de temporizador de vigilancia (cuando el temporizador se agota)

Interrupci贸n en el ESP32 GPIO

En el ESP32, podemos definir una funci贸n de rutina de servicio de interrupci贸n que se llamar谩 cuando un pin GPIO cambie el valor de su se帽al.

Con una placa ESP32, todos los pines GPIO pueden ser configurados para funcionar como entradas de solicitud de interrupci贸n.

Adjuntar la interrupci贸n a un PIN GPIO

En el IDE de Arduino, usamos una funci贸n llamada attachInterrupt() para establecer una interrupci贸n en base a un pin por pin. La sintaxis recomendada es la siguiente.

attachInterrupt(GPIOPin, ISR, Mode);

Esta funci贸n toma tres par谩metros:

  • GPIOPin: Establece la clavija GPIO como una clavija de interrupci贸n, que le dice al ESP32 qu茅 clavija debe monitorear.
  • ISR: Es el nombre de la funci贸n que se llamar谩 cada vez que se dispare la interrupci贸n.
  • Mode: Define cu谩ndo se debe disparar la interrupci贸n. Cinco constantes est谩n predefinidas como valores v谩lidos:
LOW Los disparadores interrumpen cuando el pin est谩 LOW
HIGH Los disparadores interrumpen cuando el pin es HIGH
CHANGE Los disparadores interrumpen cuando el pin cambia de valor, de HIGH a LOW o LOW a HIGH
FALLING Los disparadores interrumpen cuando el pin va de HIGH a LOW
RISING Los disparadores interrumpen cuando el pin va de LOW a HIGH

Desconectar la interrupci贸n de un pin GPIO

Opcionalmente, puedes llamar a la funci贸n de separaci贸n de interrupciones cuando ya no quieras que el ESP32 monitorice un pin. La sintaxis a utilizar es la siguiente.

detachInterrupt(GPIOPin);

Rutina de interrupci贸n del servicio

La Rutina de Servicio de Interrupci贸n se invoca cuando se produce una interrupci贸n en cualquier pin GPIO. Su sintaxis es como la siguiente.

void IRAM_ATTR ISR() {
    Statements;
}

Las ISR en ESP32 son tipos especiales de funciones que tienen algunas reglas 煤nicas que la mayor铆a de las otras funciones no tienen.

  • La rutina de servicio de interrupci贸n debe tener un tiempo de ejecuci贸n lo m谩s corto posible, porque bloquea la ejecuci贸n normal del programa.
  • Las rutinas de servicio de interrupci贸n deben tener el atributo IRAM_ATTR, seg煤n la documentaci贸n de ESP32

驴Qu茅 es IRAM_ATTR?

Al marcar un trozo de c贸digo con el atributo IRAM_ATTR estamos declarando que el c贸digo compilado se colocar谩 en la RAM interna (IRAM) del ESP32.

De lo contrario, el c贸digo se coloca en la memoria Flash. Y el flash en el ESP32 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 ejecutarla lo m谩s r谩pido posible. Si tuvi茅ramos que 芦esperar禄 a que una ISR se cargue desde el flash, las cosas ir铆an terriblemente mal.

Conexi贸n de hardware

Veamos un ejemplo pr谩ctico.

Enganchemos un pulsador al pin GPIO 18 (D18) del ESP32. No es necesario tirar de esta clavija porque tiraremos de la clavija internamente.

conexion botones ESP32-para interrupci贸n GPIO
Ejemplo: Interrupci贸n simple

El siguiente c贸digo demuestra el uso de las interrupciones y la forma correcta de escribir una rutina de servicio de interrupciones.

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

Button button1 = {18, 0, false};

void IRAM_ATTR isr() {
  button1.numberKeyPresses += 1;
  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 1 has been pressed %u times\n", button1.numberKeyPresses);
      button1.pressed = false;
  }

  //Detach Interrupt after 1 Minute
  static uint32_t lastMillis = 0;
  if (millis() - lastMillis > 60000) {
    lastMillis = millis();
    detachInterrupt(button1.PIN);
     Serial.println("Interrupt Detached!");
  }
}

Una vez que subas el c贸digo, presiona el bot贸n EN en el ESP32 y abre el monitor serial a una velocidad de 115200 baudios. Ahora obtendremos la salida como se muestra a continuaci贸n, cuando presiones el bot贸n.

interrupciones ESP32 GPIO Pins

Explicaci贸n del c贸digo

Al principio del c贸digo creamos una estructura llamada Bot贸n. Tiene tres miembros, a saber, n煤mero de pin, n煤mero de pulsaciones de teclas y estado de pulsaci贸n. Si no lo sabes, la estructura es el conjunto de variables de diferentes tipos (pero l贸gicamente relacionadas entre s铆) bajo un 煤nico nombre.

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

A continuaci贸n creamos una instancia de la estructura de los botones e inicializamos el n煤mero de pin a 18, el n煤mero de pulsaciones de teclas a 0 y el estado de pulsaci贸n por defecto a false.

Button button1 = {18, 0, false};

La siguiente pieza de c贸digo es una Rutina de Servicio de Interrupci贸n. Como se mencion贸 anteriormente, ISR en ESP32 debe tener el atributo IRAM_ATTR.

En ISR simplemente incrementamos el contador de KeyPresses en 1 y ponemos el estado de bot贸n pulsado en True.

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

En la secci贸n de configuraci贸n del c贸digo, primero inicializamos la comunicaci贸n en serie con el PC. Luego configuramos la entrada para subir la clavija D18.

Luego le decimos al ESP32 que monitoree el pin D18 y llamamos a la rutina de servicio de interrupci贸n isr cuando el pin va de HIGH a LOW, es decir, estado FALLING.

Serial.begin(115200);
pinMode(button1.PIN, INPUT_PULLUP);
attachInterrupt(button1.PIN, isr, FALLING);

En la secci贸n de bucle del c贸digo, simplemente comprobamos si el estado del bot贸n pulsado vuelve a ser verdadero (true). Cuando lo hace, simplemente imprimimos el n煤mero de tecla pulsada hasta ahora y ponemos el estado de bot贸n pulsado LOW para que podamos seguir recibiendo las siguientes interrupciones.

if (button1.pressed) {
      Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses);
      button1.pressed = false;
}

En la secci贸n de bucle tambi茅n comprobamos el n煤mero de milisegundos que han pasado desde que el programa empez贸 a usar la funci贸n millis(). Cuando este tiempo es superior a 60.000 milisegundos o 1 minuto, simplemente le decimos a ESP32 que no monitorice la clavija D18 usando la funci贸n de detachInterrupt().

//Detach Interrupt after 1 Minute
static uint32_t lastMillis = 0;
if (millis() - lastMillis > 60000) {
  lastMillis = millis();
  detachInterrupt(button1.PIN);
  Serial.println("Interrupt Detached!");
}

 

Pin It on Pinterest

Shares