Sie sind auf Seite 1von 70

1

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.

De hecho, solo trataremos el Timer1 porque el Timer3 es su perfecto clon, si


vale la expresin.
Como habrn notado, haba tratado hasta donde me posible de describir las
caractersticas de los perifricos de los megaAVR pensando tambin en los que
la propia ATmel denomina viejos AVR, dado que an son muy usados en la
actualidad y hay muchos proyectos de inters que se basan en esos
microcontroladores. Pero creo que en esta ocasin dejar de lado ese enfoque
mltiple para no recargar el tema demasiado.
Como haba dicho hay mucha similitud entre todos los Timers y bastara con
conocer bien el funcionamiento de uno de ellos para poder comprender los dems.
Con todo eso, el estar mencionando a cada rato que tal bit tiene otro nombre en
el otro AVR o que est pequea funcin no est presente en aquel otro,...
puede hacer tediosa el estudio. Suficiente ser con comparar los diversos
Timers que mencionamos. No obstante, puesto que todo el control y configuracin
de un mdulo queda reflejado en sus registros de E/S, creo que una buena idea
poner al final la descripcin respectiva de los registros de los Timers de los
viejos megaAVR. Yo creo que eso ser ms que suficiente para programarlos
bien, sin necesidad de empezar a describirlos por separado.

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

control de cada Timer a nivel de programacin requiere del


de sus registros de configuracin. Pero tampoco esto es de
lo nico que cambia es el nmero 0 por el nmero 2 en cada
registro. Por ejemplo, los registros de E/S del Timer0 son:

TCNT0. TCCR0A, TCCR0B, OCR0A, OCR0B, TIMSK0 y TIFR0.


En tanto que para el Timer2 son:
TCNT2. TCCR2A, TCCR2B, OCR2A, OCR2B, TIMSK2 y TIFR2.
Aparte de ellos, tenemos al registro GTCCR, el cual es de uso comn para todos
los Timers desde el Timer0 hasta el Timer3, y el registro ASSR, que es de uso
exclusivo del Timer2 y que controla las caractersticas distintivas del
funcionamiento asncrono de este Timer.
Del mismo modo, en los nombres de los bits de cada registro, solo cambian el
nmero 0 por el 2. Por ejemplo, los mapas de bits de los registros TCCR0A y
TCCR2A son, respectivamente:

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.

Diagrama de bloques del Timer0.

El elemento central del Timer0 es su contador, que es mismo registro


TCNT0. Como es un registro de 8 bits, decimos que el Timer0 es de 8 bits.
El Timer0 puede avanzar hacia adelante o hacia atrs, segn se programe,
impulsado por la seal de su reloj, el cual puede ser interno o externo.
Cuando nos referirnos al avance del Timer en realidad nos referimos al
avance de su contador, el registro TCNT0.

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.

El Timer0 tiene dos comparadores que en todo momento estn comparando el


valor del registro TCNT0 con los registros OCR0A y OCR0B. Cada igualdad
detectada entre los registros indicados se conoce como Coincidencia y es
el segundo concepto clave de los Timers del AVR. La coincidencia entre
TCNT0 y OCR0A activa el bit de flag OCF0A y la coincidencia entre TCNT0 y
OCR0B activa el bit de flag OCF0B.

El Desbordamiento del Timer0 y cada una de sus dos Coincidencias antes


citadas pueden ser programadas para disparar interrupciones. Los detalles
de las interrupciones sern vistos con paciencia en su seccin respectiva.

Desde el punto de vista de la programacin, podemos controlar el Timer0


con tres tipos de bits:

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.

El Reloj del Timer0 y del Timer2


La similitud entre el Timer0 y el Timer2 se comprueba fcilmente examinando sus
correspondientes registros de control. Es en esta seccin donde nos ocuparemos
de las pocas diferencias entre ellos.
El reloj del Timer0 es la seal digital, peridica o no, cuyos pulsos hacen
avanzar el Timer. La fuente de reloj del Timer0 puede ser interna o externa.

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.

Reloj Externo. He aqu la brecha ms grande que separa al Timer0 del


Timer2. La forma como la seal externa se aplica al microcontrolador
depende de cada Timer.

En el Timer0 la seal externa se conecta al T0 del megaAVR. Con esto el


programador decide si el Timer0 avanzar con cada flanco de subida o de
bajada de dicha seal. Notemos en el diagrama que la seal externa no
pasar por su prescaler.

En el Timer2 su reloj externo puede ser de dos tipos: o es una seal


aplicada al pin TOSC1 del megaAVR, en cuyo caso el Timer2 avanzar con
cada flanco de bajada detectado en dicho pin; o es la seal de un
oscilador de XTAL conectado entre los pines TOSC1 y TOSC2 del megaAVR. En
ambos casos, la seal de reloj pasar por el prescaler del Timer2.

El modo donde el Timer0/2 trabaja con un reloj externo aplicado al pin T0


(para el Timer0) o TOSC1 (para el Timer2) se conoce como modo Contador
porque de alguna forma el Timer contar los pulsos detectados en dicho
pin. Sin embargo, el hecho de que el reloj provenga de una fuente externa
no le quita sus otras funcionalidades, como por ejemplo, poder generar
ondas PWM, interrupciones, etc., claro que sera conveniente que para tal
caso la seal fuera peridica.

Contador del Timer2 con su fuente de reloj.

El Prescaler del Timer0 y del Timer2


El prescaler es un circuito contador por el que se puede hacer pasar el reloj
del Timer para dividir su frecuencia. De ese modo el Timer avanzar ms lento,
segn las necesidades del diseador.
El prescaler es parte del reloj del Timer, as que para configurarlo se usan
los bits de Seleccin de Reloj o bits CS (por Clock Select).

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.

Prescaler y Relojes del Timer0 y del Timer1.


Notemos que el prescaler divide el reloj del sistema por 8, 64, 256 1024.
Estos divisores se conocen como factores de prescaler. Observemos adems que de
usar un reloj proveniente del pin T0, entonces no ser posible usar el
prescaler.

Ahora revisemos el prescaler del Timer2. Este prescaler ofrece ms factores de


divisin, con lo que las temporizaciones podrn ser ms flexibles. A diferencia
del Timer0/1, si optamos por un reloj externo aplicado al pin TOSC1, dicha
seal s podr pasar por el prescaler. Esta vez el prescaler se puede resetear
con la seal PSRASY. Su nombre indica que se trata de naturaleza ASYncrona
porque si el reloj del Timer2 viene del exterior, no habr circuito que lo
sincronice con el reloj del sistema F_CPU. Los bits AS2 y PSRASY se encuentran
en el registro GTCCR.

Prescaler y Reloj del Timer2.

En la siguiente tabla la seal clkT2S puede ser F_CPU o el reloj proveniente


del exterior.

Modos de Operacin del Timer0 y Timer2


En general existen 3 modos en que pueden trabajar los Timers:

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.

El Timer0 y el Timer2 en Modo Normal


Este modo queda seleccionado cuando todos los bits WGM valen 0, es decir, es el
modo por defecto del Timer0. De hecho, lo es en todos los Timers.

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.

La tabla solo muestra la configuracin de la onda generada para el pin OC0A


pero es la misma que se obtiene para el pin OC0B con los bits COM0B1 y COM0B0.

Clculo de la Temporizacin en Modo Normal


Temporizar con el Timer0 implica cargar su registro TCNT0 con un valor adecuado
y dejar que siga contando hasta que se desborde. Es el tiempo que demora en
desbordarse lo que nos interesa conocer para aplicarlo a nuestras necesidades;
y son el clculo y la programacin de ese tiempo el objetivo de esta seccin.

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,

entonces, suponiendo que seguimos con nuestro XTAL de 8MHz, el registro


avanzar desde 0 hasta 255 en 32us (sin prescaler). Pero si cargamos
con 200, llegar al desbordamiento despus de 7us; y si usamos prescaler
lo har despus de 78 = 56us.

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.)

Lo ms probable es que el valor obtenido con esta frmula no est disponible


como factor de prescaler vlido (1, 8, 64, 256 1024 para el Timer0 o 1, 8,
32, 64, 128, 256 y 1024 para el Timer2). En tal caso deberemos tomar el factor
superior ms cercano (redondear para arriba). La otra frmula es:

Como antes, si el resultado no fuera un nmero entero, habra que redondearlo


para arriba.
Si el factor de prescaler obtenido estuviera fuera del rango permitido (ms
alto que 1024), se puede optar por buscar otro camino, como fragmentar la
temporizacin. Por otro lado, si la temporizacin es muy fina, puede que sea
necesario subir un poquito el valor de inicio del TCNT0 para realizar una
calibracin aadiendo algunas instrucciones de relleno como nops. Estas dos
situaciones las veremos en las prcticas; as que pierde cuidado si no las dej
muy claro.
A modo de ejemplo, hallemos el factor de prescaler N y el valor de inicio de
TCNT0 para generar una temporizacin de 5 ms si el megaAVR trabaja con un XTAL
de 10 MHz.

14

Y el valor de inicio del registro TCNT0 ser:

La secuencia de conteo resultara as:

Otro ejemplo. Cules son la razn de prescaler y el valor inicial de TCNT0


para conseguir una temporizacin de 200 s si nuestro megaAVR tiene un XTAL de
4 MHz?
El factor de prescaler N sera:

Y el valor inicial de TCNT0 ser:

Luego, la secuencia de conteo quedara as:

Finalmente, cules son la razn de prescaler y el valor inicial de TCNT0 para


conseguir una temporizacin de 50 ms si se tiene un megaAVR con un XTAL de 20
MHz?
El factor de prescaler sera:

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.

El Timer0 y el Timer2 en Modo CTC

Su nombre es el acrnimo de Clear Timer on Compare Match y significa que el


Timer se limpia cuando se produce una Coincidencia en la comparacin de los
registros TCNT0 y OCR0A.
En este modo el Timer0 (su registro TCNT0) tambin empieza a contar desde 0x00
y se incrementa hasta que su valor sea igual al del registro OCR0A, en ese
momento el registro TCNT0 se resetea y vuelve a contar desde 0x00. La
Coincidencia tambin activa el flag OCF0A, el cual se puede usar para programar
interrupciones. El registro OCR0A tambin es de lectura y escritura de modo que
podemos establecer el tope hasta donde contar el Timer0. De cierta forma el
auto-reseteo del Timer0 equivale a una auto-recarga. El diagrama indica la
operacin descrita.

Diagrama simplificado del Timer0 para temporizaciones en modo CTC.


En trminos generales todo lo que puede hacer el registro OCR0A tambin lo
puede hacer su gemelo OCR0B, pero en este caso en especial la regla se rompe:
Aunque los comparadores trabajen en todo momento y hay una Coincidencia por
cada uno de ellos, el modo CTC est reservado para operar nicamente con el

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.

Clculo de la Temporizacin en Modo CTC


La frmula que nos da el tiempo entre coincidencia y coincidencia es la
siguiente. Recuerda que en modo CTC est frmula solo vale para el registro
OCR0A y no para OCR0B.

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.

La segunda frmula se obtiene despejando OCR0A de la frmula


presupone que para esto ya debimos haber hallado el valor de N.

inicial.

Se

Si conseguimos para OCR0A una solucin entera vlida, ser genial y no


tendremos que recurrir a posteriores ajustes de precisin, sin importar en qu
lenguaje o compilador se programe. De lo contrario, no habr calibracin en

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.

Interrupciones del Timer0 y el Timer2


Esta vez el diagrama del Timer0 nos indica que debemos concentrarnos en los
bits de flag que pueden disparar las interrupciones del Timer0.

Flags de Desbordamiento y de Coincidencias del Timer0.


La real potencia del Timer0 se deja apreciar al emplear su caracterstica ms
notable: las interrupciones. El Timer0 tiene dos tipos de interrupciones: una
por el desbordamiento de su registro TCNT0 y dos en las coincidencias de su
registro TCNT0 con los registros OCR0A y OCR0B. Estas interrupciones se
controlan por los bits de los registros TIMSK0 y TIFR0:

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

Especificando, cuando se detecte la igualdad entre TCNT0 y OCR0A se activar el


flag OCF0A (Output Compare Flag 0 A), y cuando sean iguales TCNT0 y OCR0B se
activar el flag OCF0B (Output Compare Flag 0 A). De nuevo, los flags se ponen
a 1 independientemente de si sus interrupciones estn habilitadas o no. Si lo
estn, se dispararn sus interrupciones, se ejecutarn las funciones ISR
respectivas y los flags OCF0A y/o OCF0B se limpiarn por hardware. Ya sobra
decir que tambin se pueden limpiar por software escribindoles un uno.
Ambas interrupciones son gemelas pero no son siamesas, es decir, funcionan
exactamente igual pero no necesariamente se tienen que habilitar las dos al
mismo tiempo. Se habilitan por separado seteando el bit OCIE0A para una y
OCIE0B para la otra.
Una observacin: el circuito comparador (llamado Output Compare) trabaja
siempre sin importar en qu modo est operando el Timer0 (Normal, CTC o PWM),
aunque las implicancias no sern las mismas. Explico: una coincidencia en modo
CTC resetea el registro TCNT0, mientras que en los otros modos el registro
TCNT0 sigue su marchar sin hacer caso. Si captaste mi chchara, habrs
descubierto que es posible temporizar con la Interrupcin en Coincidencia
incluso si el Timer trabaja en modo PWM.

El Timer0 y el Timer2 Como Contadores


El modo Contador de los Timers es una variante de su operacin en modo Normal.
Se dice contador porque cuenta los pulsos (o flancos) de la seal aplicada en
un pin del megaAVR. Esto nos lleva de regreso a la configuracin del reloj del

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.

La limitacin es que el Timer2 solo se incrementa con los flancos


negativos de la seal externa, en tanto que el Timers0/1 puede programarse
para que su avance sea con los flancos de bajada o de subida.
La mejora es que el reloj externo del Timer2 s pasa por el prescaler. En
el Timer0/1 esto no es as por lo que el registro TCNT0 se incrementa o
decrementa en uno por cada flanco de la seal externa. Se puede programar
el factor de prescaler del Timer2 para que tenga un avance personalizado.
Por ejemplo, si escogemos un factor de 8, entonces el registro TCNT0 podr
incrementarse cada 8 pulsos detectados en el pin TOSC1.
Puedes ir a la seccin El Prescaler del Timer0 y del Timer2 para revisar
la estructura de los prescalers.

En el Timer0 debemos configurar los bits de CS02:CS00 a 110 111.

En el Timer2 los bits CS nos dan ms opciones.

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.

El Timer0 y el Timer2 en Modo PWM


Inicialmente era el Timer1 el que fue plenamente equipado para generar ondas
PWM. Si bien los otros Timers tambin ofrecen esa funcionalidad, an tienen
muchas limitaciones.
El Timer0 de los AVR actuales puede producir hasta dos canales PWM, por los
pines OC0A y OC0B. El Timer2 hace lo propio por los pines OC2A y OC2B. En los
AVR clsicos cada uno de estos Timers genera un solo canal PWM.
La principal desventaja de los Timers 0 y 2 respecto de los Timers 1 y 3 est
en la resolucin de sus ondas PWM.
En los Timers 0 y 2 la resolucin de cada onda es de 8 bits como mximo, por el
mismo hecho de que trabajan con registros de 8 bits. De hecho, la resolucin es
siempre de 8 bits, a menos que se desee mutilar un canal PWM. En ese caso, la
resolucin puede disminuir.
Por lo dems el mecanismo de generacin de las ondas PWM es el mismo en todos
los Timers, as que te sugiero que vayas a la seccin del Timer1 para entender
los detalles. All se describen y distinguen los modos Fast PWM, PWM de Fase
correcta y PWM de Fase y frecuencia Correctas. Si despus, de pasar por all
todava te quedaran algunas dudas, puedes revisar las descripciones de los
registros del Timer0 y de los registros del Timer2. Creo que con todo eso no
hay pierde.

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;

// PA0 salida de seal

/* Configuracin del Timer0


* Modo de operacin = Normal
* Factor de prescaler = 256
*/
TCCR0A = 0x00;
TCCR0B = (1<<CS02);
while(1)
{
PINA = 0x01;
Pause();
}

// 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);

// Limpiar flag de desbordamiento del Timer0

while((TIFR0&(1<<TOV0))==0); // Esperar hasta que ocurra el desbordamiento


nop(); nop();
nop(); nop();
nop(); nop();
nop(); nop();
// NOPs para ajustar la precisin
nop(); nop();
nop(); nop();
nop(); nop();
nop(); nop();
nop();
}

Descripcin del programa


El punto crucial del programa es el clculo de la temporizacin. Segn mi
cdigo, para que la seal cambie de nivel cada 2.5 ms, la funcin Pause debera
tomar 2499.55s, ya que el bucle llega a dicha llamada cada 0.45 s (lo vi en
el simulador del Studio 5). Por supuesto, este valor puede variar de un
compilador a otro porque cada cual compila a su modo. Inclusive vara en un
mismo compilador segn el nivel de optimizacin establecido o segn el
microcontrolador usado. Esta exposicin la hago habiendo compilado el cdigo
con AVR GCC con nivel de optimizacin Os.
while(1)
{
PINA = 0x01;
Pause();

// Loop forever
// Conmutar pin PA0
// Delay de 2499.55 us

23
}
El factor de prescaler sera:

Y el valor inicial del TCNT0 es:

El ajuste de la temporizacin se ha conseguido aadiendo algunos nops en Pause.


Esto es tiempo muerto pero son solo 2 us, nada comparado con los 2500 us del
total. Para calibrar estas precisiones es aconsejable recurrir al Cronmetro de
Proteus o al Stopwatch del Studio 5.
Quiz te puedas preguntar qu gracia tiene realizar temporizaciones de este
modo, si bien se pueden usar los delays? En primer lugar, los conocidos delays
nunca son precisos de por s y, en segundo lugar, son muy susceptibles de
sufrir dilataciones debido a las interrupciones. Adems, significan tiempo
muerto que impiden que el CPU ejecute otras tareas. Por ejemplo, cmo haras
si quisieras revisar el estado del puerto serie continuamente pero solo por 1
segundo?, acaso le pondras un delay de 1s? No, verdad? Bueno, puede haber
varias soluciones pero la ms recomendada suele ser usando delays a base de
Timers, en especial con sus interrupciones.
Prctica: Interrupcin del Timer0
Se genera una onda cuadrada de frecuencia 500 Hz. Quiz creas que no es una
prctica muy provechosa pero en realidad en la gran mayora de aplicaciones el
Timer0 funciona como se ver aqu. Depender del diseador saber qu hacer con
esta seal. Por ejemplo, aqu generaremos una onda PWM y al mismo tiempo una
seal para bascular un LED en intervalos largos de tiempo, ms all de lo que
permite el prescaler. Esta onda PWM se genera a nivel software y no tiene nada
que ver con el modo PWM de los Timer0 (generado por hardware y con muchsima
mejor performance). Esto es solo una demostracin y hasta parece que el mismo
datasheet recomienda no hacerlo. Pero como deca, se podrn encontrar otras
aplicaciones donde la seal generada sea ms til, como las ondas PRM para
controlar la velocidad de los motores de sus primeros robots que utilizaba Dale
Heatherington.
La onda PWM ser de 500 Hz y con duty cycle variable mediante las teclas + y
del teclado. A la salida se puede conectar un pequeo motor DC o simplemente un
LED, cuya intensidad de brillo variar.

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);

// Reponer registro TCNT0


// 1-> Salida de seal PWM
// 0-> Salida de seal PWM

if(++Dgen > MaxDuty)


Dgen = 1;

//
// Rango de Dgen es [1:MaxDuty]

if(++ticks == 5000)
{
PINA = (1<<1);
ticks = 0;
}

// Sig. bloque se ejecuta cada 5000100u = 500ms


// Conmutar pin PA0 (LED)

}
/******************************************************************************
* 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--;
}
}
}
}

Descripcin del programa


El principio el Timer0 trabaja en modo Normal como en el programa anterior,
solo que se le configura para que dispare interrupciones cada 100 s. Ahora no
interesa por qu 100 s. El hecho es que para tal cometido los clculos
indicaban que el factor de prescaler N deba ser de 8 y el valor a recargar
en TCNT0 deba ser de 156, tal como se ve abajo.

Y el valor inicial del TCNT0 ser:

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;
}

// Sig. bloque se ejecuta cada 5000100u = 500ms


// Conmutar pin PA0 (LED)

Lo hecho equivale a hacer una temporizacin grande a base de varias


temporizaciones menores. Otro ejemplo podra ser temporizar 50 segundos
partindolos en 50000. Habamos hablado de esto en las secciones tericas,
cuando veamos los ejemplos cuyos clculos no daban soluciones. Tambin se
pueden aadir ms contadores para multiplicar ms temporizaciones, o emplear
ms variables como Dutyy Dgen para sacar otros canales PWM y controlar varios
motores... Las ideas sobran.
No voy a explicar el algoritmo de generacin de la onda PWM porque creo que no
viene al caso y porque es fcil de deducir. Posteriormente estudiaremos los
Timers en modos PWM para generar ondas PWM de alta frecuencia y a nivel
hardware.
Una observacin final: en la funcin principal el programa sondea el puerto
serie para ver si llegaron datos. Tambin se pudo utilizar la interrupcin de
recepcin del USART para esta tarea y as poner al AVR en algn modo Sleep para

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);

// PA0 -> Salida LED

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

MOC_OFF() (PORTA |= (1<<0))


MOC_ON() (PORTA &= ~(1<<0))

volatile unsigned char top


= 0;
volatile unsigned char duty = 0;
volatile unsigned char ticks = 0;
//*****************************************************************************
// Gestor de Interrupcin INT0.
// Esta funcin se ejecuta cuando se detectan flancos de subida en el pin INT0.
//*****************************************************************************
ISR (INT0_vect)
{
static unsigned char i = 0;
static unsigned int avr = 0;

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();

// Habilitacin general de interrupciones

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);
}
}
}
}

Descripcin del programa


No hay mucho que explicar. Los clculos de la temporizacin se realizaron
exactamente como en la anterior prctica. Salieron precisos y no fue necesario
realizar calibraciones ni nada.
La Interrupcin INT0 se estudi tan ampliamente como lo estamos haciendo con
los Timers. Su funcin en este programa es detectar los cruces por cero de la
seal alterna AC. En ese momento se activa el opto-acoplador y tambin se
reinicia el contador ticks, el cual tiene la funcin de medir el tiempo que
dura cada semiperiodo de la seal alterna. En el cdigo se promedian cuatro de
estos tiempos, aunque creo que hubiera sido mejor aadirle un filtro software
para los picos.
La Interrupcin en Coincidencia del Timer0 pone fin al tiempo que el optoacoplador permanece activo. Este tiempo est determinado por el valor de la
variable ticks, el cual a su vez se incrementa desde 0 hasta duty, que es el
duty cycle establecido por el usuario mediante la consola del puerto serie.
No s si seguir explicando o sugerirte que mejor vieras el resultado en un
osciloscopio, aunque sea en Proteus. Se ve impresionante. La siguiente figura
es una captura de la onda alterna de 220V solo que recortada con un duty cycle
de 50%. Como siempre la prctica lleva su archivo de simulacin de Proteus y la
puedes descargar haciendo clic en la imagen del circuito.

35

Prctica: El Timer0/2 Como Contador


La prctica no puede ser ms sencilla: el Timer0 contar los flancos de bajada
generados por un pulsador conectado al pin T0 del AVR. El valor del
registro TCNT0 ser enviado al terminal serial. No se pondr ningn mecanismo
anti-rebote. As que el Timer0 se incrementar con todo y los rebotes.

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);

// Activar pull-up de pin PB0/T0

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

TCCR0A Timer/Counter Control Register 0 A


TCCR0A
COM0A1:0

COM0A1

COM0A0

COM0B1

COM0B0

---

---

WGM01

Compare Match Output A Mode


Estos bits controlan el comportamiento del pin Output
Compare (OC0A). Si uno o los dos bits COM0A1:0 estn
seteados, la salida OC0A tiene prioridad sobre la
funcionalidad normal del pin al que est conectado. Sin
embargo, note que el bit del registro DDR correspondiente
al pin OC0A debe estar configurado como salida para
habilitar el driver de salida.
Cuando OC0A est conectado al pin la funcin de los bits
COM0A1:0 depende de la configuracin de los bits WGM02:0.
La siguiente tabla muestra la funcionalidad de los bits
COM0A1:0 cuando los bits WGM02:0 estn configurados en
COM0A1

COM0A0

Descripcin

OC0A desconectado.
puerto

OC0A
OCR0A

OC0A se limpia en Coincidencia de TCNT0 y


OCR0A

OC0A se setea en Coincidencia de TCNT0 y


OCR0A

conmuta

modo Normal o CTC(no PWM).

en

Operacin

Coincidencia

normal
de

TCNT0

de
y

WGM00

38
TCCR0A

COM0A1

COM0A0

COM0B1

COM0B0

---

---

WGM01

La siguiente tabla muestra la funcionalidad de los bits


COM0A1:0 cuando
los bits WGM02:0 estn configurados
en modo Fast PWM.
Nota: ocurre un caso especial cuando OCR0A es el tope del
conteo y el bit COM0A1 vale uno. En este caso se ignora
la Coincidencia, pero la puesta a cero o a uno de OC0A se
produce al llegar a 0x00.
COM0A1

COM0A0

Descripcin

OC0A desconectado. Operacin normal del pin

WGM02 = 0: OC0A Desconectado, Operacin


normal
del
puerto.
WGM02 = 1: OC0A conmuta en Coincidencia.

OC0A se limpia en la Coincidencia, y se setea


al llegar a 0x00 (modo no-invertido)

OC0A se setea en la Coincidencia, y se limpia


al llegar a 0x00 (modo invertido).

La siguiente tabla muestra la funcionalidad de los bits


COM0A1:0 cuando los bits WGM02:0 estn configurados en
modo PWM de Fase Correcta.
Nota: ocurre un caso especial cuando OCR0A es el tope del
conteo y el bit COM0A1 vale uno. En este caso se ignora
la Coincidencia, pero la puesta a cero o a uno de OC0A se
produce al llegar al tope.

COM0B1:0

COM0A1

COM0A0

Descripcin

OC0A desconectado. Operacin normal del pin

WGM02 = 0: OC0A Desconectado, Operacin


normal
del
puerto.
WGM02 = 1: OC0A conmuta en Coincidencia.

OC0A se limpia en la Coincidencia cuando se


cuenta hacia arriba, y se setea en la
Coincidencia cuando se cuenta hacia abajo.

OC0A se setea en la Coincidencia cuando se


cuenta hacia arriba, y se limpia en la
Coincidencia cuando se cuenta hacia abajo.

Compare Match Output B Mode


Estos bits controlan el comportamiento del pin Output
Compare (OC0B). si uno o los dos bits COM0B1:0 estn
seteados, la salida OC0B tiene prioridad sobre la
funcionalidad normal del pin al que est conectado. Sin
embargo, note que el bit del registro DDR correspondiente
al pin OC0B debe estar configurado como salida para
habilitar el driver de salida.

WGM00

39
TCCR0A

COM0A1

COM0A0

COM0B1

COM0B0

---

---

WGM01

Cuando OC0B est conectado al pin la funcin de los bits


COM0B1:0 depende de la configuracin de los bits WGM02:0.
La siguiente tabla muestra la funcionalidad de los bits
COM0B1:0 cuando los bits WGM02:0 estn configurados en
COM0B1

COM0B0

Descripcin

OC0B
desconectado.
puerto

OC0B
OCR0B

OC0B se limpia en Coincidencia de TCNT0 y


OCR0B

OC0B se setea en Coincidencia de TCNT0 y


OCR0B

conmuta

en

Operacin

Coincidencia

normal
de

de

TCNT0

modo Normal o CTC(no PWM).


La siguiente tabla muestra la funcionalidad de los bits
COM0B1:0 cuando los bits WGM02:0 estn configurados en
modo Fast PWM.
Nota: ocurre un caso especial cuando OCR0B es el tope del
conteo y el bit COM0B1 vale uno. En este caso se ignora
la Coincidencia, pero la puesta a cero o a uno de OC0B se
COM0B1

COM0B0

Descripcin

OC0B desconectado. Operacin normal del pin

Reservado

OC0A se limpia en la Coincidencia, y se


setea al llegar a 0x00 (modo no-invertido)

OC0A se setea en la Coincidencia, y


limpia al llegar a 0x00 (modo invertido).

se

produce al llegar a 0x00.


La siguiente tabla muestra la funcionalidad de los bits
COM0B1:0 cuando los bits WGM02:0 estn configurados en
modo PWM de Fase Correcta.
Nota: ocurre un caso especial cuando OCR0B es el tope del
conteo y el bit COM0B1 vale uno. En este caso se ignora
la Coincidencia, pero la puesta a cero o a uno de OC0B se
produce al llegar al tope.

WGM00

40
TCCR0A

COM0A1

COM0A0

COM0B1

COM0B0

---

---

WGM01

COM0B1

COM0B0

Descripcin

OC0B desconectado. Operacin normal del pin

Reservado

OC0B se limpia en la Coincidencia cuando se


cuenta hacia arriba, y se setea en la
Coincidencia cuando se cuenta hacia abajo.

OC0B se setea en la Coincidencia cuando se


cuenta hacia arriba, y se limpia en la
Coincidencia cuando se cuenta hacia abajo.

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

Waveform Generation Mode


Estos bits se combinan con el bit WFGM02 del registro
TCCR0B. Juntos controlan la secuencia de conteo del
contador, el valor mximo del conteo (el tope) y el tipo
de la forma de onda que se generar. Los modos operacin
que soporta la unidad del Timer/Counter son: modo Normal
(contador), modo Clear Timer on Compare Match (CTC), y
dos tipos de Modulacin de Ancho de Pulso (PWM).
WGM02

WGM01

WGM00

Modo de Operacin del


Timer0

Tope del
Conteo

Normal

0xFF

PWM de Fase Correcta

0xFF

CTC

Fast PWM

0xFF

Reservado

---

PWM de Fase Correcta

Reservado

---

Fast PWM

OCR0A

OCR0A

OCR0A

WGM00

41
TCCR0B Timer/Counter Control Register 0 B
TCCR0B FOC0A
FOC0A

FOC0B

---

---

WGM02

CS02

CS01

Force Output Compare A


El bit FOC0A solo est activo cuando los bits WGM establecen un
modo no PWM.
Sin
embargo,
para
asegurar
la
compatibilidad
con
futuros
dispositivos, este bit se debe mantener en cero al escribir en
TCCRB cuando el Timer est operando en uno de los modos PWM. Si se
escribe un uno en el bit FOCA, se fuerza una Coincidencia
inmediata en la Unidad Generadora de Forma de Onda. La salida de
OC0A cambia de acuerdo con la configuracin de los bits COM0A1:0.
Note que el bit FOC0A se implementa como strobe. As que es el
valor presente en los COM0A1:0 los que determinan el efecto de la
Coincidencia forzada.
Un strobe de FOC0A no generar ninguna interrupcin ni tampoco
resetear el Timer en modo CTC si se usa OCR0A como tope del
conteo.
El bit FOC0A siempre se lee como cero.

FOC0B

Force Output Compare B


El bit FOC0B solo est activo cuando los bits WGM establecen un
modo no PWM.
Sin
embargo,
para
asegurar
la
compatibilidad
con
futuros
dispositivos, este bit se debe mantener en cero al escribir en
TCCRB cuando est operando en modo PWM. Si se escribe un uno en el
bit FOC0B, se fuerza una Coincidencia inmediata en la Unidad
Generadora de Forma de Onda. La salida de FOC0B cambia de acuerdo
con la configuracin de los bits COM0B1:0. Note que el bit FOC0B
se implementa como strobe. As que es el valor presente en los
COM0B1:0 los que determinan el efecto de la Coincidencia forzada.
Un strobe de FOC0B no generar ninguna interrupcin ni tampoco
resetear el Timer en modo CTC si se usa OCR0B como tope del
conteo.
El bit FOC0B siempre se lee como cero.

Bits
5:4

Reservados

WGM02

Waveform Generation Mode

Estos bits estn reservados y siempre se leern como cero.


Ver la descripcin de los bits WGM01:0 del registro TCCR0A.

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

Sin fuente de reloj (el Timer0 est detenido)

F_CPU (Sin prescaler)

F_CPU/8 (con prescaler)

F_CPU/64 (con prescaler)

F_CPU/256 (con prescaler)

F_CPU/1024 (con prescaler)

Reloj
externo
en
El Timer0 avanza con el flanco de
Reloj
externo
en
El Timer0 avanza con el flanco de

CS00

Fuente de reloj del Timer0

pin
T0.
bajada.
pin
T0.
subida.

TCNT0 Timer/Counter 0 Register

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 Output Compare Register 0 A

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 Output Compare Register 0 B


OCR0B
Bits 7:0

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

Timer/Counter Output Compare Match B Interrupt Enable

TOIE0

Estos bits estn reservados y siempre se leern como cero.

Cuando se escribe uno en el bit OCIE0B y el bit I del


registro SREG vale uno, se habilita la Interrupcin en
Coincidencia
B
del
Timer/Counter0.
Si
ocurre
una
Coincidencia entre TCNT0 y OCR0B se ejecutar la funcin de
interrupcin correspondiente, esto es, cuando se active el
flag OCF0B del registro TIFR0.
OCIE0A

Timer/Counter Output Compare Match A Interrupt Enable


Cuando se escribe uno en el bit OCIE0A, y el bit I del
registro SREG vale uno, se habilita la Interrupcin en
Coincidencia
A
del
Timer/Counter0.
Si
ocurre
una
Coincidencia entre TCNT0 y OCR0A, se ejecutar la funcin de
interrupcin correspondiente, esto es, cuando se active el
flag OCF0A del registro TIFR0.

TOIE0

Timer/Counter0 Overflow Interrupt Enable


Cuando se escribe uno en el bit TOIE0, y el bit I del
registro SREG vale uno, se habilita la Interrupcin por
Desbordamiento
del
Timer/Counter0.
Si
ocurre
un
Desbordamiento en el registro TCNT0, se ejecutar la funcin
de Interrupcin correspondiente, esto es, cuando se active
al flag TOV0 del registro TIFR0.

TIFR0 Timer/Counter Interrupt Flag 0 Register


TIFR0

---

---

---

---

---

OCF0B

OCF0A

Bits
7:3

Reserved

OCF0B

Timer/Counter 0 Output Compare B Match Flag


El bit OCF0B se setea cuando ocurre una Coincidencia entre los
datos de los registros TCNT0 y OCR0B. El flag OCF0B se limpia
por hardware al ejecutarse su correspondiente funcin de
interrupcin. Alternativamente se puede limpiar escribiendo en
l un uno lgico. Cuando valgan uno el bit I de SREG, el bit
de enable OCIE0B y el bit de flag OCF0B, entonces se ejecutar
la Interrupcin en Coincidencia B del Timer/Counter0.

Estos bits estn reservados y siempre se leern como cero.

TOV0

44
TIFR0

---

---

---

---

---

OCF0B

OCF0A

OCF0A

Timer/Counter 0 Output Compare A Match Flag


El bit OCF0A se setea cuando ocurre una Coincidencia entre los
datos de los registros TCNT0 y OCR0A. El flag OCF0A se limpia
por hardware al ejecutarse su correspondiente funcin de
interrupcin. Alternativamente se puede limpiar escribiendo en
l un uno lgico. Cuando valgan uno el bit I de SREG, el bit
de enable OCIE0A y el bit de flag OCF0A, entonces se ejecutar
la Interrupcin en Coincidencia A del Timer/Counter0.

TOV0

Timer/Counter0 Overflow Flag


El bit TOV0 se setea cuando ocurre un Desbordamiento del
registro TCNT0. El flag TOV0 se limpia por hardware al
ejecutarse
su
correspondiente
funcin
de
interrupcin.
Alternativamente se puede limpiar escribiendo en l un uno
lgico. Cuando valgan uno el bit I de SREG, el bit de enable
OCIE0A y el bit de flag OCF0A, entonces se ejecutar la
Interrupcin
por
Desbordamiento
del
Timer/Counter0.
La activacin de este flag depende de la configuracin de los
bits WGM02:0.

TOV0

GTCCR General Timer/Counter Control Register


GTCCR
TSM

TSM

---

---

---

---

---

PSRASY

PSRSYNC

Timer/Counter Synchronization Mode


Al escribir uno en el bit TSM se activa el modo de
Sincronizacin del Timer/Counter. En este modo, se
mantendrn los valores que se escriban en los bits PSRASY
y PSRSYNC, para mantener activadas las seales de reset
del prescaler correspondiente. Esto asegura que los
correspondientes Timers/Counters estn detenidos y se
puedan configurar al mismo valor sin correr el riesgo de
que uno de ellos avance durante la configuracin.
Si se escribe un cero en el bit TSM, los bits PSRASY y
PSRSYNC se limpian por hardware y los Timers/Counters
empiezan a contar simultneamente.

PSRASY

Prescaler Reset Timer/Counter2


Cuando este bit vale uno, el prescaler del Timer/Counter2
se resetear. Normalmente este bit se limpia de inmediato
por hardware. Si se escribe en este bit cuando el
Timer/Counter2 est trabajando en modo asncrono, el bit
permanecer en uno hasta que se resetee el prescaler. El
bit no se limpiar por hardware si el bit TSM vale uno.

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.

Registros del Timer2

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

Fuente de reloj del Timer2

Sin fuente de reloj (Timer/Counter2 detenido).

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

ASSR Asynchronous Status Register

(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.

ASSR --- EXCLK

AS2

TCN2UB

OCR2AUB

OCR2BUB

TCR2AUB

EXCLK

Enable External Clock Input


Al escribir uno en el bit EXCLK, y se tiene seleccionado
el reloj asncrono, se habilita el buffer de entrada de
reloj externo y se puede poner un reloj externo al pin
Timer Oscillator 1 (TOSC1) en vez del XTAL de 32kHz. La
escritura en EXCLK se debera realizar antes de
seleccionar la operacin asncrona.
Note que el oscilador de XTAL solo trabajar cuando este
bit vale cero.

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

Timer/Counter2 Update Busy


Cuando el Timer/Counter2 opera en modo asncrono y se
escribe en el registro TCNT2, este bit se activa a uno.
Este bit se limpiar por hardware cuando TCNT2 se
actualice desde el registro de almacenamiento temporal.
Un cero lgico en este bit indica que el registro TCNT2
est listo para ser actualizado con un nuevo valor.

OCR2AUB

Output Compare Register2 A Update Busy


Cuando el Timer/Counter2 opera en modo asncrono y se
escribe en el registro OCR2A, este bit se activa a uno.
Este bit se limpiar por hardware cuando OCR2A se
actualice desde el registro de almacenamiento temporal.
Un cero lgico en este bit indica que el registro OCR2A
est listo para ser actualizado con un nuevo valor.

OCR2BUB

Output Compare Register2 B Update Busy


Cuando el Timer/Counter2 opera en modo asncrono y se
escribe en el registro OCR2B, este bit se activa a uno.
Este bit se limpiar por hardware cuando OCR2B se

TCR2BUB

47
ASSR --- EXCLK

AS2

TCN2UB

OCR2AUB

OCR2BUB

TCR2AUB

TCR2BUB

actualice desde el registro de almacenamiento temporal.


Un cero lgico en este bit indica que el registro OCR2B
est listo para ser actualizado con un nuevo valor.
TCR2AUB

Timer/Counter Control Register2 A Update Busy


Cuando el Timer/Counter2 opera en modo asncrono y se
escribe en el registro TCCR2A, este bit se activa a uno.
Este bit se limpiar por hardware cuando TCCR2A se
actualice desde el registro de almacenamiento temporal.
Un cero lgico en este bit indica que el registro TCCR2A
est listo para ser actualizado con un nuevo valor.

TCR2BUB

Timer/Counter Control Register2 B Update Busy


Cuando el Timer/Counter2 opera en modo asncrono y se
escribe en el registro TCCR2B, este bit se activa a uno.
Este bit se limpiar por hardware cuando TCCR2B se
actualice desde el registro de almacenamiento temporal.
Un cero lgico en este bit indica que el registro TCCR2B
est listo para ser actualizado con un nuevo valor.

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

OCR1A = unin de OCR1AH y OCR1AL


OCR1B = unin de OCR1BH y OCR1BL
ICR1 = unin de ICR1H e ICR1L

Los
registros
de
control
del
Timer1
bits: TCCR1A, TCCR1B, TCCR1C, TIMSK1,TIFR1 y GTCCR.

siguen

siendo

de

48

Diagrama de bloques del Timer1.


Este diagrama del Timer2 es una adaptacin que nos facilitar su descripcin
funcional. Es una descripcin corta para no redundar demasiado sobre lo
explicado para el Timer0. Bueno, empecemos:
Los bits WGM configuran en gran medida el modo de operacin del Timer2. Con
ellos podemos escoger entre los modos Normal, CTC o PWM. Notemos que a
diferencia del Timer0, ahora son 4 bits WGM. Esto es porque el Timer2 ofrece
muchas variantes de los modos CTC y sobre todo PWM. Hay 16 modos en total, pero
muchos de ellos son redundantes y de poca utilidad.
Inicio
de
Conteo

Tope
de
Conteo

Normal

0x00

0xFFFF

PWM de Fase Correcta, 8 bits

0x00

0x00FF

PWM de Fase Correcta, 9 bits

0x00

0x01FF

PWM de Fase Correcta 10 bits

0x00

0x03FF

CTC

0x00

OCR1A

Fast PWM, 8 bits

0x00

0x00FF

Fast PWM, 9 bits

0x00

0x01FF

0x00

0x03FF

0x00

ICR1

Fast PWM, 10 bits


PWM de Fase y Frecuencia
Correctas
PWM de Fase y Frecuencia
Correctas

0x00

OCR1A

WGM13

WGM12

WGM11

WGM10

Modo de Operacin del Timer1

49
Inicio
de
Conteo

Tope
de
Conteo

PWM de Fase Correcta

0x00

ICR1

PWM de Fase Correcta

0x00

OCR1A

CTC

0x00

ICR1

Reservado

0x00

Fast PWM

0x00

ICR1

Fast PWM

0x00

OCR1A

WGM13

WGM12

WGM11

WGM10

Modo de Operacin del Timer1

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

Fuente de reloj del Timer1

Sin fuente de reloj (el Timer1 est detenido)

F_CPU (Sin prescaler)

F_CPU/8 (con prescaler)

F_CPU/64 (con prescaler)

F_CPU/256 (con prescaler)

F_CPU/1024 (con prescaler)


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.

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.

Diagrama de bloques de la Entrada de Captura.


El Timer1 y el Timer3 en Modos Normal y CTC
Con su registro TCNT1 de 16 bits, el Timer1 puede contar desde 0x0000 hasta
0xFFFF. En modo Normal y en modo CTC avanza siempre en modo ascendente. En modo
Normal llega hasta 0xFFFF y en modo CTC avanza hasta que coincida con el valor
del registro OCR1A o ICR1 que tambin son de 16 bits. El conteo es siempre
cclico, o sea que despus de llegar a su valor tope, la cuenta se reinicia
desde 0. Notamos que el modo CTC con tope de conteo establecido por registro
ICR1 no era una opcin disponible en los Timers de 8 bits. Este modo se
selecciona con los bits WGM13:0 = 1100b.

51

Cualquiera que sea su modo de operacin, el registro de conteo TCNT1 siempre es


comparado con los registros OCR1A y OCR1B. Las Coincidencias detectadas
activarn los flags OCF1A y OCF1B, respectivamente (ver el diagrama de bloques)
y se pueden usar estos eventos para programar las interrupciones de
Coincidencias setenado los bits del registro TIMSK1 OCIE1A para la coincidencia
entreTCNT1 y OCR1A, y OCIE1B para la coincidencia entre TCNT1 y OCR1B.
Si bien pueden usarse las Coincidencias como seales para setear, limpiar o
conmutar el estado de los pines OC1A y/o OC1B, segn la configuracin de los
bits COM, nunca he visto una aplicacin que saque provecho de esa
caracterstica. El Timer1 se reserva de forma casi exclusiva para el modo PWM y
es raro verlo trabajar incluso en los modos Normal o CTC. Con todo, si hubiera
que hacerlo, no hay mucho que aadir sobre la operacin de los Timers0 o 2 en
ese modo. Obviamente, las frmulas de temporizacin adoptarn nuevas formas,
teniendo en cuenta los 16 bits del Timer1.
El Tiempo que pasar entre la carga del Timer1 con un valor inicial TCNT1 hasta
su desbordamiento est dado por:

Las siguientes formulas nos dan un camino para hallar por partes las dos
incgnitas de la primera frmula.

Si el Timer1 est programado en modo CTC, el tiempo entre coincidencia y


coincidencia de TCNT1 conTOPE podemos calcular utilizando la frmula.

52

En este caso la frmula se puede descomponer en las siguientes dos frmulas de


una sola variable.

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

Modo de Operacin del Timer1

Inicio
de
Conteo

Tope
de
Conteo

PWM de Fase Correcta, 8 bits

0x00

0x00FF

PWM de Fase Correcta, 9 bits

0x00

0x01FF

PWM de Fase Correcta, 10 bits

0x00

0x03FF

Fast PWM, 8 bits

0x00

0x00FF

Fast PWM, 9 bits

0x00

0x01FF

0x00

0x03FF

0x00

ICR1

0x00

OCR1A

Fast PWM, 10 bits


PWM de Fase y Frecuencia
Correctas
PWM de Fase y Frecuencia
Correctas
PWM de Fase Correcta

0x00

ICR1

PWM de Fase Correcta

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.

El flag de desbordamiento TOV1 se activa cada vez que el contador alcanza el


tope. Adicionalmente, cuando se usa OCR1A o ICR1 para definir el tope del
conteo, el flag OCF1A o ICF1 se activa en el mismo ciclo de reloj del Timer en
que se setea TOV1. Si est habilitada una de las interrupciones, se puede usar
la funcin ISR para actualizar el valor tope.

55
La frecuencia de la onda Fast PWM se puede calcular con la siguiente ecuacin.

La variable N representa el factor de prescaler (1, 8, 64, 256 1024)


Los
valores
extremos
del
registro OCR1A representan
casos
especiales.
Si OCR1A es igual a 0x0000 la salida ser un pico angosto para cada ciclo de
reloj del Timer de tope+1. Si OCR1A es igual al tope, la salida ser un estado
constante de alto o bajo (dependiendo de la polaridad de la salida establecida
por los bits COM).
PWM de Fase Correcta
Al igual que el modo PWM de Fase y Frecuencia Correctas, el modo PWM de fase
correcta est basado en una operacin de doble pendiente, esto es, el Timer
cuenta repetidamente desde 0x0000 hasta el tope y luego desde el tope hasta
0x0000. En el modo no-invertido, la salida se limpia en la coincidencia
entre TCNT1 y OCR1A si la cuenta es ascendente y se setea en la coincidencia si
el conteo es descendente. En modo invertido la operacin es inversa.
Debido a la operacin de doble pendiente la frecuencia de la seal PWM ser
menor que la que se puede obtener en modo Fast PWM. Sin embargo, la simetra de
su onda la hace preferible para las aplicaciones de control de motores.

Los registros OCR1A y OCR1B se actualizan


cuando el contador llegue al tope.

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.

Cuando el valor de OCR1A/OCR1B es igual a cero, la salida en modo no-invertido


es un estado bajo constante, a diferencia del modo Fast PWM donde aparecen unos
delgados picos.
PWM de Fase y Frecuencia Correctas
La principal diferencia entre el modo PWM de Fase y Frecuencia Correctas y el
modo
de Fase
Correcta es
el
tiempo
en
que
se
actualizan
los
registros OCR1A/OCR1B desde su buffer doble.

57

En contraste con el modo de Fase Correcta, la figura muestra que la salida


generada
es,
simtrica
en
todos
sus
periodos.
Puesto
que
los
registros OCR1A/OCR1B se actualizan al llegar a 0x0000, las pendientes de
subida y de bajada sern siempre iguales. Esto brinda pulsos de salida
simtricos y por tanto de frecuencia correcta.
El flag de Desbordamiento TOV1 se activa cuando el contador llega a 0x0000.
Cuando se usaOCR1A como tope del contador, su flag OCF1A se activar
cuando TCNT1 alcance el tope. Se pueden usar estos flags para generar las
interrupciones correspondientes.
Los registros OCR1A/OCR1B se actualizan desde su buffer doble en el mismo ciclo
de reloj del Timer en que el contador llega a 0x0000.
Registros del Timer1
TCCR1A

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

TCCR1A Timer/Counter Control Register 1 A


TCCR1A COM1A1

COM1A0

COM1B1

COM1B0

---

COM1A1:0

Compare Output Mode for Channel A

COM1B1:0

Compare Output Mode for Channel B

---

WGM11

Los bits COM1A1:0 y COM1A1:0 controlan el comportamiento de los


pines Output Compare (OC1A y OC1B, respectivamente). Si uno o
los dos bits COM1A1:0 estn seteados, la salida OC0A tiene
prioridad sobre la funcionalidad normal del pin al que est
conectado. Si uno o los dos bits COM1B1:0 estn seteados, la
salida OC0B tiene prioridad sobre la funcionalidad normal del
pin al que est conectado. Sin embargo, note que el bit del
registro DDR correspondiente al pin OC0A o OC0B debe estar
configurado como salida para habilitar el driver de salida.
Cuando OC0A o OC0B est conectado al pin la funcin de los bits
COM1x1:0 depende de la configuracin de los bits WGM13:0. La
siguiente tabla muestra la funcionalidad de los bits COM1x1:0
cuando
los
bits
WGM13:0
estn
configurados
en
modo Normal o CTC (no PWM).
COM1A1/
COM1B1

COM1A0/
COM1B0

OC0A/OC0B conmuta en Coincidencia

OC0A/OC0B se limpia en Coincidencia

OC0A/OC0B se setea en Coincidencia

Descripcin
OC0A/OC0B
de pin

desconectado.

Operacin

normal

La siguiente tabla muestra la funcionalidad de los bits


COM1A1:0 cuando
los bits WGM13:0 estn configurados en modo
Fast PWM.

Nota: ocurre un caso especial cuando OCR1A/OCR1B es el tope del

WGM10

59
TCCR1A COM1A1

COM1A0

COM1B1

COM1B0

---

---

WGM11

conteo y el bit COM1A1/COM1B1 vale uno. En este caso se ignora


la Coincidencia, pero la puesta a cero o a uno de OC0A/OC0B se
produce al llegar a 0x0000.
COM1A1/ COM1A0/
COM1B0
COM1B1

Descripcin

OC1A/OC1B desconectado. Operacin normal del


pin

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

OC1A/OC1B se limpia en la Coincidencia, y se


setea al llegar a 0x0000 (modo no-invertido)

OC1A/OC1B se setea en la Coincidencia, y se


limpia al llegar a 0x00 (modo invertido).

La siguiente tabla muestra la funcionalidad de los bits


COM1A1:0 cuando
los bits WGM13:0 estn configurados en
modo PWM de Fase Correcta o PWM de Fase y Frecuencia Correctas.
Nota: ocurre un caso especial cuando OCR1A
conteo y el bit COM1A1/COM1B1 vale uno...

es

el

del

COM1A1/
COM1B1

COM1A0/
COM1B0

Descripcin

OC1A/OC1B desconectado. Operacin normal del


pin

WGM13:0
=
9
u
Coincidencia, OC1B
normal de pin).

11:
OC1A
conmuta
en
desconectado (operacin

Para las dems configuraciones


OC1A/OC1B desconectado (operacin
pin).

Bits 3:2

tope

de WGM1,
normal de

OC1A/OC1B se limpia en la Coincidencia cuando


se cuenta hacia arriba, y se setea en la
Coincidencia cuando se cuenta hacia abajo.

OC1A/OC1B se setea en la Coincidencia cuando


se cuenta hacia arriba, y se limpia en la
Coincidencia cuando se cuenta hacia abajo.

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

leern como cero.

WGM11:0

Waveform Generation Mode


Estos bits se combinan con los bits WFGM13:2 del registro
TCCR1B. Juntos controlan la secuencia de conteo del
contador, el valor mximo del conteo (el tope) y el tipo
de la forma de onda que se generar. Los modos operacin
que soporta la unidad del Timer/Counter son: modo Normal
(contador), modo Clear Timer on Compare Match (CTC), y
tres tipos de Modulacin de Ancho de Pulso (PWM).
WGM13 WGM12 WGM11 WGM10

Modo de Operacin del Timer1

Tope
del
Conteo

Normal

0xFFFF

PWM de Fase Correcta, 8 bits

0x00FF

PWM de Fase Correcta, 9 bits

0x01FF

PWM de
bits

0x03FF

CTC

Fast PWM, 8 bits

0x00FF

Fast PWM, 9 bits

0x01FF

Fast PWM, 10 bits

0x03FF

PWM de Fase
Correctas
PWM de Fase
Correctas

PWM de Fase Correcta

ICR1

PWM de Fase Correcta

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

Input Capture Noise Canceler


La escritura de uno en este bit activa el circuito
eliminador de ruido Input Capture Noise Canceler del Timer1.
Cuando el eliminador de ruido est activado, la entrada del
pin Input Capture (ICP1) ser filtrada. La funcin del
filtro requiere de la igualdad de cuatro muestreos del pin
ICP1 para cambiar su estado. Debido a esto, cuando el
eliminador de ruido est habilitado, la unidad de Input
Capture se retrasa por cuatro ciclos del oscilador.

ICES1

Input Capture Edge Select


Este bit selecciona el flanco en el pin Input Capture (ICP1)
que se usar para disparar el evento de captura. Cuando el
bit ICES1 vale uno, el disparo se dar en el flanco de
bajada, y si ICES1 vale cero, el disparo se dar en el
flanco de subida.
Cuando
se
dispara
una
captura
de
acuerdo
con
la
configuracin del bit ICES1, el valor del contador se
copiar al registro Input Capture Register (ICR1). El evento
tambin setear el flag Input Capture (ICF1), y se puede
usar para generar una Interrupcin de Input Capture, si esta
interrupcin est habilitada.
Cuando se usa como el tope de conteo el registro ICR1 (ver
la descripcin de los bits WGM13:0 ubicados en los registros
TCCR1A y TCCR1B), ICP1 queda desconectado y por tanto se
deshabilita la funcin de Input Capture.

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

Waveform Generation Mode


Ver la descripcin de los bits WGM11:0 del registro TCCR1A.

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

Si se usan los modos de pin externo para el Timer/Counter1,


las transiciones en el pin T1 harn el contador incluso si
el pin est configurado como salida. Esta caracterstica
permite el control software del contador.
CS12

CS11

CS10

Fuente de reloj del Timer1

F_CPU (Sin prescaler)

F_CPU/8 (con prescaler)

F_CPU/64 (con prescaler)

F_CPU/256 (con prescaler)

F_CPU/1024 (con prescaler)

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 Timer/Counter Control Register 1 C

TCCR1C FOC1A

FOC1B

---

FOC1A

Force Output Compare A

FOC1B

Force Output Compare B

---

Los bits FOC1A/FOC1B solo estn


WGM13:0 establecen un modo no PWM.

---

activos

---

cuando

---

los

bits

Sin embargo, para asegurar la compatibilidad con futuros


dispositivos, estos bits se deben mantener en cero al escribir
en TCCR1C cuando el Timer est operando en uno de los modos
PWM. Si se escribe un uno en el bit FOC1A/FOC1B, se fuerza una
Coincidencia inmediata en la Unidad Generadora de Forma de
Onda. La salida de OC1A/OC1B cambia de acuerdo con la
configuracin de los bits COM1A1:0/COM1B1:0. Note que los bits
FOC1A/FOC1B se implementan como strobes. As que es el valor
presente en los bits COM1A1:0/COM1B1:0 los que determinan el
efecto de la Coincidencia forzada.
Un strobe de FOC1A/FOC1B no generar ninguna interrupcin ni
tampoco resetear el Timer en modo CTC si se usa OCR1A como

---

63
TCCR1C FOC1A

FOC1B

---

---

---

---

---

---

tope del conteo.


Los bits FOC1A/FOC1B siempre se leen como cero.
Bits
5:0

Reservados
Estos bits estn reservados y siempre se leern como cero.

TCNT1H y TCNT1L Timer/Counter 1 Register

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.

OCR1AH y OCR1AL Output Compare Register 1 A

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 y OCR1BL Output Compare Register 1 B


OCR1BH
OCR1BL
Bits
15:0

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.

ICR1H y ICR1L Input Capture Register 1


ICR1H
ICR1L

Bits
15:0

ICR1H [7:0] y ICR1L [7:0]


El registro Input Capture se actualiza con el valor del contador (TCNT1)
cada vez que ocurre un evento en el pin ICP1 (u opcionalmente en la salida
del Comparador Analgico que va al Timer/Counter1). Se puede usar el
registro Input Capture para definir el valor tope del conteo.
El registro Input Capture es de 16 bits. Para asegurar que sus dos bytes 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 (ICR1H). Este registro temporal es compartido por todos los
dems registros de 16 bits.

65
TIMSK1 Timer/Counter Interrupt Mask 1 Register
TIMSK1

--

---

Bits
7:6

Reserved

Bits
4:3

Reserved

ICIE1

---

---

OCIE1B

OCIE1A

TOIE1

Estos bits estn reservados y siempre se leern como cero.


Timer/Counter1, Input Capture Interrupt Enable

ICIE1

Al escribir uno en este bit, y el bit enable general I del registro


SREG vale uno, se habilita la Interrupcin Input Capture del
Timer/Counter1. Al activarse el flag ICF1, del registro TIFR1, se
ejecutar su respectiva funcin de interrupcin ISR.
OCIE1B

Timer/Counter1, Output Compare B Match Interrupt Enable


Al escribir uno en este bit, y el bit enable general I del registro
SREG vale uno, se habilita la Interrupcin en Coincidencia B del
Timer/Counter1. Al activarse el flag OCF1B, del registro TIFR1, se
ejecutar su respectiva funcin de interrupcin ISR.

OCIE1A

Timer/Counter1, Output Compare A Match Interrupt Enable


Al escribir uno en este bit, y el bit enable general I del registro
SREG vale uno, se habilita la Interrupcin en Coincidencia A del
Timer/Counter1. Al activarse el flag OCF1A, del registro TIFR1, se
ejecutar su respectiva funcin de interrupcin ISR.

TOIE1

Timer/Counter1 Overflow Interrupt Enable


Cuando se escribe uno en el bit TOIE1, y el bit I del registro SREG
vale uno, se habilita la Interrupcin por Desbordamiento del
Timer/Counter1. Si ocurre un Desbordamiento en el registro TCNT1,
se ejecutar la funcin de Interrupcin correspondiente, esto es,
cuando se active al flag TOV1 del registro TIFR1.

TIFR1 Timer/Counter Interrupt Flag 1 Register


TIFR1

--

---

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

Timer/Counter1, Output Compare B Match Flag


Este flag se activa en el ciclo de reloj del Timer despus de
que el valor del contador (TCNT1) coincida con el registro

TOV1

66
TIFR1

--

---

ICF1

---

---

OCF1B

OCF1A

TOV1

Output Compare B (OCR1B).


Note que una Coincidencia forzada con el bit FOC1B no activar
el flag OCF1B.
El flag OCF1B se limpia por hardware al ejecutarse su
correspondiente funcin de interrupcin. Alternativamente se
puede limpiar escribiendo en l un uno lgico.
OCF1A

Timer/Counter1, Output Compare A Match Flag


Este flag se activa en el ciclo de reloj del Timer despus de
que el valor del contador (TCNT1) coincida con el registro
Output Compare A (OCR1A).
Note que una Coincidencia forzada con el bit FOC1A no activar
el flag OCF1A.
El flag OCF1A se limpia por hardware al ejecutarse su
correspondiente funcin de interrupcin. Alternativamente se
puede limpiar escribiendo en l un uno lgico.

TOV1

Timer/Counter1, Overflow Flag


La activacin de este flag depende de la configuracin de los
bits WGM13:0. En los modos Normal y CTC el flag TOV1 se activa
cuando se desborda el Timer1.
El flag TOV1 se limpia por hardware al ejecutarse su
correspondiente funcin de interrupcin. Alternativamente se
puede limpiar escribiendo en l un uno lgico.

GTCCR General Timer/Counter Control Register


GTCCR

TSM

TSM

---

---

---

---

---

PSRASY

Timer/Counter Synchronization Mode


Al escribir uno en el bit TSM se activa el modo de
Sincronizacin del Timer/Counter. En este modo, se
mantendrn los valores que se escriban en los bits PSRASY
y PSRSYNC, para mantener activadas las seales de reset
del prescaler correspondiente. Esto asegura que los
correspondientes Timers estn detenidos y se puedan
configurar al mismo valor sin correr el riesgo de que uno
de ellos avance durante la configuracin.
Si se escribe un cero en el bit TSM, los bits PSRASY y
PSRSYNC se limpian por hardware y los Timers/Counters
empiezan a contar simultneamente.

PSRASY

Prescaler Reset Timer/Counter2


Cuando este bit vale uno, el prescaler del Timer/Counter2
se resetear. Normalmente este bit se limpia de inmediato
por hardware. Si se escribe en este bit cuando el
Timer/Counter2 est trabajando en modo asncrono, el bit

PSRSYNC

67
GTCCR

TSM

---

---

---

---

---

PSRASY

PSRSYNC

permanecer en uno hasta que se resetee el prescaler. El


bit no se limpiar por hardware si el bit TSM vale uno.
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.

Registros del Timer3


TCCR3A

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

registro a modificar ");


-> Frecuencia");
-> Duty cycle A");
-> Duty cycle B\r");

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
}

Das könnte Ihnen auch gefallen