MPLAB X y C18: Uso del TIMER 0 como temporizador

Una parte muy importante en los microcontroladores son los TIMERs y que serán temas que abordaremos en el blog tal vez un poco lentos pero lo haremos, para comenzar pues lo haremos con el TIMER cero, ahora bien cuando al TMR0 se controla por un evento externo se dice que se está usando como contador, por el contrario si se controla con un evento interno se está usando como temporizador que será el tema que veremos en esta ocasión, existen mas TIMERs pero eso se explicara cuando llegue su turno.

El TMR0 cuenta con las siguientes características:
  • Modo de operación como temporizador o contador, ambos casos con resolución de 8 y 16 bits.
  • Registros de lectura y escritura, ósea que podemos inicializarlo en un algún valor deseado.
  • Prescaler programable de 8 bits.
  • Permite usar una fuente de reloj externa o interna.
  • Para el modo de contador permite seleccionar con que flanco se activa al momento de conectarle el reloj externo.
  • Interrupción por desborde (overflow), ósea que cuando este llegue a una cuenta deseada podemos atenderla con alguna interrupción, cuando esto pase el programa abandona temporalmente lo que estaba haciendo para atender la subrutina de interrupción, pero antes guarda en una región especial de la memoria llamada pila la dirección de la siguiente instrucción de programa, para que cuando acabe la subrutina de interrupción pueda seguir ejecutando el programa por donde se había quedado.
En todo caso se recomienda revisar el datasheet del microcontrolador que se está usando para comprender mejor el tema. Nosotros utilizaremos el PIC18F4620 para realizar nuestros ejemplos.

Para configurar el TMR0 se utiliza el registro T0CON que se muestra a continuación:
Expliquemos un poco cada bit del registro T0CON:
  • Bit7: Permite habilitar y deshabilitar el TMR0.
  • Bit6: Permite seleccionar si el timer es de 8 o 16 bits.
  • Bit5: Permite seleccionar si el reloj va a ser interno o externo.
  • Bit4: Si el reloj es externo, permite seleccionar si aumenta el conteo con un falco se subida o uno de bajada.
  • Bit3: Permite seleccionar o no el prescalador.
  • Bit2-0: Permite seleccionar algún valor del prescalador.
Para calcular un determinado tiempo de desbordamiento del TMR0 necesitamos utilizar la siguiente fórmula:
Donde:
  • TiempoTMR0 es el tiempo al cual queremos que se desborde nuestro timer y así poder atenderlo con la interrupción.
  • Fosc es la frecuencia del oscilador usado, ya sea que se esté usando el interno o se esté usando uno externo como un cristal de cuarzo.
  • BitsTMR0, como ya se había mencionado el timer podía ser utilizado a 8 o 16 bits aquí es donde se usa ese valor, por lo que los valores disponibles serán 256 y 65536 respectivamente.
  • ValorTMR0 es el numero que escribiremos en el timer para que de allí parta su conteo en C18 este valor se escribe en los registros TMR0H y TMR0L, por ejemplo si seleccionamos el timer a 8 bits e inicializamos en 200 solo se ejecutara 56 veces ya que al llegar a 256 se desbordara.
  • Prescaler es el divisor de frecuencia a la cual queremos que cada ciclo de instrucción sea ejecutado, si no se usa solo se ignora.
Pongamos un ejemplo para que esto del TIMER se comprenda mucho mejor, lo que vamos a hacer es que nuestro TMR0 se desborde aproximadamente a 1 segundo y lo atenderemos con una interrupción para así poder encender un LED. 

Lo primero que haremos será configura el registro T0CON.
  • Bit7=1, para habilitar el TMR0.
  • Bit6=0, seleccionamos el timer a 16 bits.
  • Bit5=0, Usamos los ciclos de reloj interno.
  • Bit4=0, lo dejamos en cero ya que se está usando los ciclos del reloj interno.
  • Bit3=0, para poder usar el prescaler.
  • Bit2-0=011, seleccionamos el prescaler 1:16.
Por lo tanto tenemos que T0CON=10000011 (en binario) o 0x83 (en hexadecimal).

Ahora debemos conocer el valor que se escribirá en el TMR0 para que se posible tener un desbordamiento a 1 segundo, también es importante mencionar que usaremos el oscilador interno a 4MHz. 

Como ya tenernos todos los datos sustituimos en la formula anterior y tenemos lo siguiente:
Como lo que nos interesa saber es ValorTMR0 para escribirlo en TMR0H y TMR0L despejamos, resolvemos y obtenemos:
Para escribir el resultado en los registros TMR0H y TMR0L haremos lo siguiente, pasamos el número 3036 a hexadecimal y tenemos 0xBDC así podemos asignar su valor de la siguiente forma:

TMR0H=0x0B; y TMR0L=0xDC;

Una vez explicado todo esto pasemos a ver como quedara el circuito para este ejemplo, utilizaremos un PIC18F4620 al cual le conectaremos un LED con su debida resistencia de 330Ω al puerto RE0, también le hemos agregado su botón de RESET pero para este ejemplo no es muy necesario y si se desea se puede omitir, si se omite recordar colocar el pin MCLR a VCC para que todo funcione sin problemas, importante también mencionar que se debe de energizar el circuito con 5 volts.
Ahora bien pasemos al código que va a ser posible que nuestro ejemplo funcione, utilizaremos los archivos vistos en la publicación sobre interrupciones que son el “all_interrupts.h” y el “all_interrupts.c” así que los agregaremos a nuestro proyecto, también agregaremos el archivo “Config_FusesPIC.h” ya visto antes también y que es donde siempre configuramos los fuses de nuestro PIC, crearemos como siempre el archivo “main.c” donde ira nuestro programa principal y también crearemos dos archivos más que ocuparemos en este y otros ejemplos futuros, los cuales son “mcu.h” y “mcu.c” aquí alojaremos código con respecto a configuración de entras-salidas, osciladores, pines digitales, en fin conforme avancemos se irán utilizando, todo esto con el fin de que el código utilizado para un proyecto esté bien organizado y se mucho más fácil de entender. 

Mostrare todo el código para que el tema se lo más claro posible así que comenzare por mostrar el contenido del archivo Config_FusesPIC.h no lo explicare ya que es el que hemos venido usado anteriormente, pero igual se recomienda configurar según sus necesidades al momento de hacer otras aplicaciones o ejemplos.
Ahora muestro que es lo que tenemos en los archivos “mcu.h” y “mcu.c”.
En el archivo “mcu.h” tenemos las etiquetas que usaremos en nuestro ejemplo, como solo vamos a encender o apagar un LED cada que se desborda el TMR0 lo hemos llamado LED_STATUS, para cualquier cosa que tengamos ya sea en las entradas o salidas de nuestro PIC podemos colocarle un nombre o una etiqueta y así será más fácil acceder a ella, también se agregan las funciones que se utilizaran en el archivo “mcu.c”, dentro de este declaramos que librerías vamos a utilizar y por supuesto incluimos el PIC utilizado, también tenemos dos funciones “MCU_Init” y “TMR0_Init”, en la primera configuramos el oscilador interno a 4MHz, declaramos que vamos a utilizar entradas y salidas analógicas, declaramos el pin donde está el LED como salida de la siguiente forma LED_STATUS_TRIS=0 y lo ponemos a cero LED_STATUS=0 para que no haya nada fuera de normal, en la otra función tenemos configurado el TMR0 y las interrupciones para que nuestro código responda con una interrupción de alta prioridad cuando nuestro TMR0 se desborde. El registro T0CON=0x83 visto anteriormente será lo primero que colocares en la función seguidos de los registros TMR0H=0x0B y TMR0L=0xDC que son el valor que le cargamos al TMR0 y desde allí comenzara su conteo, TMR0IF es la bandera de interrupción y debemos colocarlo a cero de la siguiente forma INTCONbits.TMR0IF =0 y este bit pasa a ser uno cuando el TMR0 se desborde y será nuestra señal para encender o apagar el LED, con la instrucción INTCONbits.TMR0IE=1 habilitamos la interrupción por desbordamiento del TMR0, seguimos con INTCON2bits.TMR0IP=1 y este establece que la interrupción será de alta prioridad, con RCONbits.IPEN=1 nos permite utilizar los niveles de prioridad para las interrupciones ya sea alta o baja, al INTCONbits.GIEH=1 habilitamos todas las interrupciones de alta prioridad.

A continuación se ve todo el código completo de nuestro archivo “mcu.c”
Ahora tenemos el archivo “all_interrupts.h” muy cortito y donde declaramos las funciones que utilizaremos en el archivo “all_interrupts.c”.
Toda la sección de interrupciones lo explicamos anteriormente así que solo vamos a ver la parte donde atendemos nuestra interrupción por desbordamiento del TMR0, todo el código lo agregaremos en la función “high_isr” que es la encargada de atender las interrupciones de alta prioridad. A continuación todo el código:
En la función “high_isr” tenemos la condicional if(INTCONbits.TMR0IF) que es lo mismo que si escribimos if(INTCONbits.TMR0IF==1) y esta revisa si es TMR0 se ha desbordado (ha llegado a su máximo valor), si esta condicional es cierta invierte el estado del LED con la instrucción LED_STATUS^=1, después vuelve a escribir en TMR0H=0x0B y TMR0L=0xDC para que vuelva a contar siempre la misma cantidad, por ultimo colocamos INTCONbits.TMR0IF=0 para borrar nuestra bandera y que espere un nuevo desbordamiento, borrar esta bandera es importante de lo contrario no volverá a hacer caso de nuestra condicional y nuestro LED se quedara en un estado fijo.
Una vez explicado todo esto pasamos al archivo “main.c” que es el encargado de hacer todas las tareas principales y es que enlaza todos los demás archivos, bueno como siempre empezamos por definir que librerías vamos a utilizar, importante escribir #include "all_interrupts.h" y #include "mcu.h" para tener acceso a estos archivos y que nuestro código funcione correctamente, también se debe agregar la configuración de FUSES. Seguido de esto tenemos nuestra función principal “main” que es desde donde llamamos nuestra función MCU_Init() y TMR0_Init() ya explicadas anteriormente, después tenemos un bucle infinito con un WHILE(1) así que nuestro ejemplo trabajara continuamente hasta que le quitemos el voltaje de alimentación o presionemos el botón de RESET.
Espero que con esto quede claro el uso del TMR0 como temporizador, recomiendo revisar la hoja de datos del PIC para mayor información sobre cada uno de los registros utilizados. Todo esto de los timer y las interrupciones las seguiremos utilizando en futuros proyectos de mayor complejidad así que es importante tenerlos dominados par que no nos cause dolores de cabeza.

Aquí el vídeo del circuito en acción:
Aquí el enlace para DESCARGAR las librerias disponibles desde mi repositorio en GitHub, si no sabes como descargarlo puedes checar aquí, bueno por el momento es todo si tienes dudas, comentarios, sugerencias, inquietudes, traumas, etc. dejarlas y tratare lo mas pronto posible responderlas...
  • Actualización (18/10/2016): Se corrigió enlace de descarga.

No hay comentarios:

Publicar un comentario