Interrupciones
Interrupciones
Gestionando excepciones
OBJETIVOS
MATERIAL REQUERIDO.
LAS INTERRUPCIONES
¿Qué es una interrupción hardware?
A un nivel básico, una interrupción es una señal que interrumpe la actividad normal de
nuestro microprocesador y salta a atenderla. Hay tres eventos que pueden disparar una
interrupción:
Cuando un evento dispara una interrupción, la ejecución normal del micro se suspende
(ordenadamente para poder volver) y salta a ejecutar una función especial que llamamos
Interrupt Service Handler o ISH (Servicio de gestión de interrupción).
Cuando el ISH finaliza, el procesador vuelve tranquilamente al punto donde lo dejó y sigue
con lo que estaba como si no hubiese pasado nada.
La respuesta como siempre es… depende. Nuestro Arduino puede estar liado y solo leerá
la señal de un pin de tanto en tanto. Y si la señal que aparece se desvanece antes de que
hayamos ido a ver, ni siquiera lo sabremos, porque aunque los Duinos son rápidos una
señal electrónica lo es varios millones de veces más. Este es otro motivo por el que usar
delays tiene mucho peligro.
Por otro lado las interrupciones nos ofrecen una ventaja enorme a la hora de organizar
nuestro programa. Se define la función que se ejecutará al recibir una interrupción dada y
se ejecuta limpiamente cuando ocurre, no hay que comprobar si se da o no una situación.
TIPOS DE INTERRUPCIONES
De los tres sucesos que pueden disparar una interrupción
Un evento hardware,
Un evento programado, o Timer
Una llamada por software.
Nos encontramos con que Arduino no soporta las interrupciones por software y punto.
Los eventos programados o Timers, son muy interesantes y tendrán una sesión
monográfica propia en un futuro próximo. Pero por ahora vamos a meternos con las
interrupciones disparadas por hardware.
Modelo
Int 0 Int 1 Int 2 Int 3 Int 4 Int 5
Arduino
UNO Pin 2 Pin 3
MEGA 2 3 21 20 19 18
DUE Todos los pines del DUE pueden usarse para interrupciones.
Leonardo 3 2 0 1 7
Esto quiere decir que el Arduino UNO puede definir dos interrupciones hardware
llamadas 0 y 1, conectadas a los pines 2 y 3 (Para que no sea fácil).
El Mega como es habitual en él, acepta nada menos que 6 interrupciones diferentes. Y el
DUE, muy sobrado, exhibe su poderío.
Si nuestra call back function se llama Funcion1 (), para activar la interrupción usaremos:
Donde Interrupt es el número de la interrupción, ISR será Funcion1 y mode es una de las
condiciones que hemos visto arriba. Así en un Arduino UNO podría ser:
DIAGRAMA DE CONEXIONES
Es una especie de costumbre en Arduino, usar un pulsador para ilustrar el concepto de
Interrupción, así que nos plegáramos a ello. Vamos a utilizar un típico circuito para leer un
pulsador con un pullup.
void setup()
{ pinMode(2, INPUT);
Serial.begin(9600);
}
void loop()
{ bool p = digitalRead(2);
Serial.println(p);
}
int contador = 0;
int n = contador ;
void ServicioBoton()
{ contador++ ;
}
En primer lugar fijaros que hemos eliminado la definición de entrada del pin 2, porque no
vamos a usarlo como input estrictamente. Con definir la interrupción es suficiente.
Y por último el trigger es FALLING porque el estado es normalmente HIGH y baja a LOW
al pulsar el botón, utilizaremos el disparo con el flanco de bajada, o sea FALLING o LOW.
Les puede parecer una manera extravagante de hacer las cosas pero no me digáis que no
es elegante. De hecho todos los lenguajes modernos de alto nivel para Windows, Mac o
Linux utilizan la programación por eventos que es algo básicamente igual a esto (Salvando
las distancias claro).
Pues como ya vimos en su día, se debe a los rebotes del pulsador. Para eliminar el rebote
de los botones, tenemos que hacer el debouncing y lo hacemos con un delay de 250 ms.
Pero vamos a tener un problema. No podemos usar un delay dentro de una interrupción.
No funciona.
Además cuando definimos una variable global como contador, de la que depende una
función ISR, se recomienda definirla como volatile y no como una global normal.
Si necesitas un retraso para algo, o sea , un delay, siempre es mejor, comprobar el tiempo
transcurrido y decidir si se toma la acción o no. Veamos otro ejemplo
void setup()
{
interrupts () ;
Serial.begin(9600);
attachInterrupt( 0, ServicioBoton, FALLING);
}
void loop()
{
if (n != contador)
{
Serial.println(contador);
n = contador ;
}
}
void ServicioBoton()
En primer lugar definimos contador como volátil y definimos otra variable global T0 para
almacenar el tiempo a partir del cual contaremos.
Así es. Mientras una interrupción esta activa millis() está congelada y su valor no
cambiará, pero sigue pudiéndose leer.
Mientras estas dentro de una interrupción, todas las demás interrupciones, son
ignoradas, por eso, nada que dependa de otras interrupciones funciona.
Por eso es importante salir pronto, para garantizar que no nos perdemos nada de
interés.
Mientras una interrupción está activa, millis() y micros()se congelan. Eso quiere
decir que si tienes unos cuantos miles de interrupciones por segundo (Como si
estas midiendo la frecuencia de una onda de audio) tu medida de tiempo con millis
o micros se puede ver distorsionada.
Por ultimo les conviene saber que existen algunas otras instrucciones relativas a las
interrupciones: