esp32-interrupciones-hardware

Cómo usar interrupciones en un ESP32

Las interrupciones de hardware, o interrupciones de GPIO permiten que el microcontrolador detecte y responda a cambios específicos en los pines de entrada, incluso mientras se está ejecutando el programa principal.

Cuando ocurre un evento que genera una interrupción, el programa principal se detiene momentáneamente y se ejecuta la función de Callback. Una vez completada la función de Callback, el programa principal continúa su ejecución.

Esto es especialmente útil en situaciones en las que necesitamos manejar eventos muy rápido, que podríamos no detectar. O, evitar revisar constantemente el estado de un sensor, por ejemplo.

Sin embargo, tampoco debemos abusar de ellos. Tener en cuenta, que durante el tiempo que esté atendiendo la interrupción, el procesador está ignorando todo lo demás. Así que usarlas con cabeza, y siempre que la ISR sea lo más corta posible.

Uso las interrupciones de GPIO en el ESP32

Usar las interrupciones de GPIO en el ESP32 con el IDE de Arduino es muy similar al de uso con un Arduino “convencional”, pero tiene alguna peculiaridad.

Definir la función de callback (ISR)

En primer lugar, definimos la función de callback, que se ejecutará cuando ocurra la interrupción en el pin GPIO. Esta función debe tener un tipo de dato void y no debe tomar ningún argumento.

void IRAM_ATTR miFuncionInterrupcion() {
  // Aquí puedes agregar el código que se ejecutará cuando ocurra la interrupción
}

Aquí viene una de las diferencias importantes, hemos etiquetado la ISR con el atributo IRAM_ATTR. Esto indique al compilador que ubique el código de la función en la RAM interna del ESP32.

Sin este atributo, la función iría a la Flash, que es mucho más lenta. Como hemos dicho, queremos que la ISR sea lo más corta y rápida posible. Por lo que debemos añadir el

Configurar la interrupción

Una vez que hemos definido la función de callback, configuramos la interrupción en el pin GPIO deseado mediante la función attachInterrupt().

Esta función acepta tres argumentos: el número del pin GPIO, la función de callback y el modo de interrupción.

El modo de interrupción determina cuándo se activará la interrupción. Los modos posibles son:

  • RISING: La interrupción se activa cuando el pin cambia de bajo a alto (flanco de subida).
  • FALLING: La interrupción se activa cuando el pin cambia de alto a bajo (flanco de bajada).
  • CHANGE: La interrupción se activa tanto en flanco de subida como de bajada.

Por ejemplo, para configurar una interrupción en el pin 12 que se activa en flanco de subida:

const int pinInterrupcion = 12; // Pin GPIO donde configurar la interrupción

void setup() {
  pinMode(pinInterrupcion, INPUT_PULLUP); // Configurar el pin como entrada con resistencia pull-up interna
  attachInterrupt(digitalPinToInterrupt(pinInterrupcion), miFuncionInterrupcion, RISING); // Configurar la interrupción
}

Desactivar la interrupción (opcional)

Si en algún momento deseas desactivar la interrupción, puedes utilizar la función detachInterrupt(). Esta función toma como argumento el número del pin GPIO donde se configuró la interrupción.

detachInterrupt(digitalPinToInterrupt(pinInterrupcion)); // Desactivar la interrupción

Ejemplo de código

A continuación, te mostramos un ejemplo completo de cómo utilizar una interrupción en un botón conectado al pin 12 del ESP32:

const int pinBoton = 12; // Pin GPIO donde está conectado el botón

volatile bool has_interruped = false;
void IRAM_ATTR miFuncionInterrupcion() {
  has_interrupted = true;
}

void setup() 
{
  Serial.begin(115200);
  pinMode(pinBoton, INPUT_PULLUP); // Configurar el pin como entrada con resistencia pull-up interna
  attachInterrupt(digitalPinToInterrupt(pinBoton), miFuncionInterrupcion, RISING); // Configurar la interrupción
}

void loop() 
{
  if(has_interrupted)
  {
    Serial.println("¡Botón presionado!");
    has_interrupted = false;
  }
}

En este ejemplo,

  • Al presionar el botón conectado al pin 12, se activará la interrupción
  • Se ejecutará la función de callback miFuncionInterrupcion()
  • Esta imprimirá el mensaje ¡Botón presionado! en el monitor serie.