Beruflich Dokumente
Kultur Dokumente
Contenido
Introduccin
El Timer0 y el Timer2
El Reloj del Timer0 y del Timer2
El Prescaler del Timer0 y del Timer2
Modos de Operacin del Timer0 y Timer2
El Timer0 y el Timer2 en Modo Normal
o Clculo de la Temporizacin Normal
El Timer0 y el Timer2 en Modo CTC
o Clculo de la Temporizacin CTC
Interrupciones del Timer0 y el Timer2
El Timer0 y el Timer2 Como Contadores
El Timer0 y el Timer2 en Modo PWM
Prctica: Temporizacin con Sondeo del Timer0
Prctica: Interrupcin del Timer0
Prctica: El Timer0 en Modo CTC
Prctica: Control de Potencia
Prctica: El Timer0/2 Como Contador
Registros del Timer0
o TCCR0A
o TCCR0B
o TCNT0
o OCR0A
o OCR0B
o TIMSK0
o TIFR0
o GTCCR
Registros del Timer2
o ASSR
El Timer1 y el Timer3
El Timer1 y el Timer3 en Modos Normal y CTC
El Timer1 y el Timer3 en Modo PWM
o Fast PWM
o PWM de Fase Correcta
o PWM de Fase y Frecuencia Correctas
Registros del Timer1
o TCCR1A
o TCCR1B
o TCCR1C
o TCNT1H y TCNT1L
o OCR1AH y OCR1AL
o OCR1BH y OCR1BL
o ICR1H y ICR1L
o TIMSK1
o TIFR1
o GTCCR
Registros del Timer3
Practica: Timer1 en PWM
Introduccin
Los Timers son mdulos que trabajan en paralelo con el procesador, permitiendo
que las operaciones de temporizacin y conteo se puedan llevar a cabo de manera
eficiente, mientras el procesador se ocupa de otras tareas.
Normalmente los megaAVR cuentan con tres Timers, llamados Timer0, Timer1 y
Timer2. A veces desaparece el Timer2 y otras veces aparece adicionalmente el
Timer3 o el Timer4. Todos los Timers pueden trabajar en modo de PWM pero esta
funcionalidad est mejor implementada en unos Timers (1 y 3) que en otros. Por
su relativa limitacin, el Timer0 est ms destinado a las temporizaciones y
otro tanto a los conteos. El Timer2 por su parte fue diseado con la
caracterstica adicional para trabajar con un XTAL de reloj externo, de 32kHz.
A pesar de sus diferencias operativas, la configuracin y control de los Timers
son muy similares en todos los casos, as que por ms que sean varios
aprenderemos a controlarlos todos con el menor esfuerzo. Bueno, eso espero.
Supongo que lo comn debe ser conocer los Timer de a uno, empezando por el
Timer0 hasta llegar al Timer3 o 4, si es que se llega. Pero despus de revisar
los diversos datasheets, creo que un mejor enfoque ser abarcarlos de a dos,
segn su nmero de bits. Esto nos permitir evitar las redundancias.
En primer lugar nos ocuparemos de los Timers de 8 bits, o sea, del Timer0
y del Timer2.
Luego estudiaremos los Timers de 16 bits, que son el Timer1 y el Timer3.
3
El Timer0 y el Timer2
Dada la paridad de caractersticas entre el Timer0 y el Timer2, no las vamos a
mencionar simultneamente para no fatigarnos de trminos. Simplemente vamos a
referirnos al Timer0 y se dar por hecho que lo mismo es aplicable para el
Timer2, salvo que se indique explcitamente lo contario. Las principales
diferencias se dejarn notar solo al inicio y al final, luego el tratamiento
ser muy parejo.
Naturalmente, el
trato especfico
preocupacin pues
registro y bit de
Queda claro entonces que bastar con referirnos al Timer0, entendiendo que las
mismas caractersticas, ventajas y limitaciones citadas sern igualmente
aplicables al Timer2, salvo, repito, que se indique lo contrario. Empecemos,
entonces.
El nombre completo del Timer0 es Timer/Counter0 o Temporizador/Contador 0, pero
por comodidad nos referimos a l simplemente como Timer0.
Dicen que un diagrama vale ms que mil palabras, as que el siguiente esquema
nos ayudar para entender la operacin comn del Timer0. Las operaciones
especficas de cada modo particular las describiremos en su momento.
Con sus 8 bits, el Timer0 puede contar en todo su rango, o sea, entre 0
hasta 255. Cuando el Timer0 opera solo en modo ascendente y llega a su
valor mximo de 255, continuar despus contando desde 0 otra vez,
cclicamente. Esta transicin de 255 a 0 es el famoso Desbordamiento y es
un concepto clave en los Timers. El desbordamiento del Timer0 activa el
bit de flag TOV0. Tambin es posible hacer que el Timer0 cuente solo hasta
un tope establecido por registro OCR0A.
Los bits CS (de Clock Select). Los bits CS02, CS01 y CS00 se encargan de
configura todo los relacionado con el reloj y el prescaler del Timer.
Los bits WGM (de Waveform Generator Mode). Los bits WGM02, WGM01 y WGM00
trabajan con los comparadores para producir ondas cuadradas de acuerdo con
la configuracin de los bits. En realidad, su funcin implica ms que eso,
pues establecen el modo en que operar el Timer0, ya sea modo Normal, CTC
o PWM.
Los bits COM (de Compare Output Mode). Son los bits COM0A1 y COM0A0 los
que en ltima instancia deciden si las ondas generadas por los
comparadores salen o no por los pines OC0A y OC0B del AVR. El tipo de onda
ms popular es PWM y es habitualmente el nico caso en que se dejan salir
las ondas. Cuando el Timer0 va a trabajar como simple contador o
temporizador, los bits COM quedan con su valor por defecto de 0, con lo
cual los pines OC0A y OC0B quedan desconectados del Timer y se pueden
seguir usando como puertos de E/S generales.
Reloj Interno. Aqu el reloj del Timer0 deriva del mismo oscilador interno
del sistema F_CPU. Como se ve en la figura, en este caso la seal pasa
previamente por el prescaler, que puede dividir la frecuencia de F_CPU por
un valor seleccionado por nosotros. Los prescalers del Timer0 y del Timer2
no son idnticos, aunque tengan los bits de control similares. Pero siendo
este reloj el que se usa con regularidad, ya sea para las temporizaciones
o para generar ondas PWM, sobrar espacio para familiarizarnos con estas
ligeras diferencias.
7
Como puedes ver, los bits CS se encuentran en los registros TCCRxB de cada
Timer, sin embargo, por ms que sean casi iguales, tiene efectos diferentes
debido a que los prescalers son diferentes. El prescaler del Timer2 es ms
sencillo y completo, pero empezaremos por explicar el prescaler del Timer0.
El prescaler del Timer0 es compartido con el Timer1 (y qu tiene que ver en
todo esto el Timer1?). De acuerdo con la figura, es posible que los dos Timers
operen simultneamente con el prescaler y utilizando diferentes factores de
divisin puesto que cada Timer tiene sus propios bits CS (de Clock Select). El
nico reparo sera que se debe tener cuidado al resetear el prescaler porque
para esto se dispone de una nica seal PSRSYNC. Es un reset SYNCrono porque el
Timers0 y el Timer1 trabajan siempre sincronizados con el reloj del sistema
F_CPU, hasta cuando su reloj proviene de los pines T0 o T1, respectivamente. El
bit PSRSYNC se encuentra en el registro GTCCR.
Modo Normal
Modo CTC
Modo PWM
Cada modo tendr sus variantes dependiendo del Timer. Por ejemplo, en el Timer1
existen hasta 12 modos PWM, pero bueno, de eso nos ocuparemos en su momento.
10
Diagrama de bloques del Timer0.
La figura nos resalta que esta vez vamos a trabajar con los bits WGM. Su nombre
viene de Waveform Generation Mode porque estos bits pre-establecen el tipo de
onda que podr generar el Timer0 por los pines OC0A y OC0B. En la prctica es
raro utilizar otras formas de onda que no sean de tipo PWM, as que el nombre
no parece muy apropiado.
En la figura tambin se aprecia que los GENERADORES DE ONDA tambin dependen de
los bits COM (de Compare Output Mode). Estos bits establecen el modo en que
finalmente saldrn las ondas por los pines OC0A y OC0B, es decir, pueden salir
normales, invertidas, o pueden simplemente no salir y dejar los pines OC0x
libres para otras tareas. A lo que quiero llegar es que al menos en cursomicros
los bits COM solo se usan en modo PWM. En los modos Normal y CTC nos olvidamos
de ellos.
Los bits WGM estn distribuidos en los dos registros de control del Timer0,
TCCR0A y TCCR0B. El hecho de que el bit WFG02 est en TCCR0B y no junto con sus
pares en TCCR0A habiendo espacios vacos all se debe a cuestiones de
compatibilidad con otros AVR.
11
En modo Normal el Timer0, habilitado, avanza libre y cclicamente en todo su
rango, es decir, su registro TCNT0 cuenta desde 0x00 hasta 0xFF, luego se
desborda para volver a iniciar desde 0x00.
El desbordamiento del Timer activa el flag TOV0 del registro TIFR0 el cual
puede programarse para disparar interrupciones. Como el registro TCNT0 es de
lectura y escritura podemos en cualquier momento modificar su valor y as
recortar los periodos de conteo para calibrar o ajustar las temporizaciones.
El Timer0 siempre inicia detenido, as que para que se cumpla todo lo descrito
primero habr echarlo a andar configurando los bits de reloj CS, segn lo
estudiado en fuentes de reloj y prescalers.
Recordemos que los comparadores del Timer0 pueden sacar por los pines OC0A y
OC0B unas seales que se pueden configurar con los bits COM. En los modos
Normal o CTC esta seal se forma poniendo a cero, a uno, o conmutando el valor
de OC0A/OC0B. Todas las opciones posibles se muestran en la siguiente tabla.
Para temas de temporizacin, que es normalmente el propsito del modo Normal o
CTC, debemos escoger la primera opcin, que es la predeterminada y que nos
dejar los pines OC0A/OC0B libres para seguir usndolos como puertos de E/S
generales.
12
Bueno, asumo que en este momento ya sabemos cmo configurar el reloj del Timer0
bits CS), que sabemos cmo programar el Timer0 en modo Normal (bits WGM) y que
entendemos su operacin en ese modo. Ahora aprenderemos a escoger la opcin de
reloj ms adecuada para nuestras temporizaciones.
Para empezar, debemos usar el reloj interno derivado de F_CPU (cuyo valor es
tericamente igual a la frecuencia del XTAL del megaAVR.), salvo que tengamos
una seal externa peridica. Como sabemos, si la fuente de reloj es interna, el
Timer0 y el Timer2 se programan igual. Lo nico que cambiar sern los factores
de prescaler.
En primer lugar veamos cmo avanza el Timer0. Por ejemplo, si tenemos un XTAL
de 8 MHz y no usamos prescaler, entonces el reloj del Timer0 ser de 8 MHz y el
registro TCNT0 se incrementar cada 1/8MHz = 128ns, lo mismo que un ciclo de
instruccin bsica. Pero si usamos el factor de prescaler 8, TCNT0 avanzar
cada 1us. Si usamos el factor de prescaler de 256, TCNT0 avanzar cada 32us. Y
si cambiamos de XTAL, los tiempos sern otros.
Ahora
TCNT0
TCNT0
de 8,
Al inicio todos vemos en esto un enredo de nmeros. Parece complejo pero solo
es cuestin de encontrar el hilo de la madeja para suspirar diciendo Ah, era
as de fcil! Sin embargo, hay quienes se rinden y prefieren usar frmulas y
clculos directos como los descritos a continuacin.
Bueno, vamos al grano. El Tiempo que pasar el Timer0 contando desde un valor
inicial TCNT0 hasta 255 y se produzca el desbordamiento est dado por la
frmula:
13
Nota: los factores de prescaler N del Timer2 son 1, 8, 32, 64, 128, 256 y 1024.
Eso podra dar otras soluciones para N y TCNT2.
Como ves, sta es una ecuacin con dos incgnitas (N y TCNT0) y es posible
encontrar ms de una solucin para ambas. Sin embargo, no todas sern
igualmente adecuadas. Los valores ms apropiados sern los que nos permitan
realizar un mejor posterior ajuste de precisin. Si eres ducho resolviendo
ecuaciones de Diofanto, puedes trabajar con esa frmula.
Pero si no quieres ir tanteando, puedes emplear las siguientes dos frmulas:
(He borrado todas sus deducciones para no alargar ms esta seccin.)
14
15
Y ahora de dnde vamos a sacar un factor de prescaler mayor que 3906.25 si el
mximo es de 1024? Buscamos otro Timer? Bueno, quiz podramos temporizar 10
veces 5 ms.
16
registro OCR0A, es decir, aunque es posible que se activen los flags OCF0A y/o
OCF0B, y se disparen inclusive sus interrupciones correspondientes, el Timer0
solo se resetea en su Coincidencia con OCR0A.
Las aplicaciones del modo CTC son similares a las del modo Normal, o sea, las
temporizaciones. Sin embargo, hay una diferencia que representa una ventaja o
desventaja, segn se vea. La auto-recarga del Timer0 en modo CTC es un suceso
hardware que genera las ms precisas temporizaciones independientemente de si
el cdigo est escrito en ensamblador, en un compilador o en otro. Pero la no
necesidad de posteriores calibraciones software tambin implica que si la
temporizacin obtenida no es la deseada, entonces no ser posible ajustar su
valor, a menos que volvamos a modificar el registro TCNT0, lo cual
desnaturaliza este modo.
Nota: los factores de prescaler N del Timer2 son 1, 8, 32, 64, 128, 256 y 1024.
Eso podra dar otras soluciones para N y TCNT2.
De nuevo, esta ecuacin tiene dos incgnitas (N y OCR0A).
Como antes, es
posible descomponerla en dos ecuaciones de una variable. La primera, para
hallar N, es igual que en el modo Normal. De no resultar un valor exacto,
tambin aqu debemos tomar el factor de prescaler superior ms cercano.
inicial.
Se
17
OCR0A que valga, de modo que ser de poco alivio para el diseador redondearlo
a su valor ms cercano, superior o inferior. En ese caso y si la precisin
fuera realmente importante, se puede optar por cambiar de XTAL.
Ya no vamos a poner ejemplos porque estas frmulas se resuelven exactamente
igual que en el Clculo de las Temporizaciones en Modo Normal.
TIMSK0 (Timer Interrupt Mask Register 0). Contiene los bits Enable de
interrupciones.
TIFR0 (Timer Interrupt Flags Register 0). Contiene los bits de Flag de
interrupciones.
Para quienes an trabajan con los viejos megaAVR, ellos no tienen interrupcin
en coincidencia B, los bits de la coincidencia A son simplemente OCIE0 y OCF0,
y los siguientes registros se llaman TIMSK y TIFR. No llevan el 0 porque
tambin controlan las interrupciones del Timer1 y del Timer2.
18
Interrupcin por Desbordamiento del Timer0. El evento que puede disparar esta
interrupcin es el desbordamiento del registro TCNT0, o sea, la transicin de
255 a 0. Esto implica la operacin incremental del Timer0, sin importar si est
contando en modo Normal, CTC o Fast PWM. En modo PWM de Fase Correcta el Timer0
cuenta en sube y baja sin pasar por la transicin 255 a 0, as que en este modo
no hay desbordamiento.
El desbordamiento de Timer0 activar el flag TOV0 y si la interrupcin est
habilitada, se disparar. El bit TOV0 se limpia automticamente al ejecutarse
su funcin de interrupcin ISR, pero tambin se puede limpiar por software,
como de costumbre, escribindole un 1 y sin usar instrucciones de lecturamodificacin-escritura como las generadas por las sentencias con el operador OR
binario (|).
Para habilitar la interrupcin por Desbordamiento del Timer0 se setean los bits
TOIE0 y obviamente, el bit enable general de interrupciones I, del registro
SREG. La instruccin del ensamblador dedicada a esta operacin es SEI y que en
lenguaje C se puede incrustar mediante la funcin macro del mismo nombre sei().
(No s por qu repito estas cosas.)
Interrupcin en Coincidencia del Timer0. Como sabemos, los comparadores del
Timer0 son circuitos que en todo momento estn comparando los valores del
registro TCNT0 con los registros OCR0A y OCR0B. Pues bien, el evento que puede
disparar esta interrupcin es la coincidencia entre los registros mencionados.
Como
puede
haber
interrupciones.
dos
coincidencias,
aqu
podemos
tener
hasta
dos
19
Timer y tambin a las diferencias entre el Timer0 y el Timer2 cuando sus
relojes son externos.
Antiguamente el Timer2 estaba ms bien pensado para ser usado con un XTAL
externo de reloj (de 32 kHz) conectado a los pines TOSC1 y TOSC2 del AVR. De
ah sus caractersticas para trabajar asncronamente con el reloj del sistema.
Esa era su nica forma de soportar un reloj externo, es decir, no poda usarse
para contar pulsos o flancos sueltos. En los viejos AVR el Timer2 es de ese
tipo.
Por fortuna, el Timer2 de los nuevos AVR viene mejor equipado y ofrece la
opcin adicional de trabajar con una seal externa (sin XTAL) aplicada al pin
TOSC1. De ese modo el Timer2 se pone a nivel del Timer0/1. En realidad tiene
una limitacin y una mejora al respecto.
20
Tengamos en cuenta que, siendo el modo Contador una interpretacin particular
del modo Normal, siguen latentes todas las funciones de temporizacin del
Timer0, incluyendo las interrupciones en el Desbordamiento y en las
Coincidencias. De hecho, tambin es posible temporizar con la seal externa,
siempre que sea una onda cuadrada peridica, claro est. La nica consideracin
es que la seal de T0 o T1 jams debera superar, o igualar siquiera, la
performance del reloj del sistema F_CPU, para permitir la sincronizacin entre
ellas. Por otro lado, el reloj externo del timer2 no est sincronizado y en ese
caso la manipulacin de sus registros de datos puede requerir el uso del
registro ASSR.
21
Prctica: Temporizacin con Sondeo del Timer0
El programa genera una onda cuadrada conmuta cada 2.5 ms, pero como ya estamos
en temas serios, la temporizacin debe ser lo ms precisa posible, ni 1 s ms
ni 1 s menos. Visto de otro modo, el programa genera una seal de onda
cuadrada de 200 Hz.
El cdigo fuente
/******************************************************************************
* FileName:
main.c
* Purpose:
Timer0 - Operacin en modo Temporizador
* Processor: ATmega164P
* Compiler:
IAR-C y AVR-GCC (WinAVR)
* Author:
Shawn Johnson. http://www.cursomicros.com.
*
* Copyright (C) 2008 - 2012 Shawn Johnson. All rights reserved.
*
* License:
Se permiten el uso y la redistribucin de este cdigo con
*
modificaciones o sin ellas, siempre que se mantengan esta
*
licencia y la nota de autor de arriba.
*****************************************************************************/
#include "avr_compiler.h"
void Pause(void);
// Prototipo de funcin
//************************************************************************
// Funcin principal
//************************************************************************
int main(void)
{
22
DDRA = 0x01;
// Loop forever
// Conmutar pin PA0
// Delay de 2499.55 us
}
//************************************************************************
// Produce 2499.55 s exactamente
// Con el Prescaler de 256 y con con XTAL de 8 MHz el Timer0 se incrementa
// cada 256/8 = 32 us. Por tanto, para alcanzar 2499.55 s se requieren de
// 2499.55/32 = 78.1 ticks. Ergo, TCNT0 se debe cargar con 256-78.1 = 178
//************************************************************************
void Pause(void)
{
GTCCR = (1<<PSRSYNC);
// Resetaer prescaler
TCNT0 = 178;
// Cargar registro TCNT0
TIFR0 = (1<<TOV0);
// Loop forever
// Conmutar pin PA0
// Delay de 2499.55 us
23
}
El factor de prescaler sera:
24
Por otro lado, el programa tambin har parpadear un LED cada 500 ms, un tiempo
que a priori no se puede conseguir as nada ms. Esto para demostrar que las
temporizaciones no tienen que ser tareas exclusivas.
En el circuito el IRF730 puede ser sustituido por un IRF720, un IRF540 o
cualquier otro similar.
Circuito de la prctica.
El cdigo fuente
/******************************************************************************
* FileName:
main.c
* Purpose:
Interrupcin del Timer0 en Modo Normal
* Processor: ATmega164P
* Compiler:
IAR-C y AVR-GCC (WinAVR)
* Author:
Shawn Johnson. http://www.cursomicros.com.
*
* Copyright (C) 2008 - 2012 Shawn Johnson. All rights reserved.
25
*
* License:
Se permiten el uso y la redistribucin de este cdigo con
*
modificaciones o sin ellas, siempre que se mantengan esta
*
licencia y la nota de autor de arriba.
*****************************************************************************/
#include "avr_compiler.h"
#include "usart.h"
#define MaxDuty
20
// Mximo duty cycle
volatile unsigned char Duty; // Duty cycle actual
/******************************************************************************
* Gestor de Interrupcin por Desbordamiento del Timer0.
* Esta interrupcin se dispara cada 100 s exactamente.
* Genera una seal PWM con una frecuencia de 500 Hz
*****************************************************************************/
ISR (TIMER0_OVF_vect)
{
static unsigned char Dgen = 1;
// Duty generator. Rango = [1:MaxDuty]
static unsigned int ticks = 0;
TCNT0 += 157;
if (Dgen <= Duty)
PORTA |= (1<<0);
else
PORTA &= ~(1<<0);
//
// Rango de Dgen es [1:MaxDuty]
if(++ticks == 5000)
{
PINA = (1<<1);
ticks = 0;
}
}
/******************************************************************************
* Main Function
*****************************************************************************/
int main(void)
{
DDRA = (1<<1)|(1<<0);
// PA0 -> Salida de seal PWM
// PA1 -> Salida LED
Duty = 0;
// Rango = [0 : MaxDuty]
usart_init();
puts("\r\n Interrupcin del Timer0 en Modo Normal \r");
puts("\r\n Control de Motor DC ");
puts("\r\n (+) Aumentar velocidad");
puts("\r\n (-) Disminuir velocidad");
/* Configuracin del Timer0
* - Modo de operacin = Normal
* - Factor de prescaler = 8
*/
TCCR0A = 0x00;
26
TCCR0B = (1<<CS01);
/* Habilitar Interrupcin por Desbordamiento del Timer0 */
TIMSK0 = (1<<TOIE0);
sei();
for(;;)
{
if(kbhit())
{
char k = getchar();
// El valor de Duty est limitado al rango [0 : MaxDuty]
if((k == '+') && (Duty < MaxDuty)) {
Duty++;
}
else if ((k == '-') && (Duty > 0)) {
Duty--;
}
}
}
}
A pesar de que el clculo para TCNT0 result exacto, en el programa tuve que
utilizar 157 para conseguir los 100s buscados. Como se predijo en la teora,
esto se debe a que la temporizacin es muy fina. Pero no solo se usa 157 en vez
de 156 sino que en vez de una recarga directa como TCNT0 = 157 se utiliza una
suma, TCNT0 += 157. Para las temporizaciones peridicas por interrupciones esta
suma ayuda a disminuir las instrucciones de relleno que se deben colocar al
ajustar la precisin. De hecho, como se ve, no tuve que aadir ni siquiera un
nop como en la anterior prctica. Las interrupciones se disparan con total
precisin cada 100us.
27
El hecho de tener que calibrar manualmente ests temporizaciones a pesar de que
los clculos eran precisos se debe a que la sentencia de recarga del
registro TCNT0 no se produce en el preciso instante en que se desborda el
Timer0, puesto que la ejecucin de la funcin de interrupcin ISR implica la
ejecucin de cierto cdigo como el salto a dicha funcin y el almacenamiento
temporal que se hace de algunos datos del programa. Todo esto es cdigo oculto
y se ejecuta muy rpido, pero no tanto como para pasar desapercibido ante
temporizaciones pequeas del orden de los microsegundos. Mientras se ejecuta
ese pequeo cdigo el Timer sigue avanzando de modo que el clculo terico no
siempre se reflejar en la prctica.
Pero no todo es mala noticia. An nos falta experimentar con el modo CTC. En
las siguientes prcticas veremos que el Timer en modo CTC utiliza su recarga
automtica para temporizar mejor sin necesidad de este tipo de ajustes.
Ahora toca pensar en la temporizacin de 500 ms. Con nuestro XTAL de 8MHz y el
mximo factor de prescaler para el Timer0 solo llegaramos a 32.768 ms, que
est bastante lejos de lo que buscamos. Aunque en las mismas condiciones el
Timer1 puede temporizar hasta 8 388 608 ms, aqu vemos que no es necesario
recurrir a l y as lo reservamos para su trabajo por excelencia que son las
ondas PWM.
Bueno, lo que hice en el programa es usar la anterior temporizacin de 100 s
para incrementar el contador ticks. Entonces deducimos que para alcanzar 500
ms, ticks deber llegar a 5000. Y all lo tenemos.
if(++ticks == 5000)
{
PINA = (1<<1);
ticks = 0;
}
28
ahorrar energa. Quiz se deba hacer en una aplicacin final, pero como estas
prcticas son de ejemplo,
Prctica: El Timer0 en Modo CTC
Se utiliza el Timer0 para incrementar dos contadores, uno cada 1ms y el otro
cada 100ms. Los contadores se pueden usar para establecer el tiempo de
ejecucin de otras rutinas. A manera de simple ejemplo, aunque no le encuentro
mucha gracia, aqu se espera por 5 segundos a que el usuario ingrese una
contrasea por el puerto serie para ahorrar en el circuito, pero que bien
podra ser el prototipo de acceso a un sistema digitando la clave en un teclado
matricial por un tiempo establecido. El tiempo se mide a partir del momento en
que se presiona el primer dgito.
Recuerdo haber hecho la pregunta cmo haramos para ejecutar una tarea durante
cierto tiempo?, ya que, obviamente, para esto no se pueden recurrir a los
tpicos delays porque son tiempo muerto y poco precisos. Bueno, pues, en esta
prctica veremos una solucin.
El circuito.
El cdigo fuente
/******************************************************************************
* FileName:
main.c
* Purpose:
Temporizacin con el Timer0 en Modo CTC usando Interrupciones
* Processor: ATmega164P
29
* Compiler:
IAR-C y AVR-GCC (WinAVR)
* Author:
Shawn Johnson. http://www.cursomicros.com.
*
* Copyright (C) 2008 - 2012 Shawn Johnson. All rights reserved.
*
* License:
Se permiten el uso y la redistribucin de este cdigo con
*
modificaciones o sin ellas, siempre que se mantengan esta
*
licencia y la nota de autor de arriba.
*****************************************************************************/
#include "avr_compiler.h"
#include "usart.h"
char GetNumStr(char *, unsigned char);
volatile unsigned char ticks_ms;
volatile unsigned char ticks_100ms;
/******************************************************************************
* Gestor de Interrupcin en Coincidencia del Timer0.
* Esta funcin se ejecuta cada 1 ms exactamente.
*****************************************************************************/
ISR (TIMER0_COMPA_vect)
{
static unsigned char i;
ticks_ms++;
if(++i >= 100)
{
// Este bloque se ejecuta cada 100 ms
ticks_100ms++;
i = 0;
}
}
/******************************************************************************
* Main Function
*****************************************************************************/
int main(void)
{
const char psw[11] = "1234"; // password actual
char buffer[11];
DDRA = (1<<0);
usart_init();
puts("\r\n Temporizacin con el Timer0 en Modo CTC usando Interrupciones");
/* Configuracin del Timer0
* - Modo de operacin
= CTC
* - Factor de prescaler
= 64
* - Periodo de auto-reset = 1 ms
*/
TCCR0A = (1<<WGM01);
TCCR0B = (1<<CS00)|(1<<CS01);
OCR0A = 124;
// Lmite de TCNT0
/* Habilitar Interrupcin en Coincidencia del Timer0 */
TIMSK0 = (1<<OCIE0A);
sei();
30
for(;;)
{
start:
GetNumStr(buffer, 0);
// Reset internal counter
puts("\r\r Ingrese su password \r ");
while(kbhit() == 0);
// Esperar a que lleguen datos al puerto serie
GTCCR = (1<<PSRSYNC);
// Resetaer prescaler
TCNT0 = 0;
// Resetear registro TCNT0
ticks_100ms = 0;
do {
// Estas rutinas se ejecutan durante 5 segundos.
// Hasta que ticks_100ms = 50 (50100ms = 5 segundos).
if(GetNumStr(buffer, 10))
// Si se leyeron hasta 10 nmeros
{
if(strcmp(buffer, psw)==0) {
puts(" Password OK");
PORTA |= (1<<0);
// Prender LED de PA0
puts("\r Presione una tecla para salir");
getchar();
PORTA &= (~1<<0);
// Apagar LED de PA0
goto start;
}
else{
puts(" Error");
goto start;
}
}
}while(ticks_100ms < 50);
puts("\r Timer out ");
}
}
//****************************************************************************
// Lee una cadena de texto de 'len' nmeros
// El tamao de 'buffer' debe ser mayor que 'len'.
//****************************************************************************
char GetNumStr(char * buffer, unsigned char len)
{
char c; static unsigned char i=0;
if(len==0) i=0;
if(kbhit()) {
c = getchar();
if((c<='9'&&c>='0')&&(i<len)) {
// Si c est entre 0 y 9
buffer[i++] = c;
// Guardar en buffer
putchar(c);
// Eco
}
else if((c=='\b')&&(i)) { // Si c es RETROCESO y si i>0
i--;
//
putchar(c);
// Eco
}
else if((c=='\r')&&(i)) { // Si c es ENTER y si i>0
buffer[i] = '\0';
// Poner un 0x00 (fin de cadena)
putchar(c);
// Eco
i = 0;
// Resetear contador
return 1;
// Retornar con 1
}
}
return 0;
// Retornar con 0
}
31
Descripcin del programa
La Interrupcin
CTC
o
en
Coincidencia
del
Timer0 incrementa
los
contadores ticks_ms yticks_100ms. Creo que es obvio cada cunto tiempo se
incrementan. Para generar el tiempo base de 1ms los valores de prescaler N del
registro OCR0A los obtuve con las formulas presentadas en la seccinClculo de
la Temporizacin en Modo CTC.
Observa que el clculo sali preciso y esos mismos valores son los que aparecen
en el programa. La temporizacin es precisa y no hay que preocuparse por
recargas ni ajustes, ni nada. Genial, verdad?
Para terminar esto quiero mencionar que el factor de prescaler usado es
bastante grande como para que el prescaler avance unos varios ticks que pueden
adelantar la temporizacin. En la simulacin vi que en vez de la espera de 5
segundos solo se cronometraban 4.973 segundos, as que tuve que resetear el
prescaler y con eso el problema se arregl.
GTCCR = (1<<PSRSYNC);
// Resetaer prescaler
Por supuesto que he dramatizado el tema, pero quise destacarlo para recordar
que si bien puede haber otras aplicaciones donde s resulte realmente serio, se
debe pensar bien antes de hacerlo porque el prescaler es tambin compartido por
el Timer1. Por ejemplo, si tuviera el Timer1 trabajando en modo PWM, yo no me
atrevera a resetear el prescaler.
Prctica: Control de Potencia
Un poco ms adelante nos dedicaremos a los motores DC. Pero antes me parece
interesante controlar la velocidad de un pequeo motor AC monofsico o de algn
dispositivo de potencia que no genere mucho ruido como por ejemplo una tpica
bombilla de 100W. Bueno yo s que en estos tiempos eso ya no es nada tpico,
pero la idea es variar la alimentacin de 220V o 110V de la red domstica para
controlar un dispositivo de ese calibre.
El circuito no est blindado para filtrar los ruidos que pueden generar los
motores AC de cierta magnitud, as que es recomendable que no sea muy grande.
Aunque
el
programe
funcione
bien,
los
ruidos
grandes
sacuden
al
microcontrolador y perturban su operacin.
32
El cdigo fuente
/******************************************************************************
* FileName:
main.c
* Purpose:
Timer0 en Modo CTC
* Processor: ATmega164P
* Compiler:
IAR-C y AVR-GCC (WinAVR)
* Author:
Shawn Johnson. http://www.cursomicros.com.
*
* Copyright (C) 2008 - 2012 Shawn Johnson. All rights reserved.
*
* License:
Se permiten el uso y la redistribucin de este cdigo con
*
modificaciones o sin ellas, siempre que se mantengan esta
*
licencia y la nota de autor de arriba.
*****************************************************************************/
#include "avr_compiler.h"
#include "usart.h"
#define
#define
33
if (duty)
{
MOC_ON();
}
avr += ticks;
if(++i >= 4) {
i = 0;
avr = avr/4;
top = (unsigned char)avr + 1;
avr = 0;
}
ticks = 0;
}
//*****************************************************************************
// Gestor de Interrupcin en Coincidencia del Timer0.
// Esta funcin se ejecuta cada 200 us exactamente.
//*****************************************************************************
ISR (TIMER0_COMPA_vect)
{
if(++ticks >= duty)
{
if (duty < top)
{
MOC_OFF();
}
}
}
/******************************************************************************
* Main Function
*****************************************************************************/
int main(void)
{
DDRA = (1<<0);
// PA0 -> Salida MOC
usart_init();
printf("\r\n Control de Potencia ");
printf("\r\n (+) Subir duty cycle ");
printf("\r\n (-) Bajar duty cycle \r");
/* Configuracin del Timer0
* - Modo de operacin
= CTC
* - Factor de prescaler
= 8
* - Periodo de auto-reset = 200 us
*/
TCCR0A = (1<<WGM01);
TCCR0B = (1<<CS01);
OCR0A = 199;
// Lmite de TCNT0
/* Habilitar parcialmente la Interrupcin en Coincidencia del Timer0 */
TIMSK0 = (1<<OCIE0A);
/* Configurar y habilitar parcialmnete la interrupcin INT0 para que se
* dispare con cualquier flanco (de subida y/o de bajada) detectado en el
* pin INTx
*/
EIMSK = (1<<INT0);
// Habilitar INT0
EICRA = (1<<INT0*2);
// Elegir flanco de bajada/subida (modo 1)
34
sei();
for(;;)
{
if(kbhit())
{
char k = getchar();
if(top==0) {
printf("\r No AC signal detected");
}
else if((k == '+') && (duty < top))
{
printf("\r duty = %d", ++duty);
}
else if ((k == '-') && (duty))
{
printf("\r duty = %d", --duty);
}
}
}
}
35
Circuito de la prctica.
El cdigo fuente
/******************************************************************************
* FileName:
main.c
* Purpose:
Timer0 en Modo Normal como Contador
36
* Processor: ATmega164P
* Compiler:
IAR-C y AVR-GCC (WinAVR)
* Author:
Shawn Johnson. http://www.cursomicros.com.
*
* Copyright (C) 2008 - 2012 Shawn Johnson. All rights reserved.
*
* License:
Se permiten el uso y la redistribucin de este cdigo con
*
modificaciones o sin ellas, siempre que se mantengan esta
*
licencia y la nota de autor de arriba.
*****************************************************************************/
#include "avr_compiler.h"
#include "usart.h"
/******************************************************************************
* Main Function
*****************************************************************************/
int main(void)
{
unsigned char tcnt0;
PORTB |= (1<<0);
usart_init();
printf("\r\n Timer0 como Contador de Pulsos \r");
/* Configuracin del Timer0
* - Modo de operacin = Normal
* - Fuente de reloj
= Pin T0
*
El registro TCNT0 se incrementa con los flancos de bajada del pin T0
*/
TCCR0A = 0X00;
TCCR0B = (1<<CS02)|(1<<CS01);
/* Resetear TCNT0 */
TCNT0 = 0x00;
tcnt0 = ~TCNT0;
for(;;)
{
if(tcnt0 != TCNT0)
{
tcnt0 = TCNT0;
printf("\r Valor del registro TCNT0 = %d", tcnt0);
}
}
}
37
Registros del Timer0
TCCR0A
COM0A1
COM0A0
COM0B1
COM0B0
---
---
WGM01
WGM00
TCCR0B
FOC0A
FOC0B
---
---
WGM02
CS02
CS01
CS00
TIMSK0
---
---
---
---
---
OCIE0B
OCIE0A
TOIE0
TIFR0
---
---
---
---
---
OCF0B
OCF0A
TOV0
GTCCR
TSM
---
---
---
---
---
PSRASY
PSRSYNC
TCNT0
OCR0A
OCR0B
COM0A1
COM0A0
COM0B1
COM0B0
---
---
WGM01
COM0A0
Descripcin
OC0A desconectado.
puerto
OC0A
OCR0A
conmuta
en
Operacin
Coincidencia
normal
de
TCNT0
de
y
WGM00
38
TCCR0A
COM0A1
COM0A0
COM0B1
COM0B0
---
---
WGM01
COM0A0
Descripcin
COM0B1:0
COM0A1
COM0A0
Descripcin
WGM00
39
TCCR0A
COM0A1
COM0A0
COM0B1
COM0B0
---
---
WGM01
COM0B0
Descripcin
OC0B
desconectado.
puerto
OC0B
OCR0B
conmuta
en
Operacin
Coincidencia
normal
de
de
TCNT0
COM0B0
Descripcin
Reservado
se
WGM00
40
TCCR0A
COM0A1
COM0A0
COM0B1
COM0B0
---
---
WGM01
COM0B1
COM0B0
Descripcin
Reservado
Bits 3:2
Reservados
Estos bits estn reservados en los ATmega164A/PA,
ATmega324A/PA, ATmega644A/PA y ATmega1284/P, y siempre se
leern como cero.
WGM01:0
WGM01
WGM00
Tope del
Conteo
Normal
0xFF
0xFF
CTC
Fast PWM
0xFF
Reservado
---
Reservado
---
Fast PWM
OCR0A
OCR0A
OCR0A
WGM00
41
TCCR0B Timer/Counter Control Register 0 B
TCCR0B FOC0A
FOC0A
FOC0B
---
---
WGM02
CS02
CS01
FOC0B
Bits
5:4
Reservados
WGM02
CS02:0
Clock Select
Los tres bits de Clock Select seleccionan la fuente de reloj que
usar el Timer/Counter.
Si se usan los modos de pin externo para el Timer/Counter0, las
transiciones en el pin T0 harn el contador incluso si el pin est
configurado como salida. Esta caracterstica permite el control
software del contador.
CS00
42
TCCR0B FOC0A
FOC0B
---
---
WGM02
CS02
CS01
CS02
CS01
CS00
Reloj
externo
en
El Timer0 avanza con el flanco de
Reloj
externo
en
El Timer0 avanza con el flanco de
CS00
pin
T0.
bajada.
pin
T0.
subida.
TCNT0
Bits
7:0
TCNT0[7:0]
El Registro Timer/Counter da acceso directo al contador de 8 bits del
Timer/Counter para las operaciones de lectura y escritura. La escritura
en el registro TCNT0 bloquea (quita) la Coincidencia en el siguiente
ciclo de reloj del Timer. La modificacin de TCNT0 cuando el contador
est corriendo conlleva un riesgo de perder una Coincidencia entre los
registros TCNT0 y OCR0x.
OCR0A
Bits
7:0
OCR0A[7:0]
El registro Output Compare A contiene un valor de 8 bits que es
continuamente comparado con el valor del contador (TCNT0). Se puede
usar una Coincidencia para disparar una Interrupcin en Coincidencia, o
para generar una onda por el pin OC0A.
OCR0B[7:0]
El registro Output Compare B contiene un valor de 8 bits que es
continuamente comparado con el valor del contador (TCNT0). Se
puede usar una Coincidencia para disparar una Interrupcin en
Coincidencia, o para generar una onda por el pin OC0B.
43
TIMSK0 Timer/Counter Interrupt Mask 0 Register
TIMSK0
---
---
---
---
---
OCIE0B
OCIE0A
Bits
7:3
Reserved
OCIE0B
TOIE0
TOIE0
---
---
---
---
---
OCF0B
OCF0A
Bits
7:3
Reserved
OCF0B
TOV0
44
TIFR0
---
---
---
---
---
OCF0B
OCF0A
OCF0A
TOV0
TOV0
TSM
---
---
---
---
---
PSRASY
PSRSYNC
PSRASY
45
GTCCR
TSM
---
PSRSYNC
---
---
---
---
PSRASY
PSRSYNC
Prescaler Reset
Si este bit vale uno, el prescaler del Timer/Counter0 y
el Timer/Counter1 se resetear. Normalmente este bit se
limpia de inmediato por hardware, excepto cuando el bit
TSM valga uno. Note que el Timer/Counter0 y el
Timer/Counter1 comparten el mismo prescaler y el reset de
este prescaler afecta a ambos Timers.
TCCR2A
COM2A1
COM2A0
COM2B1
COM2B0
---
---
WGM21
WGM20
TCCR2B
FOC2A
FOC2B
---
---
WGM22
CS22
CS21
CS20
TIMSK2
---
---
---
---
---
OCIE2B
OCIE2A
TOIE2
TIFR2
---
---
---
---
---
OCF2B
OCF2A
TOV2
TCNT2
OCR2A
OCR2B
CS22:0
Clock Select
Los tres bits de Clock Select seleccionan la fuente de reloj que
usar el Timer/Counter2.
CS22 CS21 CS20
clkT2S
clkT2S/8
clkT2S/32
(Desde el prescaler)
clkT2S/64
(Desde el prescaler)
clkT2S/128
(Desde el prescaler)
clkT2S/256
(Desde el prescaler)
clkT2S/1024
(Sin prescaler)
(Desde el prescaler)
(Desde el prescaler)
46
Si se efecta una escritura en cualquiera de los cinco registros del
Timer/Counter2 cuando su correspondiente flag de busy (ocupado) vale uno, el
valor actualizado puede resultar corrompido y se podra disparar una
interrupcin inintencionada.
El mecanismo para leer los registros TCNT2, OCR2A, OCR2B, TCCR2A y TCCR2B es
diferente. Al leer TCNT2 se obtiene el valor actual del Timer. Al leer OCR2A,
OCR2B, TCCR2A y TCCR2Bse obtiene el valor del registro de almacenamiento
temporal.
AS2
TCN2UB
OCR2AUB
OCR2BUB
TCR2AUB
EXCLK
AS2
Asynchronous Timer/Counter2
Al
escribir
cero
en
este
bit,
el
reloj
del
Timer/Counter2 provendr del reloj del sistema F_CPU. Al
escribir uno en AS2, el reloj del Timer/Counter2
derivar de un XTAL externo conectado al pin Timer
Oscillator 1 (TOSC1). Si se cambia el valor de AS2, se
podran corromper los contenidos de los registros TCNT2,
OCR2A, OCR2B, TCCR2A y TCCR2B.
TCN2UB
OCR2AUB
OCR2BUB
TCR2BUB
47
ASSR --- EXCLK
AS2
TCN2UB
OCR2AUB
OCR2BUB
TCR2AUB
TCR2BUB
TCR2BUB
El Timer1 y el Timer3
Si antes habamos estudiado a la par el Timer0 y el Timer2 por ser muy
simulares, esta vez la referencia al Timer3 se reduce solo a su mencin en los
ttulos. Sucede que el Timer3 es completamente idntico al Timer1. La mala
noticia es que solo est disponible en los ATmega128xy :-(
El Timer/Counter1, o simplemente Timer1, es de 16 bits. En principio, opera de
la misma forma en que lo hace el Timer0, solo que utilizando sus registros de
datos de 16 bits. Esto lo podremos comprobar al notar la gran similitud que
tienen sus diagramas de bloques.
Como en los megaAVR cada registro de E/S es de 8 bits, en realidad los
registros de datos del Timer1 estn compuestos por la unin de dos registros de
8 bits. Por ejemplo, TCNT1 se forma uniendo los registros TCNT1H y TCNT1L. Lo
mismo sucede con los siguientes registros
Los
registros
de
control
del
Timer1
bits: TCCR1A, TCCR1B, TCCR1C, TIMSK1,TIFR1 y GTCCR.
siguen
siendo
de
48
Tope
de
Conteo
Normal
0x00
0xFFFF
0x00
0x00FF
0x00
0x01FF
0x00
0x03FF
CTC
0x00
OCR1A
0x00
0x00FF
0x00
0x01FF
0x00
0x03FF
0x00
ICR1
0x00
OCR1A
WGM13
WGM12
WGM11
WGM10
49
Inicio
de
Conteo
Tope
de
Conteo
0x00
ICR1
0x00
OCR1A
CTC
0x00
ICR1
Reservado
0x00
Fast PWM
0x00
ICR1
Fast PWM
0x00
OCR1A
WGM13
WGM12
WGM11
WGM10
Los bits CS (Clock Select), como indica su nombre, son para configurar
fuente de reloj del Timer2. El reloj del Timer2 es idntico al del Timer0.
la
Recordemos que comparten el mismo prescaler y aunque tambin trabajan con los
mismos divisores o factores de prescaler, su configuracin no tiene que ser la
misma, es decir, podemos emplear nuestro Timer0 con un factor de 8 y el Timer2
con el factor 1024. Para mayor informacin puedes revisar la seccin
los prescalers del Timer0 y del Timer2.
CS12
CS11
CS10
Los bits COM. Hasta ahora los habamos estado dejando de lado. Como su nombre
lo indica, estos bits controlan en modo de salida de los comparadores (Compare
Output Mode). Los habamos ignorado porque no tiene mucho sentido usarlos en
los modos Normal o CTC. En cambio ahora que entraremos de lleno en el modo PWM,
sern ms que necesarios. Desde el momento en que configuremos estos bits para
sacar las ondas (PWM o no) por los pines OC1A y/o OC1B el Timer2 asumir el
control
sobre
ellos
y
ya
no
podremos
usarlos
como puertos
de
E/S
generales (mediante el registro PORTx respectivo). Sin embargo, todava ser
necesario configurarlos como pines de salida en sus correspondientes bits del
registro DDRx. Los bits COM son detestables porque tienen diferente efecto
dependiendo de si el Timer opera en modo Normal y CTC, en modo Fast PWM o en
modo PWM de Fase correcta y PWM de Fase y Frecuencia correctas. Tan solo
50
mencionar estos trminos marea un poco, verdad? Por eso voy a reservar las
tablas correspondientes para otro momento.
El Registro ICR1. Como te habrs dado cuenta, este registro es nuevo; es propio
del Timer1. Su nombre ICR1 es el acrnimo de Input Capture Register 1 y tiene
dos
funciones.
En
primer
lugar
sirve
para
capturar
el
valor
del
registro TCNT1 justo en el momento en que el bloque Fuente de Captura (ver la
figura) le d la seal. Esta funcin es til en aplicaciones que necesitan
medir la frecuencia de alguna seal externa, pero no tiene nada que ver con el
modo PWM as que la ignoraremos por el momento. Sin embargo, el registro ICR1
tambin puede trabajar como el tope del conteo del Timer1 en los modos PWM.
sta es su faceta en que ms se le emplea.
El bloque FUENTE DE CAPTURA. Se trata de un circuito que selecciona la seal de
captura. Segn su diagrama mostrado abajo, se disponen de dos opciones: o es el
pin ICP del megaAVR o es la salida del Comparador Analgico. La eleccin se
hace
mediante
el
bit ACIC,
del
registro
ACRS.
El
bit ICNC1 (del
registro TCCR1B) puede activar el eliminador de ruido para evitar falsos
disparos causados por los picos del ruido. En la etapa final, el
bit ICES1 (tambin del registro TCCR1B) establece si el disparo se dar en el
flanco de subida o de bajada de la fuente seleccionada. Una vez detectada la
seal elegida, se activar el flag ICF1 y el registro ICR1 le tomar una
fotografa al registro TCNT1. Este evento se puede aprovechar para programar y
disparar su interrupcin.
51
Las siguientes formulas nos dan un camino para hallar por partes las dos
incgnitas de la primera frmula.
52
Si no tienes idea de cmo usarlas o de cul modo (Normal o CTC) es mejor para
temporizar, puedes revisar la teora dedicada al Timer0 y al Timer2.
El Timer1 y el Timer3 en Modo PWM
El mecanismos como los Timers generan ondas PWM es fcil de asimilar asumiendo
que
ya
nos
es
familiar
las
funciones
de
sus
registros
de
datos TCNT1, OCR1A y OCR1B. Ahora se les suma el registro ICR1, cuya funcin en
este caso es establecer el tope de conteo opcional.
WGM13
WGM12
WGM11
WGM10
Inicio
de
Conteo
Tope
de
Conteo
0x00
0x00FF
0x00
0x01FF
0x00
0x03FF
0x00
0x00FF
0x00
0x01FF
0x00
0x03FF
0x00
ICR1
0x00
OCR1A
0x00
ICR1
0x00
OCR1A
Fast PWM
0x00
ICR1
Fast PWM
0x00
OCR1A
La resolucin para las ondas PWM se puede fijar a 8, 9 10 bits, o definir por
el registro OCR1A oICR1. La mnima resolucin permitida es de 2 bits
(OCR1A o ICR1 = 0x0003) y la mxima frecuencia posible es de 16 bits
53
(OCR1A o ICR1 = 0xFFFF). La resolucin PWM en bits se puede calcular usando la
siguiente frmula.
Cuando se cambia el valor del tope, el programa debe asegurarse de que el nuevo
valor del tope sea mayor o igual que el valor de todos los registros de
comparacin. Si el valor tope es menor que cualquier registro de comparacin,
nunca ocurrir una coincidencia entre TCNT1 y OCR1A/OCR1B. Note que al usar los
valores tope fijos, los bits no usados sern enmascarados a cero cuando se
escriba cualquiera de los registros OCR1A/OCR1B.
El
procedimiento
para
actualizar ICR1 difiere
de
la
actualizacin
de OCR1A cuando se usan para definir el valor tope. El registro ICR1 no usa
doble buffer. Esto significa que al cambiar ICR1 a un valor inferior cuando un
contador est corriendo hay un riesgo de que el nuevo valor escrito en ICR1 sea
inferior a TCNT1. El resultado ser que el contador no encontrar una
coincidencia en la pendiente actual.
Sin embargo, el registro OCR1A s usa doble buffer. Con esta caracterstica
podemos escribir enOCR1A en cualquier momento porque el valor escrito ser
puesto en su buffer de respaldo. El registroOCR1A se actualizar con el valor
de su buffer en el siguiente ciclo de reloj del Timer en que TCNT1coincida con
el tope actual.
El uso del registro ICR1 para definir el valor tope funciona bien cuando se
usan topes fijos. El uso deICR1 deja libre el registro OCR1A para ser usado
para generar una salida PWM en OC1A. Sin embargo, si la frecuencia PWM base
cambia activamente (cambiando el valor tope), el uso de OCR1A como tope es
claramente la mejor opcin debido a su caracterstica de doble buffer.
En modo Fast PWM los comparadores permiten la generacin de ondas PWM por los
pines OC1A y/oOC1B. Estos pines debern ser configurados como salida.
El Timer1 presenta 3 modos PWM.
Fast PWM
En este modo el registro TCNT1 avanza siempre en forma ascendente hasta llegar
a un valor tope que puede ser el del registro OCR1A o ICR1, o bien un valor
fijo 0x00FF, 0x01FF o 0x03FF.
El modo Fast PWM o Fast Pulse Width Modulation difiere de las otras opciones de
PWM por su operacin de pendiente nica. El contador TCNT1 avanza desde 0x0000
54
hasta el valor tope establecido y luego se reinicia desde 0x0000. Los bits COM
respectivos establecen si la onda saldr invertida o no.
En modo no-invertido el estado del pin OC1A/OC1B se limpia en la Coincidencia y
se setea al llegar a 0x0000. En modo invertido la salida OC1A/OC1B se setea en
la Coincidencia y se limpia al llegar a 0x0000. Debido a su operacin de
pendiente nica, la frecuencia de la seal Fast PWM puede ser hasta dos veces
mayor que la frecuencia de las ondas en modo PWM de Fase Correcta y PWM de Fase
y Frecuencia Correctas, que usan la operacin de doble pendiente. Esta alta
frecuencia hace del modo Fast PWM muy adecuado para aplicaciones de regulacin
de potencia, rectificaciones y DAC.
La siguiente figura muestra el diagrama de tiempos del modo Fast PWM cuando se
usa el registroICR1 como tope. En el diagrama el valor del registro TCNT1 se
muestra como un histograma para ilustrar la operacin en modo de pendiente
nica. El diagrama incluye las salidas PWM invertida y no invertida. Las
pequeas marcas de lneas horizontales en la pendiente de TCNT1 representan las
Coincidencias
entre
los
registros TCNT1 y OCR1A.
El
flag
de
interrupcin OCF1A/OCF1B se setea cuando ocurra la Coincidencia.
55
La frecuencia de la onda Fast PWM se puede calcular con la siguiente ecuacin.
con
el
valor
de
su
buffer
doble
56
El flag TOV1 se activa cada vez que el contador alcanza 0x0000. Si se usa el
registro ICR1 como tope del conteo, su flag ICF1 se activar en el mismo ciclo
de reloj del Timer en que el contador alcance el tope. Se pueden usar los flags
de interrupcin para generar las interrupciones correspondientes.
Como se ve en el tercer periodo del diagrama, el hecho de cambiar el tope
activamente mientras el contador est corriendo puede resultar en una salida
asimtrica, debido al momento en que se actualizan los registros OCR1A/OCR1B.
Puesto que la actualizacin de OCR1A/OCR1B ocurre en el tope, el periodo PWM
empieza y termina en el tope. Esto implica que la pendiente de bajada est
determinada por el tope previo y la pendiente de subida est determinada por el
nuevo tope.
Se recomienda usar el modo PWM de Fase y Frecuencia Correctas en lugar del modo
de Fase Correcta cuando se va a cambiar el tope mientras el Timer est
corriendo. Cuando se usa un valor esttico de tope prcticamente no hay
diferencias entre ambos modos de operacin.
La frecuencia PWM para la salida se puede calcular por la siguiente ecuacin.
57
COM1A1
COM1A0
COM1B1
COM1B0
---
---
WGM11
WGM10
TCCR1B
ICNC1
ICES1
---
WGM13
WGM12
CS12
CS11
CS10
TCCR1C
FOC1A
FOC1B
---
---
---
---
---
---
TCNT1H
TCNT1L
OCR1AH
OCR1AL
58
OCR1BH
OCR1BL
ICR1H
ICR1L
TIMSK1
--
---
ICIE1
---
---
OCIE1B
OCIE1A
TOIE1
TIFR1
--
---
ICF1
---
---
OCF1B
OCF1A
TOV1
GTCCR
TSM
---
---
---
---
---
PSRASY
PSRSYNC
COM1A0
COM1B1
COM1B0
---
COM1A1:0
COM1B1:0
---
WGM11
COM1A0/
COM1B0
Descripcin
OC0A/OC0B
de pin
desconectado.
Operacin
normal
WGM10
59
TCCR1A COM1A1
COM1A0
COM1B1
COM1B0
---
---
WGM11
Descripcin
WGM13:0
=
14
o
Coincidencia,
OC1B
normal de pin).
15:
OC1A
conmuta
en
desconectado
(operacin
Para
las
dems
configuraciones
OC1A/OC1B desconectado (operacin
pin).
de
WGM1,
normal de
es
el
del
COM1A1/
COM1B1
COM1A0/
COM1B0
Descripcin
WGM13:0
=
9
u
Coincidencia, OC1B
normal de pin).
11:
OC1A
conmuta
en
desconectado (operacin
Bits 3:2
tope
de WGM1,
normal de
Reservados
Estos
bits
estn
reservados
en
los
ATmega164A/PA,
ATmega324A/PA, ATmega644A/PA y ATmega1284/P, y siempre se
WGM10
60
TCCR1A COM1A1
COM1A0
COM1B1
COM1B0
---
---
WGM11
WGM11:0
Tope
del
Conteo
Normal
0xFFFF
0x00FF
0x01FF
PWM de
bits
0x03FF
CTC
0x00FF
0x01FF
0x03FF
PWM de Fase
Correctas
PWM de Fase
Correctas
ICR1
OCR1A
CTC
Reservado
Fast PWM
ICR1
Fast PWM
OCR1A
Fase
Correcta,
10
OCR1A
Frecuencia
ICR1
Frecuencia
OCR1A
ICR1
WGM10
61
TCCR1B Timer/Counter Control Register 1 B
TCCR1B
ICNC1
ICES1
---
WGM13
WGM12
CS12
CS11
ICNC1
ICES1
Bits 5
Reservado
Este bit est reservado para usos futuros. Al escribir en
TCCR1B, este bit se debe mantener en cero para asegurar la
compatibilidad con futuros dispositivos.
WGM13:2
CS12:0
Clock Select
Los tres bits de Clock Select seleccionan la fuente de reloj
que usar el Timer/Counter.
CS10
62
TCCR1B
ICNC1
ICES1
---
WGM13
WGM12
CS12
CS11
CS10
CS11
CS10
Reloj
externo
en
pin
T1.
El Timer1 avanza en el flanco de bajada.
Reloj
externo
en
pin
T1.
El Timer1 avanza en el flanco de subida.
Sin
detenido)
fuente
de
reloj
(el
Timer1
est
TCCR1C FOC1A
FOC1B
---
FOC1A
FOC1B
---
---
activos
---
cuando
---
los
bits
---
63
TCCR1C FOC1A
FOC1B
---
---
---
---
---
---
Reservados
Estos bits estn reservados y siempre se leern como cero.
TCNT1H
TCNT1L
Bits
15:0
TCNT1H[7:0] y TCNT1L[7:0]
Los dos registros TCNT1H y TCNT1L combinados, dan acceso directo al
contador de 16 bits del Timer/Counter para las operaciones de lectura
y escritura. Para asegurar que los dos registros se lean y escriban
al mismo tiempo, el acceso se realiza utilizando un registro temporal
de 8 bits para almacenar el byte alto (TCNT1H). Este registro
temporal se comparte con todos los otros registros de 16 bits.
La modificacin de TCNT1 cuando el contador est corriendo conlleva
un riesgo de perder una Coincidencia entre los registros TCNT1 y
OCR1A/ OCR1B.
La escritura en el registro TCNT0 bloquea (quita) la Coincidencia en
el siguiente ciclo de reloj del Timer para todas las unidades de
comparacin.
64
OCR1AH
OCR1AL
Bits
15:0
OCR1AH[7:0] y OCR1AL[7:0]
Los dos registros Output Compare A contienen un valor de 16 bits
que es continuamente comparado con el valor del contador (TCNT1).
Se puede usar una Coincidencia para disparar una Interrupcin en
Coincidencia, o para generar una onda por el pin OC1A.
Para asegurar que los dos registros Output Compare A se escriban
simultneamente cuando el CPU escribe en estos registros, el acceso
se realiza utilizando un registro temporal de 8 bits para almacenar
el byte alto (OCR1AH). Este registro temporal es compartido por
todos los dems registros de 16 bits.
OCR1BH[7:0] y OCR1BL[7:0]
Los dos registros Output Compare B contienen un valor de 16 bits
que es continuamente comparado con el valor del contador (TCNT1).
Se puede usar una Coincidencia para disparar una Interrupcin en
Coincidencia, o para generar una onda por el pin OC1B.
Para asegurar que los dos registros Output Compare B se escriban
simultneamente cuando el CPU escribe en estos registros, el acceso
se realiza utilizando un registro temporal de 8 bits para almacenar
el byte alto (OCR1BH). Este registro temporal es compartido por
todos los dems registros de 16 bits.
Bits
15:0
65
TIMSK1 Timer/Counter Interrupt Mask 1 Register
TIMSK1
--
---
Bits
7:6
Reserved
Bits
4:3
Reserved
ICIE1
---
---
OCIE1B
OCIE1A
TOIE1
ICIE1
OCIE1A
TOIE1
--
---
ICF1
---
---
OCF1B
OCF1A
Bits
7:6
Reserved
Bits
4:3
Reserved
Estos bits estn reservados y siempre se leern como cero.
Timer/Counter1, Input Capture Flag
Este flag se activa cuando ocurre un evento en el pin ICP1. Si
la configuracin de los bits WGM13:0 establecen el registro
Input Capture como tope del conteo, el flag ICF1 se activar
cuando el contador alcance el valor tope.
El bit ICF1 se limpia automticamente al ejecutarse la funcin
de Interrupcin respectiva. Alternativamente, ICF1 se puede
limpiar por software escribiendo sobre l un uno lgico.
ICF1
OCF1B
TOV1
66
TIFR1
--
---
ICF1
---
---
OCF1B
OCF1A
TOV1
TOV1
TSM
TSM
---
---
---
---
---
PSRASY
PSRASY
PSRSYNC
67
GTCCR
TSM
---
---
---
---
---
PSRASY
PSRSYNC
Prescaler Reset
Si este bit vale uno, el prescaler del Timer/Counter0 y
el Timer/Counter1 se resetear. Normalmente este bit se
limpia de inmediato por hardware, excepto cuando el bit
TSM valga uno. Note que el Timer/Counter0 y el
Timer/Counter1 comparten el mismo prescaler y el reset de
este prescaler afecta a ambos Timers.
COM3A1
COM3A0
COM3B1
COM3B0
---
---
WGM31
WGM30
TCCR3B
ICNC3
ICES3
---
WGM33
WGM32
CS32
CS31
CS30
TCCR3C
FOC3A
FOC3B
---
---
---
---
---
---
TIMSK3
--
---
ICIE3
---
---
OCIE3B
OCIE3A
TOIE3
TIFR3
--
---
ICF3
---
---
OCF3B
OCF3A
TOV3
GTCCR
TSM
---
---
---
---
---
PSRASY
PSRSYNC
TCNT3H
TCNT3L
OCR3H
OCR3AL
OCR3BH
OCR3BL
ICR3H
ICR3L
68
PRCTICA: EL TIMER1 EN MODO PWM
Se generan ondas PWM de Fase y Frecuencia correctas por los dos canales, A y B.
Se pueden configurar la Frecuencia y el Duty cycle de la dos seales desde la
consola serial.
Circuito de la prctica.
El cdigo fuente
/******************************************************************************
* FileName:
main.c
* Purpose:
Timer1 - Operacin en modo PWM
* Processor: ATmega164P
* Compiler:
IAR-C y AVR-GCC (WinAVR)
* Author:
Shawn Johnson. http://www.cursomicros.com.
*
* Copyright (C) 2008 - 2012 Shawn Johnson. All rights reserved.
*
* License:
Se permiten el uso y la redistribucin de este cdigo con
*
modificaciones o sin ellas, siempre que se mantengan esta
69
*
licencia y la nota de autor de arriba.
*****************************************************************************/
#include "avr_compiler.h"
#include "usart.h"
char GetNumStr(char * buffer, unsigned char len);
int main(void)
{
unsigned int reg;
char k, buffer[10];
usart_init();
puts("\r\n Timer1 en Modo PWM \r");
/* Configuracin del Timer1
* - Bits WGM: PWM de Fase y Frecuencia Correctas con tope de conteo = ICR1
* - Bits COM: PWM no-invertida en los dos canales A y B
* - Bits CS: Fuente de reloj = F_CPU/8
*/
TCCR1A = (1<<COM1A1)|(1<<COM1B1);
TCCR1B = (1<<WGM13)|(1<<CS11);
DDRD = (1<<4)|(1<<5);
// Pines OC1A y OC1B salidas PWM
/* Poner algunos
ICR1 = 200;
OCR1A = 100;
OCR1B = 50;
puts("\r
puts("\r
puts("\r
puts("\r
while(1)
{
do {
valores iniciales */
// frecuencia PWM = 1/(2*200 ) = 2.5 kHz
// Duty cycle canal A = 50%
// Duty cycle canal B = 25%
Escoja el
[1] ICR1
[2] OCR1A
[3] OCR1B
k = getchar();
}while (!((1<='k') && (k<='3')));
switch (k)
{
case '1': puts("\r ICR1 = "); break;
case '2': puts("\r OCR1A = "); break;
case '3': puts("\r OCR1B = "); break;
}
while( GetNumStr(buffer, 9)==0);
reg = atoi(buffer);
switch (k)
{
case '1': ICR1 = reg; break;
case '2': OCR1A = reg; break;
case '3': OCR1B = reg; break;
}
}
}
//****************************************************************************
// Lee una cadena de texto de 'len' nmeros
// El tamao de 'buffer' debe ser mayor que 'len'.
70
//****************************************************************************
char GetNumStr(char * buffer, unsigned char len)
{
char c; static unsigned char i=0;
if(kbhit()) {
c = getchar();
if((c<='9'&&c>='0')&&(i<len)) {
// Si c est entre 0 y 9
buffer[i++] = c;
// Guardar en buffer
putchar(c);
// Eco
}
else if((c=='\b')&&(i)) { // Si c es RETROCESO y si i>0
i--;
//
putchar(c);
// Eco
}
else if((c=='\r')&&(i)) { // Si c es ENTER y si i>0
buffer[i] = '\0';
// Poner un 0x00 (fin de cadena)
putchar(c);
// Eco
i = 0;
// Resetear contador
return 1;
// Retornar con 1
}
}
return 0;
// Retornar con 0
}