Como usar las interrupciones en arduino

Una interrupción es básicamente la alteración del flujo natural de un programa, si pensamos en este como secuencial. Existen varios tipos de interrupciones posibles pero vamos a enumerar las dos principales, las restantes son solo derivaciones de estas.

Antes de entrar en detalle quiero comentar que este es un tema amplio de estudio, es imposible detallar todos los conceptos que el tema implica, con lo cual solo nos vamos a detener en contar de que se trata y para que se utiliza, dando algunos ejemplos se entiende mejor.

También comentar que las interrupciones no son solo propias de arduino, estas se encuentran disponibles en todos los microprocesadores comerciales.

Índice
  1. Tipos de interrupciones
    1. Interrupciones por Timer
    2. Interrupción por hardware

Tipos de interrupciones

Interrupciones por Timer

Estas interrupciones son disparadas cuando se cumple un cierto tiempo que nosotros mismos definimos, son muy usadas para controlar y leer sensores cada determinado tiempo y también para crear señales PWM para alimentar motores de corriente continua.

Como estas interrupciones se ejecutan cada un determinado tiempo, somos dependientes del cristal y del tiempo de cada pulso de clock de nuestro arduino. Pero gracias a que utilizamos librerías no tenemos que hacer ninguna cuenta, es importante saber que somos dependientes de eso, es decir no es lo mismo tener un cristal de 32 que uno de 16 MHZ. Pero como todos los arduinos traen un cristal de 16MHZ no nos preocupemos demasiado.

Los timers tienen algo que se conoce como prescaler, son divisores de la frecuencia de clock, cuando dividimos la frecuencia ganamos en tiempo pero perdemos en precisión, la frecuencia del cristal se puede dividor por 1,8,64,256

El siguiente ejemplo ejecuta una interrupcion por timer cada 250ms y prende y apaga un led cada vez que se la atiende.

 

#include <TimerOne.h>
const int led = 13;  // the pin with a LED
int ledState = LOW;    // El LED empieza apagado
volatile unsigned long blinkCount = 0; // La definimos como volatile

void setup(void)
   {
       pinMode(led, OUTPUT);
       Timer1.initialize(250000);         // Dispara cada 250 ms
       Timer1.attachInterrupt(ISR_Blink); // Activa la interrupcion y la asocia a ISR_Blink
       Serial.begin(9600);
   }

   void ISR_Blink()
   {   ledState = !ledState ;
       blinkCount++    ;     // Contador veces se enciende el LED
   }

   void loop(void)
   {
       unsigned long N;  // Haremos copia del blinkCount
       digitalWrite(led, ledState);  // Asignamos el valor del
                                     // status a la salida
       noInterrupts();               // Suspende las interrupciones
       N = blinkCount;
       interrupts();                 // Autoriza las interrupciones

       Serial.print("Ciclos = ");
       Serial.println(N);
       delay(100);
   }

Interrupción por hardware

Estas interrupciones son muy utilizadas en rebotica, se utilizan para detectar eventos externos. Por ejemplo si queremos que cada vez que alguien apriete un botón suceda alguna acción tenemos dos opciones. La primera alternativa y sin duda la peor de todas es quedarnos esperando que alguien apriete el botón, claramente no podríamos hacer otra cosa que esperar y estaríamos gastando toda la capacidad del microprocesador en no hacer nada, simplemente esperando que alguien apriete el botón. La segunda opción es usar las interrupciones de arduino (o del micro controlador que estemos usando).

Usar las interrupciones nos da como ventaja que podemos hacer cualquier otra cosa mientras esperamos que el evento suceda, simplemente cuando el evento se produce se acciona una bandera de interrupción que detiene y altera el flujo natural del programa para atender esa interrupción, básicamente es un orden de prioridades.

Como comente recién, manejar los eventos externos mediante interrupciones es la manera correcta de hacerlo, las ventajas están a la vista, gastamos pocos recursos del micro procesador y cumplimos el mismo objetivo.

Pero bueno, vamos al detalle. A la hora de usar las interrupciones en arduino necesitamos lo siguiente.

  • Conocer que arduino estamos usando: No todos tienen los mismo pines de interrupción.
  • Pin de arduino que reciba la condición de disparo.
  • Una condición de disparo
  • Una función que se ejecute cuando la interrupción sea disparada.

como usar interrupciones arduino

La condición de disparo se refiere a si la interrupción se va a ejecutar cuando detecte el paso del pin de interrupción de un estado alto a un estado bajo FALLING o cuando detecte el paso de un estado bajo a uno alto RISING.

Cuando eso ocurra arduino debe saber que hacer, para eso tenemos que definir una función que sera la encargada de atender la interrupción.

En el siguiente ejemplo se muestra como al presionar un botón vamos contando y enviando el dato por puerto serie para visualizarlo en pantalla, la interrupción es detectada y disparada cuando el pin de interrupción pasa de un estado alto a uno bajo FALLING.

int contador = 0;
int n = contador ;

void setup()
   {   Serial.begin(9600);
       attachInterrupt( 0, ServicioBoton, FALLING);
   }
void loop()
   {
       if (n != contador)
          {     Serial.println(contador);
                n = contador ;
          }
   }

void ServicioBoton() 
   {    contador++ ;
   }

Para usar las interrupciones y no generar conflictos con otras lógicas, y no alterar demasiado el flujo del programa, la atención de la interrupción debe ser rápida, lo mas rápida que se pueda, no es para nada recomendable hacer un bucle dentro de la función que atiende la interrupción.

En el programa de ejemplo no seria conveniente hacer el print en pantalla dentro de la interrupción, estaríamos generando demasiada demora en la atención de la interrupción.

Es importante entender que cuando la interrupción se esta atendiendo todo lo demás queda en pausa, el stack pointer por ejemplo, la función millis() queda en pausa hasta que salga de la atención de la interrupción.

En resumen es importante tener presente lo siguiente.

  • Cuando se esta atendiendo una interrupción, todas las demás interrupciones son ignoras hasta que no se termine de atender la interrupción presente.
  • Es importante no estar mucho tiempo atendiéndola, hay que hacer todo rápido y salir.
  • La función millis() queda congelada hasta que finalice la atención.
  • No hay que definir variables dentro de la interrupción, si se necesita usar variables deben ser definidas como globales fuera de ella.
  • Jamas hacer un Seriel.println dentro de una interrupción, primero por que tardaría demasiado y segundo por que es posible que ni siquiera funcione dependiendo de algunas variables.

Como siempre digo, espero que les sea de utilidad y respondo todos sus comentarios, todo lo que quieran aportar sera bienvenido y ayuda a mejorar.

No dudes en dejar tu opinión.

 

 

  1. Fermín dice:

    Soy aficionado a la programación en C. La explicación que has dado no puede estar mas clara.
    Gracias por la aportación, muy interesante

    1. veloso dice:

      Gracias Fermin!

  2. pablo dice:

    buenos dias. soy pablo de argentina.
    estoy usando un arduino mega y el ide de arduino (no recueerdo la version en este momento pero es una de las últimas )
    en mi codigo habilito el timer1 para q imterrumpa cada 1 segundo. el problema esta en que cuado dejo de usarlo necesitaría poder desactivar la interrupcion del mismo y luego volver a habilitarla cuando sea necesario. eso es posible?
    toque un par de registro pero hasta el momento sin exito. gracias

    1. Francisco dice:

      Pablo, Si se tiene que poder , yo no soy aún experto con arduino (soy de la vieja escuela), pero si se tiene que poder, seguí buscando en internet, info porque sé que se puede, seguramente se tiene que activar o desactivar un bit en algún registro, y con eso lo gobernás, es decir, activás o desactivás el timer.

      Fijate un poco en el artículo de este Señor, usa casi las cosas en assemble, con las instrucciones cli y sei, habilita o deshabilita las interrupciones.

      https://jaimedearcos.github.io/arduino/2017/01/04/Timers/

      Saludos

  3. Juliana dice:

    buenas noches, estoy haciendo un banner (leds en desplazamiento). Y me piden con un interruptor externo detener el movimiento.
    Es decir si mi banner dice "Hola mundo" y el movimiento va de derecha a izquierda y presiono el pulsador en la L ... ya me habría pasado Hol.. Y se quedaría mostrando la 'L'.. hasta que decida que avance. .
    Como podría hacer ese código de interrupción externa. Ayuda por favor 🙁

Deja un comentario

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

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Subir

Este sitio web utiliza cookies propias y de terceros para mejorar su experiencia. Puede optar por no participar si lo desea. Mas información