Timers AVR

1 Contenido                        Introducción El Timer0 y el Timer2 El Reloj del Timer0 y d

Views 345 Downloads 17 File size 2MB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

1 Contenido                

   



 

Introducción El Timer0 y el Timer2 El Reloj del Timer0 y del Timer2 El Prescaler del Timer0 y del Timer2 Modos de Operación del Timer0 y Timer2 El Timer0 y el Timer2 en Modo Normal o Cálculo de la Temporización Normal El Timer0 y el Timer2 en Modo CTC o Cálculo de la Temporización CTC Interrupciones del Timer0 y el Timer2 El Timer0 y el Timer2 Como Contadores El Timer0 y el Timer2 en Modo PWM Práctica: Temporización con Sondeo del Timer0 Práctica: Interrupción del Timer0 Práctica: El Timer0 en Modo CTC Práctica: Control de Potencia Práctica: 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

2

Introducción Los Timers son módulos que trabajan en paralelo con el procesador, permitiendo que las operaciones de temporización 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 limitación, el Timer0 está más destinado a las temporizaciones y otro tanto a los conteos. El Timer2 por su parte fue diseñado con la característica adicional para trabajar con un XTAL de reloj externo, de 32kHz. A pesar de sus diferencias operativas, la configuración y control de los Timers son muy similares en todos los casos, así que por más que sean varios aprenderemos a controlarlos todos con el menor esfuerzo. Bueno, eso espero. Supongo que lo común debe ser conocer los Timer de a uno, empezando por el Timer0 hasta llegar al Timer3 o 4, si es que se llega. Pero después de revisar los diversos datasheets, creo que un mejor enfoque será abarcarlos de a dos, según su número 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 expresión. Como habrán notado, había tratado hasta donde me posible de describir las características de los periféricos de los megaAVR pensando también en los que la propia ATmel denomina “viejos AVR”, dado que aún son muy usados en la actualidad y hay muchos proyectos de interés que se basan en esos microcontroladores. Pero creo que en esta ocasión dejaré de lado ese enfoque múltiple para no recargar el tema demasiado. Como había dicho hay mucha similitud entre todos los Timers y bastaría con conocer bien el funcionamiento de uno de ellos para poder comprender los demás. Con todo eso, el estar mencionando a cada rato que tal bit tiene otro nombre en el otro AVR o que está pequeña función 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 configuración de un módulo queda reflejado en sus registros de E/S, creo que una buena idea poner al final la descripción respectiva de los registros de los Timers de los “viejos megaAVR”. Yo creo que eso será más que suficiente para programarlos bien, sin necesidad de empezar a describirlos por separado.

3 El Timer0 y el Timer2 Dada la paridad de características entre el Timer0 y el Timer2, no las vamos a mencionar simultáneamente para no fatigarnos de términos. Simplemente vamos a referirnos al Timer0 y se dará por hecho que lo mismo es aplicable para el Timer2, salvo que se indique explícitamente lo contario. Las principales diferencias se dejarán notar solo al inicio y al final, luego el tratamiento será muy parejo. Naturalmente, el trato específico preocupación pues registro y bit de

control de cada Timer a nivel de programación requiere del de sus registros de configuración. Pero tampoco esto es de lo único que cambia es el número 0 por el número 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 común 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 características distintivas del funcionamiento asíncrono de este Timer. Del mismo modo, en los nombres de los bits de cada registro, solo cambian el número 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 características, ventajas y limitaciones citadas serán 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 más que mil palabras, así que el siguiente esquema nos ayudará para entender la operación común del Timer0. Las operaciones específicas de cada modo particular las describiremos en su momento.

4

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 atrás, según se programe, impulsado por la señal 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 máximo de 255, continuará después contando desde 0 otra vez, cíclicamente. Esta transición 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. También es posible hacer que el Timer0 cuente solo hasta un tope establecido por registro OCR0A.



El Timer0 tiene dos comparadores que en todo momento están 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 serán vistos con paciencia en su sección respectiva.



Desde el punto de vista de la programación, podemos controlar el Timer0 con tres tipos de bits:

5 

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 configuración de los bits. En realidad, su función implica más 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 más 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 fácilmente examinando sus correspondientes registros de control. Es en esta sección donde nos ocuparemos de las pocas diferencias entre ellos. El reloj del Timer0 es la señal digital, periódica 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 señal 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 idénticos, 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 más grande que separa al Timer0 del Timer2. La forma como la señal externa se aplica al microcontrolador depende de cada Timer.



En el Timer0 la señal 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 señal. Notemos en el diagrama que la señal externa no pasará por su prescaler.



En el Timer2 su reloj externo puede ser de dos tipos: o es una señal aplicada al pin TOSC1 del megaAVR, en cuyo caso el Timer2 avanzará con cada flanco de bajada detectado en dicho pin; o es la señal de un oscilador de XTAL conectado entre los pines TOSC1 y TOSC2 del megaAVR. En ambos casos, la señal de reloj pasará por el prescaler del Timer2.

6 

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 sería conveniente que para tal caso la señal fuera periódica.

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á más lento, según las necesidades del diseñador. El prescaler es parte del reloj del Timer, así que para configurarlo se usan los bits de Selección 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 más que sean casi iguales, tiene efectos diferentes debido a que los prescalers son diferentes. El prescaler del Timer2 es más 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 simultáneamente con el prescaler y utilizando diferentes factores de división puesto que cada Timer tiene sus propios bits CS (de Clock Select). El único reparo sería que se debe tener cuidado al resetear el prescaler porque para esto se dispone de una única señal 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 además que de usar un reloj proveniente del pin T0, entonces no será posible usar el prescaler.

8

Ahora revisemos el prescaler del Timer2. Este prescaler ofrece más factores de división, con lo que las temporizaciones podrán ser más flexibles. A diferencia del Timer0/1, si optamos por un reloj externo aplicado al pin TOSC1, dicha señal sí podrá pasar por el prescaler. Esta vez el prescaler se puede resetear con la señal 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 señal clkT2S puede ser F_CPU o el reloj proveniente del exterior.

9

Modos de Operación 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 práctica es raro utilizar otras formas de onda que no sean de tipo PWM, así que el nombre no parece muy apropiado. En la figura también se aprecia que los GENERADORES DE ONDA también dependen de los bits COM (de Compare Output Mode). Estos bits establecen el modo en que finalmente saldrán 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 están 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 vacíos 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 cíclicamente 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, según lo estudiado en fuentes de reloj y prescalers. Recordemos que los comparadores del Timer0 pueden sacar por los pines OC0A y OC0B unas señales que se pueden configurar con los bits COM. En los modos Normal o CTC esta señal 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 temporización, que es normalmente el propósito del modo Normal o CTC, debemos escoger la primera opción, que es la predeterminada y que nos dejará los pines OC0A/OC0B libres para seguir usándolos como puertos de E/S generales.

La tabla solo muestra la configuración 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.

Cálculo de la Temporización 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 cálculo y la programación de ese tiempo el objetivo de esta sección.

12 Bueno, asumo que en este momento ya sabemos cómo configurar el reloj del Timer0 bits CS), que sabemos cómo programar el Timer0 en modo Normal (bits WGM) y que entendemos su operación en ese modo. Ahora aprenderemos a escoger la opción de reloj más adecuada para nuestras temporizaciones. Para empezar, debemos usar el reloj interno derivado de F_CPU (cuyo valor es teóricamente igual a la frecuencia del XTAL del megaAVR.), salvo que tengamos una señal externa periódica. Como sabemos, si la fuente de reloj es interna, el Timer0 y el Timer2 se programan igual. Lo único que cambiará serán los factores de prescaler.

En primer lugar veamos cómo 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 instrucción básica. 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 serán 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 después de 7us; y si usamos prescaler lo hará después de 7×8 = 56us.

Al inicio todos vemos en esto un enredo de números. Parece complejo pero solo es cuestión de encontrar el hilo de la madeja para suspirar diciendo ¡Ah…, era así de fácil! Sin embargo, hay quienes se rinden y prefieren usar fórmulas y cálculos directos como los descritos a continuación. 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 fórmula:

13

Nota: los factores de prescaler N del Timer2 son 1, 8, 32, 64, 128, 256 y 1024. Eso podría dar otras soluciones para N y TCNT2. Como ves, ésta es una ecuación con dos incógnitas (N y TCNT0) y es posible encontrar más de una solución para ambas. Sin embargo, no todas serán igualmente adecuadas. Los valores más apropiados serán los que nos permitan realizar un mejor posterior ajuste de precisión. Si eres ducho resolviendo ecuaciones de Diofanto, puedes trabajar con esa fórmula. Pero si no quieres ir tanteando, puedes emplear las siguientes dos fórmulas: (He borrado todas sus deducciones para no alargar más esta sección.)

Lo más probable es que el valor obtenido con esta fórmula no esté disponible como factor de prescaler válido (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 más cercano (“redondear” para arriba). La otra fórmula es:

Como antes, si el resultado no fuera un número entero, habría que redondearlo para arriba. Si el factor de prescaler obtenido estuviera fuera del rango permitido (más alto que 1024), se puede optar por buscar otro camino, como fragmentar la temporización. Por otro lado, si la temporización es muy fina, puede que sea necesario subir un poquito el valor de inicio del TCNT0 para realizar una calibración añadiendo algunas instrucciones de relleno como nops. Estas dos situaciones las veremos en las prácticas; 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 temporización 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 resultaría así:

Otro ejemplo. ¿Cuáles son la razón de prescaler y el valor inicial de TCNT0 para conseguir una temporización de 200 µs si nuestro megaAVR tiene un XTAL de 4 MHz? El factor de prescaler N sería:

Y el valor inicial de TCNT0 será:

Luego, la secuencia de conteo quedaría así:

Finalmente, ¿cuáles son la razón de prescaler y el valor inicial de TCNT0 para conseguir una temporización de 50 ms si se tiene un megaAVR con un XTAL de 20 MHz? El factor de prescaler sería:

15 ¿Y ahora de dónde vamos a sacar un factor de prescaler mayor que 3906.25 si el máximo es de 1024? ¿Buscamos otro Timer? Bueno, quizá podríamos temporizar 10 veces 5 ms.

El Timer0 y el Timer2 en Modo CTC

Su nombre es el acrónimo de Clear Timer on Compare Match y significa que el Timer se limpia cuando se produce una Coincidencia en la comparación de los registros TCNT0 y OCR0A. En este modo el Timer0 (su registro TCNT0) también 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 también activa el flag OCF0A, el cual se puede usar para programar interrupciones. El registro OCR0A también 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 operación descrita.

Diagrama simplificado del Timer0 para temporizaciones en modo CTC. En términos generales todo lo que puede hacer el registro OCR0A también 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, según se vea. La auto-recarga del Timer0 en modo CTC es un suceso hardware que genera las más precisas temporizaciones independientemente de si el código está escrito en ensamblador, en un compilador o en otro. Pero la no necesidad de posteriores calibraciones software también implica que si la temporización 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.

Cálculo de la Temporización en Modo CTC La fórmula que nos da el tiempo entre coincidencia y coincidencia es la siguiente. Recuerda que en modo CTC está fórmula 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 podría dar otras soluciones para N y TCNT2. De nuevo, esta ecuación tiene dos incógnitas (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, también aquí debemos tomar el factor de prescaler superior más cercano.

La segunda fórmula se obtiene despejando OCR0A de la fórmula presupone que para esto ya debimos haber hallado el valor de N.

inicial.

Se

Si conseguimos para OCR0A una solución entera válida, será genial y no tendremos que recurrir a posteriores ajustes de precisión, sin importar en qué lenguaje o compilador se programe. De lo contrario, no habrá calibración en

17 OCR0A que valga, de modo que será de poco alivio para el diseñador redondearlo a su valor más cercano, superior o inferior. En ese caso y si la precisión fuera realmente importante, se puede optar por cambiar de XTAL. Ya no vamos a poner ejemplos porque estas fórmulas se resuelven exactamente igual que en el Cálculo 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 característica más 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 aún trabajan con los viejos megaAVR, ellos no tienen interrupción 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 también controlan las interrupciones del Timer1 y del Timer2.

18 Interrupción por Desbordamiento del Timer0. El evento que puede disparar esta interrupción es el desbordamiento del registro TCNT0, o sea, la transición de 255 a 0. Esto implica la operación 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 transición 255 a 0, así que en este modo no hay desbordamiento. El desbordamiento de Timer0 activará el flag TOV0 y si la interrupción está habilitada, se disparará. El bit TOV0 se limpia automáticamente al ejecutarse su función de interrupción ISR, pero también se puede limpiar por software, como de costumbre, escribiéndole un 1 y sin usar instrucciones de lecturamodificación-escritura como las generadas por las sentencias con el operador OR binario (|). Para habilitar la interrupción por Desbordamiento del Timer0 se setean los bits TOIE0 y obviamente, el bit enable general de interrupciones I, del registro SREG. La instrucción del ensamblador dedicada a esta operación es SEI y que en lenguaje C se puede incrustar mediante la función macro del mismo nombre sei(). (No sé por qué repito estas cosas.) Interrupción en Coincidencia del Timer0. Como sabemos, los comparadores del Timer0 son circuitos que en todo momento están comparando los valores del registro TCNT0 con los registros OCR0A y OCR0B. Pues bien, el evento que puede disparar esta interrupción 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 están habilitadas o no. Si lo están, se dispararán sus interrupciones, se ejecutarán las funciones ISR respectivas y los flags OCF0A y/o OCF0B se limpiarán por hardware. Ya sobra decir que también se pueden limpiar por software escribiéndoles 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 observación: 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 serán 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 cháchara, habrás descubierto que es posible temporizar con la Interrupción 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 operación en modo Normal. Se dice contador porque cuenta los pulsos (o flancos) de la señal aplicada en un pin del megaAVR. Esto nos lleva de regreso a la configuración del reloj del

19 Timer y también a las diferencias entre el Timer0 y el Timer2 cuando sus relojes son externos. Antiguamente el Timer2 estaba más 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 características para trabajar asíncronamente con el reloj del sistema. Esa era su única forma de soportar un reloj externo, es decir, no podía 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 opción adicional de trabajar con una señal externa (sin XTAL) aplicada al pin TOSC1. De ese modo el Timer2 se pone a nivel del Timer0/1. En realidad tiene una limitación y una mejora al respecto.  



La limitación es que el Timer2 solo se incrementa con los flancos negativos de la señal 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 señal 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 sección 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 más opciones.

20 Tengamos en cuenta que, siendo el modo Contador una interpretación particular del modo Normal, siguen latentes todas las funciones de temporización del Timer0, incluyendo las interrupciones en el Desbordamiento y en las Coincidencias. De hecho, también es posible temporizar con la señal externa, siempre que sea una onda cuadrada periódica, claro está. La única consideración es que la señal de T0 o T1 jamás debería superar, o igualar siquiera, la performance del reloj del sistema F_CPU, para permitir la sincronización entre ellas. Por otro lado, el reloj externo del timer2 no está sincronizado y en ese caso la manipulación 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 también ofrecen esa funcionalidad, aún 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 clásicos 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 resolución de sus ondas PWM. En los Timers 0 y 2 la resolución de cada onda es de 8 bits como máximo, por el mismo hecho de que trabajan con registros de 8 bits. De hecho, la resolución es siempre de 8 bits, a menos que se desee mutilar un canal PWM. En ese caso, la resolución puede disminuir. Por lo demás el mecanismo de generación de las ondas PWM es el mismo en todos los Timers, así que te sugiero que vayas a la sección 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 después, de pasar por allí todavía 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 Práctica: Temporización con Sondeo del Timer0 El programa genera una onda cuadrada conmuta cada 2.5 ms, pero como ya estamos en temas serios, la temporización debe ser lo más precisa posible, ni 1 µs más ni 1 µs menos. Visto de otro modo, el programa genera una señal de onda cuadrada de 200 Hz.

El código fuente /****************************************************************************** * FileName: main.c * Purpose: Timer0 - Operación 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 redistribución de este código 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 función

//************************************************************************ // Función principal //************************************************************************ int main(void) {

22 DDRA = 0x01;

// PA0 salida de señal

/* Configuración del Timer0 * Modo de operación = Normal * Factor de prescaler = 256 */ TCCR0A = 0x00; TCCR0B = (1