Gestión de interrupciones

Cuando queremos gestionar entradas/salidas con nuestro arduino, normalmente asociamos una acción a una entrada, pero si el software es grande o lento, puede que no tengamos el resultado esperado.

Hay dos formas de gestionar la entrada/salida de datos:

  • consulta de estado
  • Interrupciones

La consulta de estado puede ser un simple “if”, es una parte del código que corre dentro de la rutina (o función) principal. Esto hace que periódicamente, lleguemos a esta parte del código y acceda a la consulta, veamos un ejemplo:

// set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin</code>

// variables will change:
int buttonState = 0; // variable for reading the pushbutton status

void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
}

void loop(){
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);

// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(ledPin, HIGH);
}
else {
// turn LED off:
digitalWrite(ledPin, LOW);
}
}

Esto está bien para códigos pequeños, o que no necesiten realizar otras tareas… pero, ¿qué pasa si el código es muy largo, o muy lento?

// set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin</code>

// variables will change:
int buttonState = 0; // variable for reading the pushbutton status

void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
}

void loop(){
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);

// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(ledPin, HIGH);
}
else {
// turn LED off:
digitalWrite(ledPin, LOW);
}
delay(50000); //50 segundos de espera
}

¿Cuanto tardará en llegar otra vez la comprobación? Una eternidad si lo que queremos es una respuesta rápida. Y si encima, se nos pasa, pues ya…
Pero bueno, podemos decirle al procesador que espere que pulsemos el botón:

// set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin</code>

// variables will change:
int buttonState = 0; // variable for reading the pushbutton status

void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
}

void loop(){
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);

// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
while (buttonState == LOW) {
// turn LED off:
digitalWrite(ledPin, LOW);
}
digitalWrite(ledPin, HIGH);
}

Pero otro de los problemas de la consulta de estado es que durante el tiempo que está esperando que se produzca, el procesador no está haciendo nada útil.

Para solucionar esto, las interrupciones funcionan de la siguiente forma, una vez recibida la interrupción, el procesador deja lo que estaba haciendo y se va pitando a procesarla.

Un ejemplo muy básico para ver qué son las interrupciones y la consulta de estado:
Estamos leyendo un libro y en media hora hemos de hacer una llamada telefonica, podemos hacer 2 cosas;

  • consulta de estado
    • vamos mirando a cada párrafo el reloj
  • Interrupciones
    • ponemos una alarma al reloj y vamos leyendo

Es mucho más eficiente poner la alarma, ¿no?

Arduino UNO (más bien el Atmega 168 y 328) dispone de dos niveles de interrupción por Hardware, 0 y 1 asociados a los pines 2 y 3, estos definen la prioridad de la interrupción. La interrupción por hardware significa que son eventos que se producen fuera de nuestro código y que el procesador las debe tratar. Las interrupciones por software se les llama excepciones y son interrupciones a nuestro código debido generalmente a errores en nuestro código que las provoca (buffer overflows, divisiones por 0 … ), estas excepciones no las voy a tratar aquí, pero hay que tenerlas en cuenta para depurar nuestro código correctamente.

Un ejemplo muy cutre de una interrupción por software sería que estamos leyendo el libro y nos viene un apretón… poco más que decir… haced el debugging y listo xD

En cuanto a las interrupciones por hardware, nuestro programa principal va ejecutando un código, en el cual el flujo de trabajo es contínuo, y las interrupciones marcan una serie de pautas extras que pueden afectar o no a nuestro código, pero puede que afecte al comportamiento del sistema.

// set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin</code>

// variables will change:
int buttonState = 0; // variable for reading the pushbutton status

void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
attachInterrupt(0, enciendeLed, HIGH);
attachInterrupt(0, apagaLed, LOW);
}

void loop(){
//aqui puedes poner el codigo que quieras
delay(50000);
}

void enciendeLed(){
digitalWrite(ledPin, HIGH);
}
void apagaLed(){
digitalWrite(ledPin, LOW);
}

Aquí un ejemplo práctico para usar una interrupción, una maqueta de un tren, en la cual, el Arduino controla la velocidad desde un potenciómetro y mediante interrupción, controla su dirección mediante un relé:

int pulsadorDir = 2;
int dirTren = 8;
int pwmTren = 3;
int potenciometroTren= 0;
int state = LOW;
int velocidadTren = 0;</code>

void setup(){
Serial.begin(9600);

//configuracion de pines
pinMode(pulsadorDir, INPUT);
pinMode(dirTren, OUTPUT);
pinMode(pwmTren, OUTPUT);

attachInterrupt(0, direccionTren, FALLING); //(nivel int, funcion, en que estado);

}
void loop(){
//Si el switch no esta pulsado, gira en una direccion, si no en la contraria
velocidadTren = analogRead(potenciometroTren); // Lectura del valor del potenciometro
velocidadTren = 800 + (velocidadTren/6); // Para establecer la velocidad del tren
analogWrite(pwmTren, velocidadTren);
digitalWrite(ledPin, HIGH);
}

void direccionTren(){
state = !state;
digitalWrite(dirTren, state); // Establece la dirección del tren
}

El circuito de control de la maqueta es bastante simple, el Arduino lee el valor desde un potenciómetro y por PWM imprime la velocidad para que la locomotora se mueva. El código de la interrupción añade el sentido en que tiene que circular la locomotora para evitar que, al llegar cerca del extremo de la vía, si la siguiente lectura del pulsador llega tarde, el tren pueda descarrilar.

La sintaxis de la interrupción es bastante sencilla de escribir:
en setup tenemos que definir que vamos a utilizar una interrupción, en qué nivel, una función (llamada rutina de servicio de interrupción) que se encargara de tratarla y en qué evento se dispara.

attachInterrupt(0, direccionTren, FALLING);

El evento en que queremos disparar la interrupción tiene 4 modos, debido a los 4 eventos que se pueden producir en una señal eléctrica:

  • LOW lanza la interrución cuando el pin está a nivel bajo
  • CHANGE lanza la interrupción cuando el pin cambia de valor
  • RISING lanza la interrupción cuando el pin pasa de nivel bajo a nivel alto
  • FALLING lanza la interrupción cuando el pin pasa de nivel alto a nivel bajo

y luego definimos una rutina (que podemos utilizar como una función normal y corriente si es necesario).

void direccionTren(){
state = !state;
digitalWrite(dirTren, state); // Establece la dirección del tren
}

y este es el resultado, pasajeros al treeeeeen!!!

Licencia Creative Commons
Gestión de interrupciones por PepeChorva.com, a excepción del contenido de terceros y de que se indique lo contrario, se encuentra bajo una Licencia Creative Commons Attribution-ShareAlike 3.0 Unported Licencia.

3 pensamientos en “Gestión de interrupciones

  1. Pingback: Gestión de interrupciones | Freshcos como Lechugas

  2. Wenas Pepe
    Muy interesante lo de las interrupciones, lo estaba buscando.
    Una pregunta…las placas arduino tienen 5 entradas analogicas.
    ¿qué haces si necesitas tener no se, 20 entradas analogicas de 20 sensores?. Supongo que con un shield, ¿no?. ¿Cómo lo conectas, y cómo accedes a cada sensor?

    Gracias!

  3. Güenas Tomás, Arduino UNO tiene 6 entradas analógicas (0 a 5), te habrás fijado sólo en el pin del extremo :p

    Para usar más sensores analógicos se pude usar un multiplexor analógico o conversores A/D externos. No se si existe un shield que haga eso, supongo que sí… Pero es fácil montar el multiplexor, mira a ver esto:
    http://www.arduino.cc/es_old/Tutoriales/74HC4051
    lo explica divinamente y te da un código de ejemplo :)

Deja un comentario

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

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by sweetCaptcha