En este momento estás viendo ¿Qué son las interrupciones en Arduino?

¿Qué son las interrupciones en Arduino?

¿Que es una interrupción?

Una interrupción es una señal externa o interna que le indica al microcontrolador que un proceso debe ser atendido inmediatamente, y dispara un tipo único de función llamada rutina de servicio a interrupciones (Interrupt Service Routine ISR). Cuando se activa la interrupción, la ISR será llamada no importando lo que esté haciendo el microcontrolador.

Las interrupciones juegan un papel fundamental, en especial en la operación de dispositivos E/S. Sin ellas el sistema debería chequear constantemente los dispositivos para comprobar su actividad,

En todas las placas Arduino hay múltiples interrupciones que pueden ser controladas, sin embargo su manejo corresponde a funciones avanzadas. En la placa Arduino UNO solo tenemos dos interrupciones (externas) disponibles con el conjunto de instrucciones básicas. Estas interrupciones se encuentran en los pines digitales 2 y 3, y se llaman interrupción 0 y 1 respectivamente.

Las interrupciones externas (INT0 e INT1) de Arduino pueden ejecutarse porque la señal de entrada de un pin:

  • Está en nivel bajo (tiene el valor de 0) LOW
  • Ha cambiado de estado (tanto para flanco de subida como de bajada) CHANGE
  • Cambia a nivel alto (flanco de subida) RISING
  • Cambia a nivel bajo (flanco de bajada) FALLING

Funciones para el manejo de interrupciones

Hay 4 funciones básicas para el uso de interrupciones, y estas son:

interrupts()

Vuelve a habilitar las interrupciones (después que han sido inhabilitadas por noInterrupts()). Las interrupciones están habilitadas por defecto.

nointerrupts()

Deshabilita las interrupciones (puedes volver a habilitarlas con interrupts()).

Ejemplo 1 – Habilitar y deshabilitar las interrupciones

void setup() {}

void loop() {
noInterrupts();      //Deshabilita las interrupciones
// Código critico a ejecutarse sin interrupciones
interrupts();        //habilita las interrupciones
// más código aquí
}

attachInterrupt()

Habilita la interrupción indicando cual pin digital es el usado, cual es la función ISR y el modo de trabajo. La sintaxis es la siguiente:

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

donde

pin: Es el número de pin que se usara para la interrupción (pin 2 o pin 3)
ISR: La función ISR a llamar cuando la interrupción ocurra; esta función no tiene parámetros ni devolverá ningún valor. Se le llama por su nombre.
Mode: Indica cómo se activara la interrupción (LOW, CHANGE, RISING o FALLING)

detachInterrupt()

Desactiva la interrupción. La sintaxis es la siguiente:

detachInterrupt(digitalPinToInterrupt(pin));

donde
pin: Es el número de pin que se usara para la interrupción (pin 2 o pin 3)

¿Como funcionan las ISR en Arduino?

Las ISR son un tipo especial de funciones las cuales tienen algunas limitaciones, en principio estas no tienen parámetros y tampoco devuelven ningún valor. Generalmente, una ISR debe ser tan corta como sea posible, si nuestro programa usa varias ISR solo una podrá correr a la vez. La función millis() no cambiara su valor mientras este en la función, tampoco delay() funcionara, micros() funcionara bien siempre que no pasemos de 2ms, y delaymicroseconds() funcionara bien.

Típicamente las variables globales son usadas para intercambiar datos entre una ISR y el programa principal, y para mantener estas variables correctamente actualizadas debemos declararlas como “volatile”.

Ejemplo 2 – Un Led cambia de estado cada vez que pulsamos un boton

const byte ledPin = 13;         //declaramos una constante con el número de pin 
const byte interruptPin = 2;    //declaramos una constante con el pin de la interrupción
volatile byte estadop = LOW;    //Declaramos un variable global tipo byte “volatile”

void setup() {
  pinMode(ledPin, OUTPUT);    //configuramos el pin como salida
  pinMode(interruptPin, INPUT_PULLUP);  //configuramos el pin 2 como entrada
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);  //configura la interrupción
}

void loop() {
  digitalWrite(ledPin, estadop);  //se enciende el led de acuerdo al valor de la variable estadop
}

void blink() {      //se declara la función ISR
 estadop = !estadop;  //instrucción a ejecutar en la ISR
}

Ejemplo 3

int contador = 0;           //define una variable global

void setup()
   {   Serial.begin(9600);  //inicializa el monitor serial
       pinMode(2,INPUT_PULLUP); //configura el pin 2 como entrada con Resistencia pullup
       attachInterrupt(digitalPinToInterrupt(2),ServicioBoton,FALLING); //configura la interrupción
   }
void loop() { }    

void ServicioBoton()    //función ISR de atención de la interrupción
   {    
     contador++;      //incrementa el contador
     Serial.println(contador);    //imprime el valor de la variable contador
   }

Ejercicios

Ejercicio 1: Pulsador por interrupción

Crear un programa que incremente el valor de un contador y lo muestre en el monitor serial, el contador iniciara en 0 y se incrementara hasta 255, cambiando su valor cada 0,5 segundos. Adicionalmente configurar una interrupción en el pin 2, para que cuando se presione el botón conectado al pin2 el contador se reinicie (vuelva a cero).

Ejercicio 2: Contador

Crear un programa que muestre el valor de una variable en el monitor serial cada 1 segundo, y configurar una interrupción en el pin 2, que incremente el valor de la variable en dos unidades, cada vez que se presione el pulsador.

Probablemente te hayas dado cuenta que algunas veces que presionas el pulsador el valor se incrementa correctamente y otras veces cuenta mas de lo debido. Esto se debe a un comportamiento particular de los interruptores mecánicos que tiene como consecuencia un «rebote» de la señal al momento de la transición. Nada mejor que una imagen para ilustrarlo.

Como podemos apreciar la transición entre el nivel bajo y nivel alto no esta perfectamente definida por un tiempo (este tiempo puede oscilar entre unos 50 microsegundos hasta unos 10 milisegundos dependiendo del tipo de pulsador), y puede provocarnos errores cuando usamos una entrada digital para realizar operaciones de conteo, o cuando llamamos a una interrupción como en nuestro caso.

Hay dos formas de lidiar con el rebote de los contactos mecánicos, una es por hardware y la otra es por software. A continuación se presenta la solución por hardware que consiste en agregar un par de componentes, un capacitor y una resistencia, esta configuración filtra la señal del pulsador mejorando la transición entre los niveles altos y bajos. La solución por software cuando se lee el pulsador desde una ISR, no es la mejor opción pues involucra tiempos de espera, lo cual es contradictorio con lo que hablamos que debe ser una ISR.

Pulsador sin circuito Anti-rebote
Pulsador con circuito Anti-rebote

Modificar el circuito del pulsador y verificar que funciona el circuito antirebote.

Ejercicio 3 – Configurar dos interrupciones

Usaremos dos pulsadores para modificar el valor de una variable, El pulsador 1 incrementa la variable en uno, y el pulsador 2 la decrementa en 1 también, después que se ha presionado alguno de los dos pulsadores se imprime el valor de la variable en el monitor serie. La variable se inicializa en 1.

Y con los ejercicios hemos culminado la lección, espero te allá sido de provecho.

Y si aun no te has suscrito a nuestro boletín, suscríbete y te mantendré informado de  la últimas publicaciones y entregas especiales. Y si tienes alguna pregunta o comentario acerca del post no dudes en hacerla.

Esta entrada tiene un comentario

Deja una respuesta