Interrupciones externas y por hardware en Arduino

¿Qué son las interrupciones externas y por hardware en Arduino? ¿Cómo utilizar las interrupciones en un programa? Veamos ejemplos sencillos de cómo trabajar con interrupciones en el IDE de Arduino, en qué casos se pueden utilizar las interrupciones y cómo manejarlas correctamente. Presentaremos algunos programas de ejemplo con explicaciones y puntos importantes a los que prestar atención al utilizar interrupciones en Arduino.

Para esta actividad necesitaremos:

  • Arduino Uno / Arduino Nano / Arduino Mega
  • botón pulsador
  • LEDs y resistencias
  • protoboard
  • cables de conexion

Las interrupciones pueden explicarse con un ejemplo bastante sencillo de la vida. Por ejemplo, el cartero tiene que traerte hoy una carta muy importante. Para leerla más rápido, vas a mirar el buzón cada 10 minutos. De este modo, malgastará su tiempo personal de forma improductiva. En el caso de un microcontrolador Arduino Uno, parece un sondeo constante de algún sensor o botón pulsador, en el que el procesador también malgastará recursos.

La segunda opción, más racional en términos de ahorro de tiempo, es dejar una nota al cartero para que no eche la carta al buzón y te la entregue personalmente. De este modo, puedes dedicarte a tus asuntos sin la distracción de mirar constantemente el buzón. Cuando el cartero llame a tu timbre, tendrás que interrumpir tu trabajo para abrir la puerta y coger la carta y luego volver a tu negocio. Por eso se llama interrupción externa en lenguaje Arduino.

Qué son y cómo usar interrupciones en Arduino

Interrupciones externas y por hardware en Arduino
Interrupciones externas y por hardware en Arduino

Las interrupciones en Arduino IDE funcionan de forma similar. Por ejemplo, el microcontrolador puede esperar a que el usuario pulse un botón. Para ello, puede utilizar el comando digitalRead() en el programa y controlar el botón con una frecuencia alta. Pero puede utilizar una interrupción de hardware sin perder tiempo sondeando el botón, pero tan pronto como se pulse el botón, la señal de hardware activará una función dentro del código Arduino.

placas Arduino pines que soportan interrupciones
Arduino Uno, Nano, Mini 2, 3
Arduino Mega 2, 3, 18, 19, 20, 21
Arduino Micro, Leonardo 0, 1, 2, 3, 7
Arduino Zero todos los pines digitales excepto 4
Arduino Due todos los pines digitales

La tabla muestra los pines que pueden utilizarse para las interrupciones. Si un pin de la placa no es compatible con la función de interrupción, el programa no funcionará. Las interrupciones en el IDE de Arduino se activan por un cambio en la señal digital de la entrada que está monitorizando, pero puede seleccionar el cambio exacto que desea monitorizar. Para hacer esto, necesitas cambiar el tercer parámetro en la función attachInterrupt().

Sintaxis: attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);

digitalPinToInterrupt(pin) – en este parámetro es necesario especificar un pin concreto que se utilizará para procesar la señal de interrupción externa.

ISR – nombre de la función que será llamada durante la interrupción

mode – tipo de transición (cambio de estado) que se procesará, por ejemplo, nivel abajo, nivel arriba, etc. Son posibles los siguientes valores

  • RISING: cuando la señal cambia de LOW a HIGH
  • FALLING: cuando la señal cambia de LOW a HIGH
  • CHANGE: cada vez que la señal cambia de HIGH a LOW o de LOW a HIGH
  • LOW: la interrupción se activará cada vez que la señal sea HIGH

Interrupciones en Arduino con attachInterrupt

Interrupciones en Arduino con attachInterrupt
Interrupciones en Arduino con attachInterrupt

En el primer ejemplo, el microcontrolador monitoriza constantemente el estado del botón, y el LED se enciende cuando se pulsa el botón pulsador. Pero al utilizar la entrada digital 2 de la placa en modo interrupción, el microcontrolador no necesita sondear el botón. Si la señal digital en el pin habilitado para interrupción cambia, el Arduino detendrá la ejecución del código del programa principal sin que el botón pulsador sea sondeado continuamente.

Programa Arduino sin interrupciones de hardware

#define LED 10
#define BUTTON 2

byte ledState = LOW;

void setup() {
   pinMode(LED, OUTPUT);
   pinMode(BUTTON, INPUT);
}

void loop() {
   if (digitalRead(BUTTON) == HIGH) {
      ledState = !ledState;
   }

   digitalWrite(LED, ledState);
}

Explicación del código sin interrupciones de hardware Arduino:

  1. al pulsar el botón cambia el estado del LED.

El siguiente ejemplo cambiará la forma de controlar el botón – una función de interrupción se adjuntará a la entrada digital 2 del microcontrolador Arduino. Cuando la señal del botón aumente, es decir, la señal digital LOW cambie a HIGH, el código del programa principal en void loop() se detendrá y se llamará a void blinkLed(). La principal ventaja que obtenemos en este caso es que ya no es necesario el sondeo constante del botón en el programa.

Programa Arduino con interrupciones por hardware

#define LED 10
#define BUTTON 2

volatile byte ledState = LOW;

void setup() {
   pinMode(LED, OUTPUT);
   pinMode(BUTTON, INPUT);

   attachInterrupt(digitalPinToInterrupt(BUTTON), blinkLed, RISING);
}

void loop() {
 
}

void blinkLed() {
   ledState = !ledState;
   digitalWrite(LED, ledState);
}

Explicación del código con interrupciones por hardware Arduino:

  1. observe que no hay ningún comando en el bucle principal.

Qué hay que tener en cuenta al trabajar con interrupciones

Haz que la función de interrupción sea lo más rápida posible

Debes hacer que la función de interrupción sea lo más rápida posible, porque detiene la ejecución del código principal de tu programa. Si necesitas realizar cálculos pesados o acciones largas cuando se dispara una interrupción externa, deberías dejarlas en void loop(). Y dentro de las funciones de interrupción deberías cambiar sólo las variables de estado de las que dependen las operaciones necesarias.

No utilice funciones de tiempo en las interrupciones

El comando delay() en una función de interrupción no funcionará. Si utiliza un contador de tiempo en millis(), cuando salga de la función de interrupción, obtendrá el último valor almacenado, ya que millis() no se incrementa dentro de la función de interrupción. Es posible que el uso de millis() se utilice para evitar que el botón traquetee, pero es mejor utilizarlo en el bucle principal void loop().

No utilice el monitor de puerto dentro de interrupciones

Cuando está dentro de una interrupción, los datos enviados o recibidos a través de comandos Serial pueden perderse. Puedes usar Serial.print() dentro de una función de interrupción para depurar el programa, por ejemplo para asegurarte de que la interrupción se dispara, pero puedes tener problemas. Es mejor simplemente establecer una bandera dentro de la interrupción y sondear esa bandera dentro del programa principal void loop().

Usar volatile para declarar variables

Las variables usadas dentro de funciones ISR y en funciones normales deben ser declaradas usando volatile. Esto indica al compilador que las variables de este tipo pueden cambiar en cualquier momento, y que el microcontrolador debe recargar la variable cada vez que acceda a ella, en lugar de confiar en una copia de la misma. De lo contrario, los algoritmos de optimización pueden eliminar la variable por completo del ejecutable.

Conclusión. Usar la función attachInterrupt(digitalPinToInterrupt(pin), ISR, mode); de Arduino es muy útil cuando necesitas estar seguro de que el microcontrolador no se perderá ningún cambio en la señal que estás monitorizando. Sin embargo, cuando se utilizan interrupciones de pulsador en Arduino, hay que tener cuidado de no utilizarlas con demasiada frecuencia. A veces, utilizar sólo el sondeo del sensor puede ser una mejor opción.


Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *