Recursos del PIC - Uso del TMR1 como Temporizador

Tutorial que trata sobre el uso del TMR1 del PIC

MICROCONTROLADORES

Biblioman

3/12/20107 min read

Continuamos con el curso de C con CCS, esta vez con la utilización de un nuevo recurso, que todavía no habíamos visto: el Timer1.

El Timer1 es un temporizador/contador ascendente parecido al TMR0, pero con algunas peculiaridades que lo hacen muy interesante a la hora de incluir temporizaciones en nuestros programas.
La primera de ellas, es que se trata de un contador de 16 bits cuyo valor se almacena en dos registros de 8 bits el TMR1H y el TMR1L, ambos registros se pueden leer y escribir su valor durante la ejecución del programa.

Cuando el Timer1 está habilitado, el valor de esos registros se incrementan desde 0000h a FFFFh y una vez que llega a su máximo valor empieza otra vez desde 0 avisándonos de ello por medio de la bandera TMR1F .
Si está activa la interrupción por desbordamiento del Timer 1 al desbordarse el contador, el programa entra en la función de tratamiento a la interrupción por desbordamiento del Timer1.

El diagrama de bloques es el siguiente:

Algunas características de este Timer son las siguientes:

  • El Timer1 puede funcionar con un oscilador externo y trabajar a una frecuencia distinta a la del oscilador principal del PIC.

  • Al igual que el TMR0 el Timer1 puede operar en dos modos: como temporizador y como contador. El modo de funcionamiento está determinado por el tipo de reloj seleccionado (interno -->temporizador, externo -->contador), lo configuramos por medio del bit TMR1CS del registro TICON. Cuando está en modo contador su valor se incrementa en cada flanco de subida de la señal de reloj externa.

  • El tiempo que se tarda en incrementarse el contador se le suele llamar paso, el paso del contador depende de la frecuencia del oscilador y del prescaler seleccionado.

  • La fórmula para determinar los tiempos del Timer1 cuando es utilizado como temporizador (Reloj interno) es la siguiente:

  • El paso del contador vendrá determinado por:

Paso_Contador= 4/Frecuencia Oscilación.Prescaler

  • El Timer1 se puede habilitar o deshabilitar por medio del bit TMR1ON del registro T1CON.


Un dibujo con los bits de configuración del registro TICON, lo tenéis en la figura de abajo:

Vamos a ver un ejemplo sencillo (como siempre) de como utilizar el Timer1 como temporizador usando el reloj interno del micro. El ejemplo consiste simplemente en hacer parpadear un led a un intervalo de 0.5 segundos, usando el Timer1 con la interrupción por desbordamiento habilitada.

Para ello tenemos como siempre dos opciones, escribir nosotros todo el código o ayudarnos por medio del asistente que trae CCS. Cualquiera de las opciones es valida, ya que el código es muy sencillo.

El que utilice el asistente, deberá configurar primeramente el micro a utilizar y la frecuencia de reloj. Yo voy ha utilizar el PIC16f877 y un cristal de 4MHz (el viejo amigo de batallas PIC16f84A no dispone de este recurso).

Después en el apartado timers habrá que configurar los parámetros para el Timer1, como vamos a trabajar con el Timer1 en modo Temporizador, en el tipo de reloj seleccionaremos Internal, después seleccionaremos una resolución entre las cuatro disponibles, según se muestra en la figura de abajo.

La resolución es el tiempo que tarda el contador en incrementar su valor, es decir, el paso del
contador. Este valor, como hemos dicho ya, depende del Preescaler seleccionado y de la frecuencia del reloj principal. Por ejemplo, si seleccionamos la última opción le estamos diciendo al asistente que queremos un preescaler de 8 y como hemos seleccionado una frecuencia de 4MHz para el reloj principal, el paso del contador será igual a:

4/Frecuencia Oscilación.Prescaler= 4/4MHz.8= 8u segundos.

El asistente también nos muestra el Overflow, que como hemos dicho también, es el tiempo que tardará el contador en desbordarse. Suponiendo que carguemos el TMR1 con valor 0, que es como viene por defecto, si aplicamos la formula obtendremos el valor de 524ms (Desbordamiento_Timer1= 4/4MHz*8(65536-0)= 524 ms).

Como en vez de 524 ms, queremos obtener 500 ms. Sustituimos ese valor en la fórmula y despejamos el valor a cargar en el TMR1:

El valor de TMR1 que sale es de 3036 que en hexadecimal es: 0x0BDC

Por último solo nos queda decirle al asistente que queremos utilizar la interrupción por desbordamiento del Timer 1, según se muestra en la figura de abajo:

El código de nuestro ejemplo quedará de la siguiente forma:

#include <16F887.h>//Pic utilizado

//Palabra de configuración de los fusibles.

#FUSES NOWDT, XT, NOPUT, NOMCLR, NOPROTECT, NOCPD, NOBROWNOUT, NOIESO, NOFCMEN,

NOLVP, NODEBUG, NOWRT, BORV40

#use delay(clock=4000000)//Frecuencia del reloj principal

#bit RB7=0x06.7 //Identificador para el bit RB7

#int_TIMER1

void TIMER1_isr(void)//Función de interrupción por desbordamiento TMR1

{

RB7=~RB7; //Togle RB7

set_timer1(0x0BDC);//carga del TMR1

}

void main()

{

set_tris_b(0b01111111); //configura RB7 como salida el resto como entrada

RB7=0;//Inicializo RB7

setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);//Setup timer: Reloj interno, preescaler= 8

enable_interrupts(INT_TIMER1);//Habilito interrupción particular del TIMER1

enable_interrupts(GLOBAL);//Habilito interrupciones globales

set_timer1(0x0BDC);//Carga del TMR1

while(true);//Bucle infinito hasta interrupción

}

Siempre hay que limpiar un poco el código que nos genera el asistente, de parámetros y opciones que están deshabilitadas y que no nos sirven para nada.

El circuito a montar en Proteus, será el siguiente:

En el que se ha incluido una gráfica digital para medir el intervalo de tiempo de parpadeo del diodo LED.

Si hacemos un zoom sobre la gráfica y añadimos un segundo cursor (Ctrl+c), podemos ver que el intervalo es de 500 ms.

Comentario del programa:

El programa de lo sencillo que es, está más que explicado con los comentarios hechos en el código fuente. Solo comentar las funciones que incluye CCS para el control del Timer1:

  • set_timer1(value); //Función para inicializar los registros TMR1H y TMR1L.

  • value=get_timer1; //Función para leer el valor del timer1

  • setup_timer_1 (parámetros);//configuración del Timer1 por medio de parámetros. Los parámetros pueden ser:

    • T1_DISABLED: deshabilita el Timer1, esto me permite un ahorro de energía en el PIC si no utilizo este recurso.

    • T1_INTERNAL: fuente de reloj, el principal. Modo temporizador.

    • T1_EXTERNAL: fuente de reloj externa. El timer funcionara como contador y como condición para empezar el contaje debe de producirse un flanco de bajada en la señal de reloj, mira la figura de abajo:

Este pequeño detalle que parece poco importante, no lo es en el caso de que queramos contar de manera precisa los pulsos de entrada.

  • T1_EXTERNAL_SYNC: con esto le digo al compilador que la señal de reloj externa se sincronice con la señal de reloj principal. Como se ve en el diagrama de bloques la sincronización se produce después del preescaler, por lo que hasta después del preescaler la señal sigue siendo asíncrona. Hay que tener en cuenta que cuando tenemos definido este parámetro si el PIC entra en modo SLEEP el TIMER1 no se incrementará aunque este presente la señal de reloj externa.

  • T1_CLK_OUT: con este parámetro pongo a 1 el bit T1OSCEN, para habilitar el oscilador del Timer1. Cuando tengo seleccionada la fuente de reloj externa y este parámetro a la vez, me permite independizar el timer1 del oscilador principal, por lo que el timer1 seguirá contando aunque el PIC entre en modo SLEEP. La entrada de la señal de reloj será por la patilla RC0/T1OSO/TICK1 del PIC. Cuando este parámetro no está definido T1OSCEN toma el valor por defecto que es 0, en este caso y siempre y cuando este definido el parámetro T1_EXTERNAL la entrada de la señal de reloj externa será por RC1/TlOSI/CCP2. Este modo se utiliza para poder producir un reinicio del Timer1 a partir de cualquiera de los módulos CCP1 o CCP2 del PIC.

  • T1_DIV_BY_1, T1_DIV_BY_2, T1_DIV_BY_4, T1_DIV_BY_8: constantes para seleccionar el preescaler que queremos seleccionar.


Los parámetros seleccionados se colocan juntos separados por el símbolo |.

Ejemplos:

setup_timer_1 ( T1_DISABLED );
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_4 );
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 );

Fuentes de información:


En el próximo artículo (sobre CCS), veremos como utilizar el timer1 como contador, utilizando un reloj externo de 32.768Hz de frecuencia, y veremos si la precisión obtenida es suficiente para implementar un reloj en tiempo real (RTC) de Horas, minutos y segundos.

Un Saludo y hasta pronto.