23- Arduino, Interrupciones de hardware

No pude encontrar una imagen divertida para esta lecci贸n, solo encontr茅 alg煤n tipo de conferencia sobre programaci贸n, y el comienzo de esta conferencia nos explica perfectamente qu茅 es una interrupci贸n. Una interrupci贸n en Arduino se puede describir exactamente de la misma manera: el microcontrolador 芦deja todo禄, cambia a la ejecuci贸n del bloque de funciones en el controlador de interrupciones, las ejecuta y luego regresa exactamente al punto en el c贸digo principal donde fue detenido.


Una llamada desde el exterior.

Las interrupciones son diferentes, es decir, no las interrupciones en s铆 mismas, sino sus razones: una interrupci贸n puede ser activada por un convertidor de anal贸gico a digital, un temporizador-contador o, literalmente, un pin de microcontrolador. Estas interrupciones se denominan interrupciones externas de hardware y hoy hablaremos de ellas.

La interrupci贸n de hardware externa es una interrupci贸n causada por un cambio en el voltaje en un pin del microcontrolador. El punto principal es que el microcontrolador (n煤cleo de computaci贸n) no sondea el pin y no pierde tiempo en 茅l, otra pieza de hardware est谩 conectada en el pin. Tan pronto como cambia el voltaje en el pin (lo que significa que se aplica una se帽al digital, se aplica +5 / se elimina + 5), el microcontrolador recibe una se帽al, deja todo, procesa la interrupci贸n y vuelve a funcionar. 驴Por qu茅 es necesario? La mayor铆a de las veces, las interrupciones se utilizan para detectar eventos cortos: pulsos o incluso para contar su n煤mero sin cargar el c贸digo principal. Una interrupci贸n de hardware puede detectar una pulsaci贸n breve de un bot贸n o un disparador de sensor durante c谩lculos largos y complejos o retrasos en el c贸digo, es decir, en t茅rminos generales, el pin se consulta en paralelo con el c贸digo principal. Adem谩s, las interrupciones pueden despertar al microcontrolador de los modos de ahorro de energ铆a, cuando en general casi todos los perif茅ricos est谩n apagados. Veamos c贸mo trabajar con interrupciones de hardware en el IDE de Arduino.


Uso de las Interrupciones en Arduino.

Comencemos con el hecho de que no todos los pines pueden 芦interrumpir禄. S铆, existe algo llamado pinChangeInterrupts, pero hablaremos de ello en los tutoriales avanzados. Ahora debemos entender que las interrupciones de hardware solo las pueden generar ciertos pines:

Mc / n煤mero de interrupci贸nINT 0INT 1INT 2INT 3INT 4INT 5
ATmega 328/168 (Nano, UNO, Mini)D2D3
ATmega 32U4 (Leonardo, Micro)D3D2D0D1D7
ATmega 2560 (Mega)D2D3D21D20D19D18
Pines de interrupci贸n de Arduino.

Como entendi贸 en la tabla, las interrupciones tienen su propio n煤mero, que difiere del n煤mero de pin. Por cierto, hay una funci贸n relacionada, digitalPinToInterrupt ( pin ) que toma un n煤mero pin y devuelve el n煤mero de interrupci贸n. Habiendo alimentado esta funci贸n con el n煤mero 3 en el Arduino nano, obtenemos 1. Todo seg煤n la tabla anterior, una funci贸n para los perezosos.

Una interrupci贸n se conecta mediante la funci贸n attachInterrupt(pin, handler, mode):

  • pin – n煤mero de interrupci贸n
  • handler– el nombre de la funci贸n del controlador de interrupciones (debe crearla usted mismo)
  • mode– 芦modo禄 de operaci贸n de interrupci贸n:
    • LOW (bajo): se activa cuando una se帽al est谩 BAJA en el pin
    • RISING (crecimiento): se activa cuando la se帽al en el pin cambia de BAJA a ALTA
    • FALLING (ca铆da): se activa cuando la se帽al en el pin cambia de ALTA a BAJA 
    • CHANGE (cambio): se activa cuando la se帽al cambia (de BAJA a ALTA y viceversa)

La interrupci贸n tambi茅n se puede desactivar mediante la funci贸n detachInterrupt ( pin ), donde pin es nuevamente el n煤mero de interrupci贸n de arduino.

Tambi茅n puede deshabilitar globalmente las interrupciones con la funci贸n noInterrupts () y resolverlos de nuevo con interrupts (). 隆Cuidado con ellos! noInterrupts () tambi茅n detendr谩 las interrupciones de los temporizadores, y todas las funciones de tiempo y la generaci贸n de PWM se 芦detendr谩n禄.

Veamos un ejemplo en el que las pulsaciones de botones se cuentan en la interrupci贸n y, en el bucle principal, se emiten con un retraso de 1 segundo. Trabajando con el bot贸n en el modo habitual, es imposible combinar una salida tan aproximada con un delay:

volatile int counter = 0;  //contador variable
void setup() {
  Serial.begin(9600);// abre un puerto para la comunicaci贸n
 // conect贸 el bot贸n a D2 y GND
  pinMode(2, INPUT_PULLUP); \
  // D2 es interrupci贸n 0
  // controlador - funci贸n buttonTick
  // CAYENDO - cuando se presiona el bot贸n, habr谩 una se帽al de 0, y la capturamos
  attachInterrupt(0, buttonTick, FALLING);
}
void buttonTick() {
  counter++;  // + clic
}
void loop() {
  Serial.println(counter);  // salida
  delay(1000);              // espera
}

隆As铆 que nuestro c贸digo cuenta los clics incluso durante un delay; Excelente. Pero que es volatile? Hemos declarado una variable global counter, que almacenar谩 el n煤mero de veces que se presion贸 el bot贸n del arduino. Si el valor de la variable cambia en la interrupci贸n, debe informar al microcontrolador sobre esto utilizando el especificador volatile, que se escribe antes de especificar el tipo de datos de la variable, de lo contrario el trabajo ser谩 incorrecto. Solo debe recordarse esto: si una variable cambia en una interrupci贸n, h谩gala volatile.

Algunos puntos m谩s importantes:

  • Las variables modificadas en la interrupci贸n deben declararse como vol谩tile
  • La interrupci贸n no tiene retrasos como delay()
  • No cambian su valor durante las interrupci贸n las funciones  millis () y micros ()
  • En la interrupci贸n, la salida al puerto serie no funciona correctamente (Serial.print ()), tampoco debe usarlo all铆: carga el kernel.
  • Debe intentar hacer el menor n煤mero de c谩lculos posible durante una interrupci贸n y, en general, acciones 鈥渓argas鈥. 隆Ralentizar谩 el funcionamiento del MC con frecuentes interrupciones! 驴Qu茅 hacer? Lee abajo.

Atrapar el evento.

Si una interrupci贸n detecta un evento arduino que no necesita ser procesado inmediatamente, entonces es mejor usar el siguiente algoritmo de interrupci贸n:

  • En el controlador de interrupciones, simplemente levante la bandera.
  • En el bucle principal del programa, comprobamos la bandera, si se levanta, la reseteamos y realizamos las acciones necesarias.
volatile boolean intFlag = false;   // bandera
void setup() {
  Serial.begin(9600); 
   // conect贸 el bot贸n a D2 y GND
  pinMode(2, INPUT_PULLUP);
  // D2 es interrupci贸n 0
  // controlador - funci贸n buttonTick
  // falling - cuando se presiona el bot贸n, habr谩 una se帽al de 0, y la capturamos
  attachInterrupt(0, buttonTick, FALLING);
}
void buttonTick() {
  intFlag = true;   // levant贸 la bandera de interrupci贸n
}
void loop() {
  if (intFlag) {
    intFlag = false;    // reinicia
    // alguna accion
    Serial.println("Interrupt!");
  }  
}

El siguiente escenario posible: necesitamos captar la se帽al del 芦sensor禄 y responder inmediatamente una vez hasta que aparezca la siguiente se帽al. Si el sensor es un bot贸n, nos espera el rebote de los contactos. Es mejor lidiar con el rebote en el hardware, pero puede resolver el problema en el software: recuerde el momento de presionar e ignore las operaciones posteriores. Considere un ejemplo donde la interrupci贸n est谩 configurada para cambiar (CHANGE).

void setup() {
 // interrumpt en D2 (UNO / NANO)
  attachInterrupt(0, isr, CHANGE);
}
volatile uint32_t debounce;
void isr() {
  // deja un tiempo de espera de 100 ms para el rebote
  // CHANGE no proporciona el estado del pin, 
  // tengo que averiguarlo usando digitalRead
  if (millis() - debounce >= 100 && digitalRead(2)) {
    debounce = millis();
   // su c贸digo para interrumpcion en se帽al alta aqui
  }
}
void loop() {
}

Podr铆a decir: 隆pero millis () no cambia de valor en la interrupci贸n! S铆, no es as铆, 隆pero cambia entre interrupciones!

Esto es b谩sicamente todo lo que necesitas saber sobre interrupciones, analizaremos casos m谩s espec铆ficos en el curso avanzado.


Deja un comentario