Timers
El ATmega328P cuenta con 3 temporizadores o contadores (cuando se utiliza una fuente externa), el Timer0 y Timer 2 de 8 bit y Timer3 de 16 bit. Tambi茅n tienen la posibilidad de generar PWM de periodo variable.
Fuente de reloj interna o externa
Todos los timer pueden utilizar la fuente interna del microcontrolador $clk_{I/O}$, pero tambi茅n pueden utilizar fuentes de reloj externas. En el caso de los timer 0 y 1 la fuente externa es s铆ncrona, puesto que el microcontrolador realiza un muestreo en el pin T0/T1
de la se帽al externa de reloj $clk_{T0S}$ / $clk_{T1S}$ en cada ciclo m谩quina. Debido al proceso mediante el cual se realiza la detecci贸n de flanco (ascendente o descendente), la frecuencia m谩xima de la fuente externa es menor a $\frac{f_{\text{clk}_\text{I/O}}}{2.5}$ como se explica en el datasheet (pag.114).
La fuente de reloj se selecciona mediante los bits CS02:0
/CS12:0
del registro TCCR0B
/TCCR1B
como se muestra en la siguiente tabla:
CS02 /CS12 |
CS01 /CS11 |
CS00 /CS10 |
Descripci贸n |
---|---|---|---|
0 | 0 | 0 | Sin fuente de reloj (paro) |
0 | 0 | 1 | $\text{clk}_\text{I/O}/1$ (sin preescalamiento) |
0 | 1 | 0 | $\text{clk}_\text{I/O}/8$ |
0 | 1 | 1 | $\text{clk}_\text{I/O}/64$ |
1 | 0 | 0 | $\text{clk}_\text{I/O}/256$ |
1 | 0 | 1 | $\text{clk}_\text{I/O}/1024$ |
1 | 1 | 0 | Fuente de reloj externa en T0/T1 de flanco descendente |
1 | 1 | 1 | Fuente de reloj externa en T0/T1 de flanco ascendente |
El Timer2 est谩 conectado por default a $\text{clk}_\text{I/O}$, sin embargo tiene un modo de operaci贸n as铆ncrona que utiliza 煤nicamente una se帽al de reloj externa. Esta se activa mediante el bit AS2
del registro ASSR
. Entonces se utiliza el cuarzo externo que se utiliza entre los pines TOSC1
y TOSC2
que est谩 optimizado para un cristal de $32.768\ \text{kHz}$. Las ventajas de esto es que se puede utilizar el timer 2 como un contador en tiempo real, adem谩s seguir铆a funcionando en modo de suspensi贸n del microcontrolador.
El preescalador del timer 2 se controla por medio de los pines CS22:CS20
del registro TCCR2B
como se muestra en la siguiente tabla ($\text{clk}_\text{TS2}$ es la se帽al de reloj seleccionada para Timer2):
CS22 |
CS21 |
CS20 |
Descripci贸n |
---|---|---|---|
0 | 0 | 0 | Sin fuente de reloj (paro) |
0 | 0 | 1 | $\text{clk}_\text{T2S}/1$ (sin preescalamiento) |
0 | 1 | 0 | $\text{clk}_\text{T2S}/8$ |
0 | 1 | 1 | $\text{clk}_\text{T2S}/32$ |
1 | 0 | 0 | $\text{clk}_\text{T2S}/64$ |
1 | 0 | 1 | $\text{clk}_\text{T2S}/128$ |
1 | 1 | 0 | $\text{clk}_\text{T2S}/256$ |
1 | 1 | 1 | $\text{clk}_\text{T2S}/1024$ |
C谩lculos de tiempo
El tiempo que le toma a cada conteo se calcula de la siguiente forma:
\[t_\text{cont} = (\text{CM})(\text{preescala}) = \frac{1}{f_\text{clk}}(\text{preescala})\]Entonces el tiempo de desbordamiento para cada timer para cada preescala, tomando en cuenta una frecuencia de reloj de $f_\text{clk} = 16 \text{ MHz}$ (Arduino), se muestran en la siguiente tabla:
Preescala | T0 /T2 (8 bit) |
T1 (16 bit) |
---|---|---|
1 | $16 \text{ ns}$ | $4.096 \text{ ms}$ |
8 | $0.128 \text{ ms}$ | $32.768 \text{ ms}$ |
32 | $0.512 \text{ ms}$ | $131.072 \text{ ms}$ |
64 | $1.024 \text{ ms}$ | $262.144 \text{ ms}$ |
128 | $2.048 \text{ ms}$ | $524.288 \text{ ms}$ |
256 | $4.096 \text{ ms}$ | $1048.576 \text{ ms}$ |
1024 | $16.384 \text{ ms}$ | $4194.304 \text{ ms}$ |
Interrupci贸n por desbordamiento
Un desbordamiento del timer ocurre en un evento de conteo cuando el contador ya ha alcanzado su m谩xima capacidad 0xFF
para Timer 0 y 2 y 0xFFFF
para Timer1. Al desbordarse el registro correspondiente a cada timer TCNT
, se reinicia el contador y ocurre una llamada a interrupci贸n que activa la bandera de desbordamiento en el registro TIFR
. Para habilitar las interrupciones por desbordamiento de alg煤n timer, se debe actvar el bit TOIE
de su respectivo registro TIMSK
.
Los registros TCNT
se pueden escribir, por lo que se puede modificar el conteo de los timers para hacer conteos exactos. Entonces si se quisiera la interrupci贸n a s贸lo dos conteos, lo 煤nico que hay que hacer es poner el valor en TCNT
a una unidad menos que su m谩xima capacidad (eg. 256 - 2 = 254 para un timer de 8 bit).
Programaci贸n en C de interrupciones por desbordamiento
Para utilizar las interrupciones por desbordamiento de los timers del ATmega328P en lenguaje C
, se puede seguir este procedimiento:
- Importar la librer铆a
avr/interrupt.c
#include<avr/interrupt.h>
- Definir la rutina de interrupci贸n
ISR
para el vector de interrupci贸n deseadoTIMER0_OVF_vect
/TIMER1_OVF_vect
/TIMER2_OVF_vect
ISR (TIMER0_OVF_vect) { // C贸digo de rutina de interrupci贸n de desbordamiento para TIMER0 } ISR (TIMER1_OVF_vect) { // C贸digo de rutina de interrupci贸n de desbordamiento para TIMER1 } ISR (TIMER2_OVF_vect) { // C贸digo de rutina de interrupci贸n de desbordamiento para TIMER2 }
-
Configurar las interrupciones por desbordamiento y el preescalador
Ejemplo que configura las interrupciones por desbordamiento para el Timer0, con una preescala de 1024 y en la interrupci贸n suma un 1 al PORTD.
int main(void) { cli(); TCCR0B = (1<<CS02)|(0<<CS01)|(1<<CS00); //preescala a 1024 TIMSK0 = (1<<TOIE0); // habilitar interrupci贸n por desbordamiento del timer0 sei(); }
Interrupciones por comparaci贸n
Para cualquiera de los timers, se pueden hacer llamadas a interrupci贸n cuando el contador llega a un valor TCNTx
(x
= 0
,1
,2
) que se iguala a cualquiera de los valores en los registros OCRxA
o OCRxB
. Cuando ocurre un match, la bandera OCFxA
o OCFxB
se levanta en el siguiente ciclo m谩quina y se hace la llamada a la respectiva interrupci贸n, si est谩 habilitada por medio de los bits OCIExA
y OCIExB
del registro TIMSKx
Programaci贸n en C de interrupciones por comparaci贸n del timer
-
Importar la librer铆a
avr/interrupt.c
#include<avr/interrupt.h>
-
Definir la rutina de interrupci贸n
ISR
para el vector de interrupci贸n deseadoTIMERx_COMPA_vect
/TIMERx_COMPB_vect
ISR (TIMER0_COMPA_vect) { // C贸digo de rutina de interrupci贸n de comparaci贸n en OCR0A para TIMER0 } ISR (TIMER0_COMPB_vect) { // C贸digo de rutina de interrupci贸n de comparaci贸n en OCR0B para TIMER0 }
-
Configurar las interrupciones por desbordamiento y el preescalador
Ejemplo que configura las interrupciones por comparaci贸n de
OCR0A
yOCR0B
para el Timer0, con una preescala de 1024.int main(void) { cli(); TCCR0B = (1<<CS02)|(0<<CS01)|(1<<CS00); //preescala a 1024 TIMSK0 = (1<<OCIE0A)|(1<<OCIE0B); // habilitar interrupci贸n por comparaci贸n del timer0 para OCR0A y OCIE0B OCR0A = 0xF0 // Valor de comparaci贸n OCR0A OCR0B = 0x0F // Valor de comparaci贸n OCR0B sei(); }
Modos de operaci贸n
Los modos de operaci贸n se definen con los bits WGMx2
del registro TCCRxB
en conjunto con los bits WGMx1:0
del registro TCCRxA
como se muestra en la tabla 14-8 del datasheet. En estas notas no se explican todos los modos de operaci贸n.
Modo CTC
El modo Clear Timer on Compare match o CTC por sus s铆glas en ingl茅s, permite reiniciar el contador al alcanzar el valor en OCRxA
. Aunque esto puede hacerse de forma manual por medio de la interrupci贸n por comparaci贸n, se gastan muchos m谩s ciclos de m谩quina. Utilizar el modo CTC es mucho m谩s r谩pido pues es en hardware.
Esto sirve para poder variar la frecuencia de las interrupciones. Adem谩s, esto permite generar una se帽al de onda cuadrada de frecuencia variable como se ve en la figura 14-5 del datasheet. Para esto, se puede configurar el microcontrolador para que cambie el nivel l贸gico en el pin autom谩ticamente al ocurrir el match, tanto para el pin OCxA
como el OCxB
, siempre y cuando estos pines est茅n configurados como salidas. Esto se hace mediante los pines COMxA1:0
y COMxB1:0
del registro TCCRxA
con cualquiera de las configuraciones de la tabla 14-2 del datasheet.
Generando una forma de onda cuadrada de frecuencia variable, de forma tal que hace un toggle en cada match. Para calcular la frecuencia de dicha onda, se ocupa la siguiente f贸rmula:
\[f_{OCn} = \frac{f_{clk I/O}}{2N(1+OCRn)}\]Donde:
$N$ es la preescala
$OCRn$ es el valor en OCRxA
/OCRxB
Modo PWM
El ATmega328P tiene dos modos de PWM, el de fase correcta y PWM r谩pido. La diferencia es que el de fase correcta sube hasta el valor m谩ximo del contador y luego decrementa, mientras que el segundo se desborda. Esto hace que uno sea el doble de r谩pido que el otro.
Debido a la velocidad a las que pueden variar los dominios magn茅ticos de un material, tienen un l铆mite en la frecuencia que pueden manejar. Por lo mismo, los motores tienen ese l铆mite y hay que tenerlo en cuenta al elegir el PWM.
El modo PWM funciona haciendo que el contador cuente en subida y bajada constantemente, switcheando al cruzar TCNTx
con el valor del pin OCxA
/OCxB
. Es decir, se modula el duty cicle con el valor de OCxA
/OCxB
. Cuando es 0
se mantiene una se帽al baja en la salida, cuando es 255
se tiene un duty cicle de 100\% y la salida es alta constante.
La frecuencia del PWM puede cambiar si se selecciona WGM2:0 = 5
a diferencia de WGM2:0 = 1
, porque hace que el valor m谩ximo de conteo es el almacenado en OCxA
.
La frecuencia del PWM se calcula como:
\[f_{PWM} = \frac{f_\text{CLKI/O}}{N\times 510}\]En el datasheet p谩g. 81, se explica m谩s a detalle este modo de operaci贸n. Es importante recalcar que el timer 1 tiene m谩s opciones de configuraci贸n para el PWM.