42- El temporizador de interrupciones en Arduino

Ya hemos聽considerado el dise帽o del temporizador聽Arduino muchas veces, millis (), que le permite ajustar la l贸gica del c贸digo mediante temporizadores.聽La desventaja de este m茅todo es la necesidad de sondear constantemente la construcci贸n del temporizador para comprobar si ha funcionado.聽En consecuencia, el c贸digo en el bucle principal debe ser 芦transparente芦, es decir, no debe contener retrasos ni bucles cerrados largos, simplemente c贸digo.聽Esto no es tan cr铆tico para las temporizaciones con un per铆odo largo (minutos, muchos segundos), pero para realizar acciones con una frecuencia alta y estrictamente especificada cualquier peque帽o retraso en el bucle principal puede ser un gran problema.聽Una forma de salir de la situaci贸n puede ser con una interrupci贸n del temporizador.聽Recuerde la聽lecci贸n sobre interrupciones de hardware: una interrupci贸n le permite 芦salir禄 de cualquier fragmento de c贸digo que se est茅 ejecutando actualmente en el bucle principal de Arduino, ejecutar el bloque de c贸digo deseado que se encuentra dentro de la interrupci贸n y volver a donde lo dej贸 y continuar con la ejecuci贸n.聽Por tanto, es pr谩cticamente una ejecuci贸n paralela de tareas.聽En este tutorial, aprenderemos c贸mo hacer esto usando el temporizador de hardware.

驴Por qu茅 utilizar interrupciones de temporizador?

  • Generaci贸n de se帽ales.
  • Medida de tiempo.
  • Ejecuci贸n paralela de tareas.
  • Completar una tarea despu茅s de un per铆odo de tiempo estrictamente especificado.
  • Y mucho m谩s…

Temporizadores.

Las interrupciones en Arduino son generadas por un temporizador de hardware separado, que se encuentra en Arduino en alg煤n lugar cerca del n煤cleo.聽El temporizador de hardware, tambi茅n聽conocido聽como聽contador, realiza una tarea muy simple: cuenta los 芦tics禄 del generador de reloj (que establece la frecuencia de todo el sistema) y, dependiendo del modo de funcionamiento, puede solo reiniciarse o enviar una se帽al al microcontrolador en ciertos valores de contador.聽Por lo tanto, la 芦resoluci贸n禄 del temporizador es un tic (reloj) del oscilador maestro, a 16 MHz es聽0.0625聽microsegundos.聽El segundo punto importante a entender es el siguiente: el temporizador-contador funciona y cuenta los pulsos en paralelo al n煤cleo computacional.聽Es por eso que la generaci贸n de una se帽al PWM, incluso a alta frecuencia, no tiene absolutamente ning煤n efecto en la ejecuci贸n del c贸digo, todo sucede en paralelo.

En arduino nano (atmega328) tenemos tres de estos temporizadores, y cada uno puede activar una interrupci贸n independiente seg煤n su per铆odo. El contador de tiempo en las funciones millis () y micros () funcionan simplemente interrumpiendo el temporizador 0. Si ponemos a cero el temporizador 0, perderemos la cuenta de tiempo correcta (y, posiblemente, PWM en los pines 5 y 6). Algunas bibliotecas tambi茅n usan interrupciones de temporizador, por ejemplo, Servo usa el primero y la funci贸n incorporada tone ()– el segundo. Tambi茅n discutimos en las lecciones que los temporizadores son los que est谩n involucrados en generar una se帽al PWM en sus pines, y cuando el temporizador se reconfigura, el PWM suele apagarse, comenzar a trabajar en un modo diferente o cambiar la frecuencia PWM.

A diferencia de la generaci贸n de se帽ales PWM y las interrupciones Arduino de hardware, los desarrolladores de Arduino no implementan el control de interrupciones del temporizador en el kernel y las bibliotecas est谩ndar, por lo que trabajaremos con interrupciones utilizando bibliotecas de terceros. Puede trabajar con el temporizador directamente, como se describe en la hoja de datos (datasheet), pero esto no est谩 incluido en este curso. Para el primer y segundo temporizador, se pueden encontrar bibliotecas antiguas llamadas timerOne y timerTwo. Pero usaremos la biblioteca: GyverTimers, que permite la configuraci贸n flexible de todos los temporizadores en atmega328 (Arduino UNO / Nano) y atmega2560 (Arduino Mega). Puede descargar la biblioteca a trav茅s de un enlace directo. Consideremos las principales herramientas de la biblioteca.


Biblioteca GyverTimers.

La biblioteca GyverTimers le permite generar interrupciones de temporizador con una frecuencia espec铆fica en el canal de temporizador seleccionado o en varios canales a la vez con un cambio de fase: las interrupciones ocurrir谩n con la misma frecuencia, pero se 鈥渄esplazar谩n鈥 entre s铆. Tambi茅n puede configurar la acci贸n para mostrar el temporizador: habilitar / deshabilitar / alternar: el temporizador controlar谩 el pin seleccionado independientemente del n煤cleo computacional de Arduino, por lo que puede generar una onda cuadrada (se帽al cuadrada), tanto de ciclo 煤nico como de dos y tres tiempos con cambio de fase ajustable.

Hay tres temporizadores disponibles para Arduino Nano / UNO / Pro MiniTimer0 , Timer1 , Timer2. Para Arduino MEGAseisTimer0 , Timer1 , Timer2 , Timer3, Timer4 , Timer5 . En la biblioteca, los temporizadores se describen como objetos, el acceso se produce como de costumbre a trav茅s de un punto, por ejemplo Timer1.stop();

Tabla de temporizador ATmega328p

TemporizadorProfundidad de bitsFrecuencia PeriodoSalidasPin de ArduinoPin del Mc
Timer08 bits61 Hz .. 1 MHz16 384 .. 1 渭sCHANNEL_AD6PD6
CHANNEL_BD5PD5
Timer116 bits0,24 Hz .. 1 MHz4200 000 .. 1 渭sCHANNEL_AD9PB1
CHANNEL_BD10PB2
Timer28 bits61 Hz .. 1 MHz16 384 .. 1 渭sCHANNEL_AD11PB3
CHANNEL_BD3PD3

Tabla de temporizador ATmega2560

TemporizadorProfundidad de bitsFrecuenciaPeriodoSalidasPin de ArduinoPin Mc
Timer08 bits61 Hz .. 1 MHz16 384 .. 1 渭sCHANNEL_A13PB7
CHANNEL_B4PG5
Timer116 bits0,24 Hz .. 1 MHz4200 000 .. 1 渭sCHANNEL_A11PB5
CHANNEL_B12PB6
CHANNEL_C13PB7
Timer28 bits61 Hz .. 1 MHz16 384 .. 1 渭sCHANNEL_A10PB4
CHANNEL_B9PH6
Timer316 bits0,24 Hz .. 1 MHz4200 000 .. 1 渭sCHANNEL_A5PE3
CHANNEL_B2PE4
CHANNEL_C3PE5
Timer416 bits0,24 Hz .. 1 MHz4200 000 .. 1 渭sCHANNEL_A6PH3
CHANNEL_B7PH4
CHANNEL_C8PH5
Timer516 bits0,24 Hz .. 1 MHz4200 000 .. 1 渭sCANAL_A46PL3
CHANNEL_B45PL4
CHANNEL_C44PL5

Periodo m谩ximo

La tabla anterior muestra los rangos para el reloj de 16 MHz est谩ndar de Arduino.聽Para otro reloj del sistema, el per铆odo m谩ximo se calcula mediante la f贸rmula, donde F_CPU es la frecuencia del sistema en Hz:

  • Temporizadores de 8 bits: (1000000UL / F_CPU) * (1024 * 256)
  • Temporizadores de 16 bits: (1000000UL / F_CPU) * (1024 * 65536)

Ajuste de frecuencia / per铆odo

setPeriod (per铆odo);- establece el per铆odo en microsegundos y pone en marcha el temporizador. Devuelve el per铆odo real en 渭s (precisi贸n limitada por la resoluci贸n del temporizador).
setFrequency (frecuencia);- establece la frecuencia en hercios y pone en marcha el temporizador. Devuelve la frecuencia real en Hz (precisi贸n limitada por la resoluci贸n del temporizador).
setFrequencyFloat ( frecuencia Float);- configurando la frecuencia en Hertz e iniciando el temporizador, se permiten fracciones decimales. Devuelve la frecuencia real (precisi贸n limitada por la resoluci贸n del temporizador).

Control del temporizador

  • pause () ;- pausar el conteo del temporizador sin reiniciar el contador.
  • resume () ; – seguir contando despu茅s de una pausa.
  • stop () ;- dejar de contar y poner a cero el contador.
  • restart () ;- reiniciar el temporizador (reinicia el contador)

Interrupciones

  • enableISR (canal, fase );- iniciar interrupciones en el canal seleccionado con el cambio de fase seleccionado. Si no se especifica nada, se seleccionar谩n el canal A y la fase 0.
    • Canal – CHANNEL_A, CHANNEL_B o CHANNEL_C (隆vea la tabla de arriba!)
    • Fase – valor num茅rico 0-359.
  • disableISR ( canal ) ;- deshabilitar interrupciones en el canal seleccionado. Si no se especifica nada, se seleccionar谩 el CHANNEL_A.

La biblioteca proporciona acceso directo a la interrupci贸n sin el 芦Arduino禄 attachInterrupt, lo que reduce el tiempo necesario para llamar a la funci贸n del controlador de interrupciones. Una interrupci贸n con una frecuencia configurada se procesar谩 en un bloque de la forma ISR ( canal ) {}, ejemplo:

ISR ( TIMER1_A ) { 
// tu codigo
}
ISR ( TIMER1_B ) { 
// tu codigo
}
ISR ( TIMER2_B ) { 
// tu codigo
}
ISR ( TIMER0_A ) { 
// tu codigo
}

Salidas de hardware

  • outputEnable ( canal, modo ) ; – habilitar el control de la salida de hardware del temporizador
    • Canal: CHANNEL_A o CHANNEL_B (y CHANNEL_C para ATmega2560, consulte la tabla de temporizadores).
    • Modo: TOGGLE_PIN, CLEAR_PIN, SET_PIN (alternar / deshabilitar, valor Bajo / habilitar pin por temporizador, valor Alto)
  • outputDisable ( canal ) ; – deshabilitar la salida del temporizador
    • Canal: CHANNEL_A o CHANNEL_B (y CHANNEL_C para Mega2560, consulte la tabla de temporizadores)
  • outputState ( canal, estado ) ;- cambiar manualmente el estado del canal. Por ejemplo, establecer canales en diferentes estados para comenzar a generar una onda push-pull.
    • Canal: CHANNEL_A o CHANNEL_B (y CHANNEL_C para ATmega2560, consulte la tabla de temporizadores).
    • Condici贸n: ALTO o BAJO

Importante: al generar una onda cuadrada, la frecuencia real ser谩 la mitad de la especificada debido a las peculiaridades del propio temporizador. Vea ejemplos con ondas mas abajo.

Cambio de fase (desde 1.6)

Con ayuda PhaseShift ( fuente, 谩ngulo ) puede cambiar las interrupciones o cambiar los pines en el canal seleccionado, fuente – en fase, 谩ngulo – 谩ngulo de cambio en grados de 0 a 360.

  • Para los temporizadores de 8 bits, puede establecer el desplazamiento solo para el segundo canal (CHANNEL_B)
  • Los de 16 bits pueden mover los tres canales.

Configuraci贸n predeterminada

Usando el m茅todo聽setDefault ()聽puede restablecer la configuraci贸n del temporizador a los valores predeterminados de Arduino: frecuencia y modo de funcionamiento.

Ejemplo de todas las funciones de la biblioteca comentadas

// Demostraci贸n de todas las funciones de la biblioteca
#include "GyverTimers.h"
void setup() {
  // Reconfigure el temporizador y establezca un per铆odo o frecuencia
  // Todas las funciones devuelven un per铆odo / frecuencia real, que puede diferir de los ingresados
  Timer2.setPeriod(1000);          // Establezca un per铆odo espec铆fico de 1000 渭s (~ 1000 Hz), devolver谩 el per铆odo real en 渭s
  Timer0.setFrequency(250);        // Establezca la frecuencia de interrupci贸n del temporizador en Hz, devolver谩 la frecuencia real en hercios
  Timer1.setFrequencyFloat(50.20); // Establezca la frecuencia con mayor precisi贸n, en n煤meros fraccionarios, relevante para bajas frecuencias y temporizador 1
  // A partir de este momento, el temporizador ya se ha reconfigurado y funciona con la frecuencia / per铆odo seleccionado
  // Conecta una interrupci贸n del temporizador, a partir de este momento se empezar谩n a llamar las interrupciones
  Timer0.enableISR();              // Conectar la interrupci贸n est谩ndar, canal A, sin desplazamiento de fase
  Timer2.enableISR(CHANNEL_B, 180); // Conecte el temporizador de interrupci贸n 2, canal B, fase inicial - 180 grados
  Timer1.enableISR(CHANNEL_A, 60); // 隆Conecte el canal de interrupci贸n A, configure la fase para el canal A disponible solo para el temporizador 1!
  Timer1.enableISR(CHANNEL_B, 120); // Conecta la segunda interrupci贸n del temporizador 1 y establece el cambio de fase para esta secuencia
  // La interrupci贸n ya comenzar谩 a llamarse
  // Si de repente es necesario desactivar la interrupci贸n sin detener el temporizador
  Timer1.disableISR(CHANNEL_B);
  // A partir de ahora, la interrupci贸n B ya no se llamar谩
  // Si necesita suspender el temporizador COMPLETAMENTE, el hardware
  Timer2.pause();
  // A partir de este momento, el temporizador est谩 en su lugar, el contenido del contador permanece intacto
  // Ahora el temporizador puede volver al servicio
  Timer2.resume();
  // El cron贸metro sigue contando desde el mismo lugar
  // Si necesita detener completamente el temporizador y restablecer el contenido del contador
   Timer1.stop();
  // El temporizador est谩 encendido, el contador se reinicia
  // Devuelve el temporizador a cero
  Timer1.restart();
  // El temporizador se reinicia, comienza a contar desde el principio
  // Si necesita devolver el Arduino est谩ndar - configuraci贸n del temporizador
  Timer0.setDefault();
  // Ahora el temporizador funciona en modo est谩ndar
}
//vectores interrumpcion
ISR ( TIMER1_A ) { 
}
ISR ( TIMER1_B ) { 
}
ISR ( TIMER2_B ) { 
}
ISR ( TIMER0_A ) { 
}
void loop() {
}

Ejemplo sencillo con interrupciones

// Un ejemplo de una generaci贸n de interrupciones simple por un temporizador de hardware
#include "GyverTimers.h"
void setup() {
  Serial.begin(9600);
  Timer1.setFrequency(3);             // Temporizador 1 de alta precisi贸n para la primera interrupci贸n, frecuencia - 3 Hertz
 //Timer1.setPeriod(333333); // 隆mismo! La frecuencia de 3 Hz es un per铆odo de 333 333 microsegundos
 //Timer1.setFrequencyFloat(4.22); // Si necesita una frecuencia fraccionaria en Hz  
  Timer1.enableISR();              // Iniciar interrupci贸n (canal A predeterminado)
  // inicia el segundo temporizador
  Timer2.setPeriod(1000000);   // Establece el per铆odo del temporizador 1000000 渭s -> 1 Hz
  Timer2.enableISR(CHANNEL_A);  // O simplemente .enableISR (), activa una interrupci贸n en el canal A del temporizador 2
   pinMode(13, OUTPUT);         // parpadear谩 led
}
void loop() {}
// Interrumpcion en temporizador 1
ISR ( TIMER1_A ) { // escribir en la serie  
  Serial.println("timer1");
}
//Interrumpcion en temporizador 2
ISR ( TIMER2_A ) { // genera una onda cuadrada de 1 khz, parpadea   
  digitalWrite ( 13 ,! digitalRead ( 13 )) ;
  //Serial.println("timer2 ");
}

Interrupci贸n sencilla en dos canales

// Un ejemplo de generaci贸n de interrupciones de dos canales en un temporizador con un per铆odo EQUAL, pero fuera de fase
// dos flujos de interrupci贸n desplazados 180 grados (inversi贸n completa)
#include "GyverTimers.h"
void setup() {
  Serial.begin(9600);
  Serial.print("Real timer frequency is : ");       // Muestra la frecuencia real, la real puede diferir de la dada (limitada por la resoluci贸n del temporizador)
  Serial.println(Timer1.setFrequencyFloat(2.50));   // La frecuencia de interrupci贸n es de 2.5 Hz, use .setFrequency (...) para enteros
  delay(1000);
  Timer1.enableISR(CHANNEL_A, 0);     // El primer canal es A, la fase inicial es 0 grados
  Timer1.enableISR(CHANNEL_B, 180);   // El segundo canal es B, la fase inicial es de 180 grados
}
void loop() {} 
// dos interrupciones en un temporizador
ISR ( TIMER1_A ) { 
  De serie. println ( "隆Interrupci贸n del canal A!" ) ;  // Interrumpcion A
}
ISR ( TIMER1_B ) { 
  De serie. println ( "隆Interrupci贸n del canal B!" ) ;  // Interrumpcion B
}

Generaci贸n de una Onda

// Un ejemplo de generaci贸n de un onda en el temporizador 2, canal B (D3 en Arduino UNO) 
#include "GyverTimers.h"
void setup() {
  pinMode(3, OUTPUT);                          // configurar pin como salida
  // debido a la peculiaridad de generar un meandro por el temporizador
  // 隆la frecuencia debe especificarse el doble de lo necesario!
  Timer2.setFrequency(500 * 2);               // establece la frecuencia del temporizador en Hz
  Timer2.outputEnable(CHANNEL_B, TOGGLE_PIN);  // en el momento en que se activa el temporizador, el pin cambiar谩
}
void loop() { 
}

Deja un comentario