1 TUTORIAL OBJETIVOS Familiarizarse con el TMR0 como contador de pulsos internos y generador de retardos. Conocer el método del polling para verificar banderas de dispositivos. Crear y manipular variables INTRODUCCIÓN En esta práctica pretendemos utilizar el timer 0 como contador de pulsos internos para generar bases de tiempo. Inicialmente lo usaremos para generar retardos variables para controlar la velocidad de un motor paso a paso. En una segunda parte de este tutorial incrementaremos una variable cada cierto tiempo (es decir realizaremos un conteo) y utilizaremos displays de 7 segmentos para visualizar los datos. PRIMERA PARTE: GENERACIÓN DE UN RETARDO CON TIMER. CONCEPTOS: El timer0: Un temporizador es un módulo que se encarga de contar ya sea tiempos (pulsos del reloj interno) o pulsos externos (pulsos recibidos por el pin RA para este caso particular). El timer0 trabaja sobre un registro llamado TMR0 en el cual guarda el conteo actual de los pulsos (8 bits) y es controlado por un registro llamado OPTION_REG (el cual también controla otras funciones del microcontrolador). A continuación se ilustra el registro de control y la función de cada uno de sus bits. OPTION_REG: Bit 7: RBPU: Cuando está en cero activa las pullups del puerto B, no se usa para controlar el TMR0 pero se usará mas adelante. Bit 6: INTEDG: No se usa para el TMR0, se usa para la interrupción externa. Bit 5: T0CS: Acá indicamos cual es la fuente para el conteo, en uno indica que se contaran pulso externos por el pin RA (T0CKI) (contador) en cero indicaran que se cuentan ciclos internos de instrucción del microcontrolador (temporizador) (1 ciclo de instrucción = ciclos del reloj). 1
2 Bit : T0SE: Si se esta utilizando como contador de eventos por RA, en este bit se indica si se incrementa en un flanco de subida (0) o de bajada (1). Bit 3: PSA: Asignación del preescaler, el preescaler es un módulo que permite incrementar el conteo cada dos, cuatro, ocho, dieciséis... pulsos en lugar de incrementarlo en cada pulso, al colocarlo en cero el preescaler se asignara al TMR0, de resto se asignará al WDT. Bit 2-0: PS2 PS0: Acá seleccionamos el valor del preescaler según la siguiente tabla: Desbordamiento del TMR0: El Tmr0 trabaja sobre un registro de 8 bits, por lo tanto su máximo valor alcanzable es 255, cuando alcanza este valor el próximo pulso que sea contado causará el desbordamiento del TMR0, en este momento el Tmr0 volverá al valor de 0 y una bandera llamada T0IF (del registro INTCON) será activada indicando que ha sucedido desbordamiento, está bandera puede disparar una interrupción si esta está habilitada. Para generar un retardo (o una base de tiempo) utilizando el TMR0 o cualquier otro temporizador procedemos de la siguiente manera: Cargamos un valor inicial en TMR0, en este momento el TMR0 empieza a contar a partir de dicho valor, luego verificamos cuando se ha cumplido el tiempo al saber cuando se desbordó el timer, ya sea preguntando continuamente por la bandera T0IF, o por medio de una interrupción. El tiempo generado a partir de este retardo estará dado por la fórmula: Tiempo = Fosc ( 256 TMR0) Pr eescaler Donde Fosc es la frecuencia de oscilador usada, TMR0 es el valor cargado inicialmente en dicho registro y preescaler es el valor escogido en el OPTION_REG. Ejemplo: 2
3 Para generar un retardo de 10ms, usando un preescaler de 1:128 tendríamos y un oscilador de Mhz tendríamos: 10ms = ( 256 TMR0)128 Mhz ( 10ms) ( ) Mhz TMR 0 = 256 = 177.8 128 Obviamente, solo podemos escribir valores enteros, por lo tanto escogemos el valor de TMR0 igual 178 y obtenemos un pequeño error por la aproximación. El código para el retardo sería de la siguiente forma: OPTION=0b00000110; //En la configuración, TMR0 como contador interno //preescaler 1:128 TMR0=178; while(t0if==0) //Cargo el valor del retardo //Limpio bandera de desbordamiento. //Espero que se cumpla el tiempo. En la instrucción while(t0if==0) el microcontrolador estará preguntando continuamente por la bandera de desbordamiento del TMR0, cuando haya transcurrido el tiempo de retardo el timer se desbordará y se pondrá en 1 la bandera del TMR0, por lo tanto el microcontrolador saldrá de este ciclo y continuará la ejecución. Al simular el retardo anterior obtenemos un tiempo de: 9.99ms. El retardo más grande que puede obtenerse por medio de este método, a un cristal de Mhz sería: Tiempo = 53 Mhz ( 256 0) 256 = 65. ms El cual es relativamente pequeño, en especial si se buscan retardos como en nuestro caso del orden de 200 o 300ms necesitamos llamar varias veces el retardo. En ocasiones se utilizan variables para contar varias veces el retardo. Basados en lo anterior podemos realizar un código que permita mover un motor de paso a paso utilizando una secuencia normal con retardo variable, para ello leeremos un valor de 8 bits en el puerto B, dicho valor será cargado en TMR0 para generar un retardo variable, además se agregará un swiche en RA0 para controlar el sentido de giro, se propone el siguiente código: 3
#include <pic.h> void retardo (void); void main (void) //Configuración de puertos TRISD=0b11110000; TRISB=0b11111111; //PORTB son entradas // TRISA=0b11111111; //PORTA son entradas ADCON1=6; ANSEL=0x00; ANSELH=0x00; OPTION=0b00000111; while(1) PORTD=0b00001000; PORTD=0b00000100; PORTD=0b00000010; PORTD=0b00000001; //Opcional //Configuro TMR0. void retardo (void) while(t0if==0) ; //Subrutina para el retardo variable
5 En el código anterior se ha hecho uso de subrutinas para evitar copiar varias veces el código del retardo. Obsérvese que si se introduce un valor muy cercano a 256 en el puerto B el tiempo de retardo generado será muy pequeño y el motor empezará a oscilar. ESQUEMA DE CONEXIONES: 5