VI. Interrupciones en un microcontrolador

 

Las interrupciones de hardware. Consisten en el cambio en la secuencia de ejecución de un programa, esto cuando se da un determinado evento de hardware, para pasar a ejecutar una rutina asociada con el evento de hardware implicado, a ésta frecuentemente se le denomina “rutina de servicio”. Una vez que concluye la ejecución de la rutina de servicio, el microcontrolador deberá retornar a la secuencia de ejecución que fue interrumpida. Para un determinado MCU, eventos de hardware podrán ser entre otros: que el puerto serie asíncrono haya recibido un byte y éste esté listo para ser leído, que se dé un flanco de bajada en un determinado bit de puerto, etc. En esta exposición, a los diversos eventos de hardware que pueden hacer que se dé una interrupción, se les denominará como INSTANCIAS DE INTERRUPCIÓN y cuando éstas llegan a presentarse, se dice que se tiene un REQUERIMIENTO REQUERIMIENTO INTERRUPCIÓN (RI). N (RI).

Las interrupciones con Arduino nos permitirán reaccionar a eventos externos a la placa de una forma rápida. Cuando se detecta una señal, una interrupción, interrumpe el proceso que se está ejecutando. Esto nos va a permitir dos cosas. Por un lado, ejecutar rápidamente un trozo de código, y por otro lado parar la ejecución del código que se estaba ejecutando.

Por qué utilizar interrupciones con Arduino

Utilizar interrupciones nos permitirá olvidarnos de controlar ciertos pines. Esto muy importante ya que, dentro de una aplicación o programa, no vamos a hacer una única cosa. Por ejemplo, queremos que un LED se encienda o se apague cuando pulsamos un botón. Esto es relativamente sencillo, pero cuando además queremos que otro LED parpadee, la cosa se complica.

Las interrupciones no son simplemente para cambiar y hacer algo diferente. Por ejemplo, estamos montando en bicicleta llegamos a casa y guardamos la bici en el garaje o un botón es pulsado por el usuario y permite parar el DFRobot. En estos dos casos no interrumpimos una acción, pasamos a hacer algo diferente. Terminamos de hacer una cosa y hacemos otra. En el caso del botón, lo máximo que podemos hacer es recordar el estado de botón pulsado. Debemos utilizar las interrupciones para lo que son, interrumpir lo que se está ejecutando y realizar otra tarea, para luego volver al mismo sitio donde lo habíamos dejado.

Dentro de la gama de interrupciones con Arduino están las interrupciones programadas y las interrupciones externas. La filosofía es la misma, poder ejecutar un código cuando sucede un evento concreto. En el caso de las interrupciones programadas, el evento se disparará cada cierto intervalo de tiempo que debemos de configurar. Este tipo de interrupciones no es el objeto de este artículo. Si quieres saber más puedes ver la referencia de la librería TimerOne que se encarga de configurar y gestionar este tipo de interrupciones.

 

attachInterrupt(pin, ISR, modo)

Esta función nos va a permitir definir o configurar uno de los pines como un puerto de interrupción. Los tres parámetros que admite son:

·         pin: debemos llevar especial cuidado con este parámetro. Indica que pin vamos a utilizar como interrupción. No debemos pasar el número de pin, debemos pasar el ordinal, es decir, si trabajamos con Arduino UNO tenemos dos pines para interrupciones el 2 y el 3. Si queremos utilizar el 2 debemos poner un 0 y si queremos utilizar el 3 debemos poner un 1. Esto se resuelve muy fácilmente utilizando otra función, digitalPinToInterrupt(pin), que devuelve el ordinal del pin que queremos utilizar. En este caso sí que debemos pasar su número. Por ejemplo, en el caso anterior, si queremos utilizar el pin 2 llamaríamos a la función digitalPinToInterrupt(2). Esto nos devolverá un 0 y es el método recomendado por Arduino para pasar este parámetro.

·         ISR: es una abreviatura de Interrupt Service Routine y no es más que la función o método que se llama cuando se produce la interrupción. Es de un tipo particular ya que no admite parámetros y tampoco devuelve ningún valor.

·         modo: define cuando debe ser disparada la interrupción. Puede tomar cuatro valores constantes dependiendo de lo que queramos hacer:

·         LOW: se lanzará la interrupción cuando el pin esté en estado bajo.

·         CHANGE: se lanzará la interrupción cuando el pin cambie de valor de alto a bajo, o de bajo a alto.

·         RISING: se lanzará la interrupción cuando el pin cambie de estado de bajo a alto.

·         FALLING: se lanzará la interrupción cuando el pin cambie de estado de alto a bajo.

Existe un quinto estado que solo los Arduino Due, Zero y MKR1000 permiten:

·         HIGH: se lanzará la interrupción cuando el pin esté en estado alto.



 

detachInterrupt(pin)

Si attachInterrupt() nos permite configurar un pin como interrupción, el método detachInterrupt() anula esa configuración. Como parámetro le pasamos el pin y lo podemos hacer con la función digitalPinToInterrupt(número de pin) que nos devolverá el ordinal del pin del que queremos anular la configuración.

Ejemplo 1

Circuito eléctrico

Vamos a necesitar el siguiente material:

·         2 LEDs verdes

·         3 LEDs rojos

·         5 resistencias de 470 Ω

·         2 pulsadores

·         1 resistencia de 1 kΩ

·         Arduino UNO

·         Protoboard

·         Cables macho/macho

Cada pulsador irá conectado a un pin y tendrán una resistencia pull-down. Esto hará que, en estado normal, sin pulsar, el pin tengamos un estado bajo. Cuando el pulsador se active tendremos un estado alto. Por lo tanto, debemos de detectar un cambio de estado de bajo a alto (RISING).

Por otro lado, los LEDs van a hacer una secuencia de encenderse y apagarse de izquierda a derecha y de derecha a izquierda. Simula las luces del coche fantástico. Empezaremos con una velocidad y según vayamos pulsando los pulsadores se irá aumentando o disminuyendo la velocidad.

El esquema eléctrico es el siguiente.



Programación del sketch de interrupciones con Arduino

La primera parte es la declaración de contantes y variables. En este punto hay que hacer una aclaración. Cuando trabajamos con interrupciones con Arduino, hay que llevar especial cuidado con los métodos ISR que se van a ejecutar cuando se produce el evento.

En general, debemos hacer métodos o funciones ISR lo más cortas y rápidas posibles. Se puede producir un bloqueo entre los diferentes ISR. Lo que sucede en estos casos es que solo se ejecuta una a la vez quedando en cola el resto de interrupciones.

Dentro de las interrupciones no funciona el delay() (retardo) por lo tanto no lo utilices. Recuerda que se trata de ejecutar un código lo más rápido posible. Si quieres hacer que el proceso se pare dentro de un ISR utiliza la función delayMicrosends(), ya que funciona con normalidad.

Las variables que vayamos a utilizar tanto dentro de los métodos ISR como fuera, ya sea en el loop() o en cualquier otra función, debemos declararlas como volatile. Esta palabra reservada le dice al compilador que estas variables pueden cambiar de valor en cualquier momento y, por lo tanto, el compilador debe volver a cargar la variable cada vez que se hace referencia en algún sitio a ella. Al contrario que ocurre con otras variables donde el compilador confía en alguna copia que pueda tener en algún registro del procesador.

 

Código en Arduino



Simulación en fritzing




Simulación en proteus


Ejemplo 2

En este ejemplo, se utiliza el pin2 de la tarjeta Arduino UNO, el cual está asociado a la interrupción INT0 (ver tablas 12.1 y 12.3); también, se emplea la función attachInterrupt(num int, rutina interrupción, CHANGE) donde se ha seleccionado la constante CHANGE para indicar cambios de niveles de voltaje (LOW y HIGH), esta es la forma para detectar o activar la interrupción . Al pin 2 debe conectarse el pin 13, el cual conmuta esos niveles de voltaje.

Código en Arduino






Ejemplo 3

Se utiliza el pin 2 (INT0) para generar la solicitud de interrupción, la forma de activarla es por cambios de voltajes 0 y 5 V para Arduino UNO o 3.3 V para otros modelos (LOW y HIGH). Para eso se emplea un puerto digital programado como salida, por ejemplo, el pin 13, el cual está conectado al pin 2. El cuadro de código Arduino 12.2 contiene la descripción del sketch cap12 funciones. La subrutina de servicio de interrupción ISR se denomina rutina interruptcion(); en esta función se realiza la conmutación de pulsos del pin 13 → pin 2, el incremento del tiempo tk y la función y = sen(t) (las demás funciones el usuario las puede pro- gramar).

 




Código en Arduino



Código en matlab



Simulación grafica



 

Ejemplo 4

Para trabajar en tiempo real es necesario generar una base de tiempo a través de un timer interno o reloj externo, tal que en forma periódica establezca una señal de interrupción, con la frecuencia de muestreo adecuada de tal forma que el tiempo empleado en realizar todas las operaciones dentro de la IRS sean menor al período de muestreo (la frecuencia de muestreo es el inverso del período de muestreo).

 

Código Arduino



Código matlab


Simulación grafica



Ejemplo 5

ejemplos en adquisición de datos y control, cuya base de tiempo es de 2 mseg como período de muestreo, el cual se genera a partir del TIMER 1 de la tarjeta Arduino UNO.

Código Arduino


codigo matlab



Simulación grafica




Ejemplo 6

La rutina de servicio de interrupción ISR contiene la implementación discreta del sistema, así como la ley de control u(tk) para obtener la convergencia del estado del sistema al estado deseado xd = 1, conforme el tiempo discreto tk evoluciona.

 

Código Arduino



Código matlab

Simulación grafica



Ejemplo 7

Encender y apagar, consecutivamente, un LED en la patilla RB7 cuando se produzca un cambio de nivel en la patilla RBO Componentes: ISIS: PIC16F876, RES, LED-GREEN y SW-SPDT-MOM.

Simulación en proteus



Programación en pic

 



Ejemplo 8

Generar una señal cuadrada de 1KHz utilizando la interrupción del TIMER0 Componentes ISIS: PIC16F876 e Instrumentos ISIS: OSCILLOSCOPE y COUNTER TIMER.

Programación en pic

 



Simulación en proteus





Ejemplo 9

Generar una función que permita realizar retardos de 1 segundo empleando el TIMER1. Componentes ISIS: PIC16F876.

Simulación en proteus

 



Programación en pic

 


 

Ejemplo 10

: Medir el ancho de un pulso mediante el TIMER1 y la interrupción externa por RBO f figura 18). Componentes ISIS: PIC16F876 y LM016L. Instrumentos: OSCILLOSCOPE y Generadores: PULSE.

Simulación en proteus

 



Programación en pic

 



Ejemplo 11

Generar una señal cuadrada de 1 KHz utilizando la interrupción del TIMER2. Componentes ISIS: P1CI6F876 e Instrumentos ISIS: OSCILLOSCOPE 1/ COUNTER TIMER.

Simulación en proteus





Programación en pic



Ejemplo 12

Introducir los datos, a través del teclado, de la velocidad de un motor de corriente continua y generar una señal modulada en un ancho de pulso proporcional al dato de velocidad. Controlar la velocidad en rpm y visualizarla en un LCD (figura 24). Componentes ISIS: P1CI8FS76, KEYPAD-PHONE, RES, 2SK1058, CELL, LM016L y M OTORENCODER.

Programación en pic



Simulación en proteus



Ejemplo 13

Según la duración de pulsación de un botón obtener tres tipos defunciones: una pulsación corta da lugar a tina función (por ejemplo, encender un led en el puerto A), una prim era pulsación mayor de tres segundos da lugar a otra función (por ejem plo encender un led en el puerto C) y una segunda pulsación mayor de tres segundos de lugar a otra función (por ejem plo apagar el led del puerto C). Cuando se trabaje con la segunda o tercera función no se atenderán las pulsaciones cortas. Componentes ISIS: PIC18F877, BUTTON, RES, LED-RED, LED-BLUE.

Simulación en proteus




Programación en pic





Para finalizar se muestran avances del proyecto asignado como robot minisumo.

codigo del minisumo 


int in1=2, in2=4, in3=7, in4=8;
int ena1=3, ena2=5;
int sensor1=10;
int sensor2=11;
int TRIGGER=9;
int ECHO=6;
int valor1=0;
int valor2=0;
long distancia;
float velocidad=0.017;
long tiempo;

void setup() {
  //Sensor ultrasonico
  pinMode (TRIGGER, OUTPUT);
  pinMode (ECHO, INPUT);
  digitalWrite(TRIGGER, LOW);
  //Sensor infrarrojo
  pinMode (sensor1, INPUT);
  pinMode (sensor2, INPUT);
  //Entradas de los motores
  pinMode (in1, OUTPUT);
  pinMode (in2, OUTPUT);
  pinMode (in3, OUTPUT);
  pinMode (in4, OUTPUT);
  //Controles de velocidad
  pinMode (ena1, OUTPUT);
  pinMode (ena2, OUTPUT);
  //Velocidad de motores
  analogWrite(ena1, 255); 
  analogWrite(ena2, 255); 
}
//Estados del robot
void detener() {
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, LOW);
}
void izquierda() {
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
}
void derecha() {
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
}
void atras() {
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
}
void adelante() {
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);

digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
}
void buscar(){
  adelante;
  atras;
  izquierda;
  derecha;
  detener;
  }
void ultrasonico(){
  digitalWrite(TRIGGER, HIGH);//Realiza un ultrasonido
  delayMicroseconds(10);// Por 10 microsegundos
  digitalWrite(TRIGGER, LOW);// Se apaga
  tiempo=pulseIn(ECHO, HIGH);//Cuanto tiempo tardo el microfono en captar el sonido
  distancia=velocidad*tiempo;
  Serial.print(distancia);
  delay(50);
}
void infrarrojos(){
  valor1=digitalRead(sensor1);
  valor2=digitalRead(sensor2);
}
void loop(){
  ultrasonico();
  if(distancia<20){
    adelante();
  }
  else
  if(distancia>41){
    infrarrojos();
  if(valor1==1 & valor2==1){
    adelante();
  }
  if (valor1==0 & valor2==0){
    detener();
    delay(1000);
    atras();
    delay(1000);
    derecha();
    delay(1250);
  }
  if (valor1==0 & valor2==1){
    detener();
    delay(1000);
    izquierda();
    delay(1250);
  }
  if (valor1==1 & valor2==0){
    detener();
    delay(1000);
    derecha();
    delay(1250);
    }
  }
}

Comentarios

Entradas más populares de este blog

VII. PROGRAMACIÓN DEL MICROCONTROLADOR CON APLICACIONES