- ¿Por qué Timer cuando tenemos Delay ()?
- Temporizadores del microcontrolador PIC:
- Programación y explicación de trabajo:
- Diagrama de circuito y simulación de Proteus:
Este será el quinto tutorial de nuestra serie de tutoriales PIC, que le ayudará a aprender y utilizar los temporizadores en PIC16F877A. En nuestros tutoriales anteriores, habíamos comenzado con Introducción a PIC y MPLABX IDE, luego escribimos nuestro primer programa PIC para hacer parpadear el LED usando PIC y luego hicimos una secuencia de parpadeo de LED usando la función de retardo en el microcontrolador PIC. Ahora usemos la misma secuencia de parpadeo de LED que hemos usado en el hardware del tutorial anterior y con esto aprenderemos a usar los temporizadores en nuestro PIC MCU. Acabamos de agregar un botón más en la placa LED para este tutorial. Siga el tutorial para obtener más información.
Los temporizadores son uno de los caballos de batalla importantes para un programador integrado. Cada aplicación que diseñamos involucrará de alguna manera una aplicación de tiempo, como encender o apagar algo después de un intervalo de tiempo específico. De acuerdo, pero ¿por qué necesitamos temporizadores cuando ya tenemos macros de retardo (__delay_ms ()) haciendo lo mismo?
¿Por qué Timer cuando tenemos Delay ()?
Una macro de retardo se denomina retardo de "volcado". Debido a que durante la ejecución de la función Delay, la MCU realiza un volcado simplemente creando un retraso. Durante este proceso, la MCU no puede escuchar sus valores ADC ni leer nada de sus registros. Por lo tanto, no es aconsejable utilizar las funciones de Retraso, excepto para aplicaciones como el parpadeo de LED donde el Retardo de tiempo no necesita ser preciso o largo.
Las macros de retardo también tienen las siguientes deficiencias,
- El valor de la demora debe ser una constante para las macros de demora; no se puede cambiar durante la ejecución del programa. De ahí que quede definido por el programador.
- El retraso no será exacto en comparación con el uso de temporizadores.
- No se pueden crear valores más grandes de retrasos utilizando macros, por ejemplo, un retraso de media hora no se puede crear mediante macros de retraso. El retardo máximo que se puede utilizar se basa en el oscilador Crystal utilizado.
Temporizadores del microcontrolador PIC:
Físicamente, el temporizador es un registro cuyo valor aumenta continuamente a 255, y luego comienza de nuevo: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3……etc.
La MCU PIC PIC16F877A tiene tres módulos de temporizador. Son nombres como Timer0, Timer1 y Timer2. El temporizador 0 y el temporizador 2 son temporizadores de 8 bits y el temporizador 1 es un temporizador de 16 bits. En este tutorial usaremos el Timer 0 para nuestra aplicación. Una vez que entendamos el Timer 0, será fácil trabajar con Timer 1 y Timer 2 también.
El temporizador / contador del módulo Timer0 tiene las siguientes características:
- Temporizador / contador de 8 bits
- Legible y escribible
- Prescaler programable por software de 8 bits
- Selección de reloj interno o externo
- Interrupción por desbordamiento de FFh a 00h
- Selección de borde para reloj externo
Para comenzar a usar un temporizador, debemos comprender algunos de los términos elegantes como temporizador de 8 bits / 16 bits, preescalador, interrupciones del temporizador y focos. Ahora, veamos qué significa realmente cada uno. Como se dijo anteriormente, existen temporizadores de 8 y 16 bits en nuestra MCU PIC, la principal diferencia entre ellos es que el temporizador de 16 bits tiene una resolución mucho mejor que el temporizador de 8 bits.
Prescaler es un nombre para la parte de un microcontrolador que divide el reloj del oscilador antes de que alcance la lógica que aumenta el estado del temporizador. El rango de la identificación del preescaler es de 1 a 256 y el valor del preescalador se puede configurar usando el registro de OPCIÓN (el mismo que usamos para las resistencias de extracción). Por ejemplo, si el valor de contador de impulsos preliminar es de 64, a continuación, para cada 64 º pulso el temporizador se incrementa en 1.
A medida que el temporizador aumenta y cuando alcanza su valor máximo de 255, activará una interrupción y se inicializará a 0 nuevamente. Esta interrupción se denomina interrupción del temporizador. Esta interrupción informa a la MCU que este tiempo en particular ha transcurrido.
El Fosc significa Frecuencia del Oscilador, es la frecuencia del Cristal utilizado. El tiempo que tarda el registro de temporizador depende del valor de Prescaler y del valor de Fosc.
Programación y explicación de trabajo:
En este tutorial configuraremos dos botones como dos entradas y 8 LED como 8 salidas. El primer botón se utilizará para configurar el tiempo de retardo (500 ms por cada pulsación) y el segundo botón se utilizará para iniciar la secuencia del temporizador a parpadear. Por ejemplo, si se presiona el primer botón tres veces (500 * 3 = 1500ms), la demora se establecerá en 1.5 segundos y cuando se presione el botón dos, cada LED se encenderá y apagará con el tiempo de demora predefinido. Consulte el video de demostración al final de este tutorial.
Ahora, con estos conceptos básicos en mente, veamos nuestro programa al final de la sección Código.
Está bien si no recibió el programa, ¡pero si lo recibió! Dése una cookie y descargue el programa para disfrutar de su salida. Para otros, dividiré el programa en partes significativas y les explicaré lo que está sucediendo en cada bloque.
Como siempre las primeras líneas del código son los ajustes de configuración y los archivos de encabezado, no voy a explicar esto ya que ya lo hice en mis tutoriales anteriores.
A continuación, saltemos todas las líneas y saltemos directamente a la función principal void, dentro de la cual tenemos la configuración PORT para el Timer0.
void main () {/ ***** Configuración de puerto para el temporizador ****** / OPTION_REG = 0b00000101; // Timer0 con frecuencia externa y 64 como prescalar // También habilita PULL UPs TMR0 = 100; // Cargue el valor de tiempo para 0.0019968s; delayValue puede estar entre 0-256 solo TMR0IE = 1; // Habilita el bit de interrupción del temporizador en el registro PIE1 GIE = 1; // Habilitar interrupción global PEIE = 1; // Habilitar la interrupción de periféricos / *********** ______ *********** /
Para entender esto tenemos que mirar el Registro de OPCIONES en nuestra hoja de datos de PIC.
Como se discutió en el tutorial anterior, el bit 7 se usa para habilitar una resistencia de extracción débil para el PORTB. Mire la figura anterior, el bit 3 se hace 0 para indicar a la MCU que el siguiente preescalador que se está configurando debe usarse para el temporizador y no para el WatchDogTimer (WDT). El modo de temporizador se selecciona borrando el bit 5 T0CS
(OPTION_REG <5>)
Ahora, los bits2-0 se utilizan para establecer el valor del preescalador para el temporizador. Como se muestra en la tabla anterior, para establecer un valor de preescalador de 64, los bits deben establecerse como 101.
A continuación, echemos un vistazo a los registros asociados con Timer0
El temporizador comenzará a incrementarse una vez configurado y se desbordará después de alcanzar un valor de 256, para habilitar la interrupción del temporizador durante este punto, el registro TMR0IE debe establecerse alto. Dado que el temporizador 0 en sí mismo es un periférico, tenemos que habilitar la interrupción del periférico haciendo PEIE = 1. Finalmente tenemos que habilitar la Interrupción Global para que la MCU sea notificada sobre la Interrupción durante cualquier operación, esto se hace haciendo GIE = 1.
Retraso = ((256-REG_val) * (Prescal * 4)) / Fosc
La fórmula anterior se utiliza para calcular el valor de Retraso.
Dónde
REG_val = 100;
Prescal = 64
Fosc = 20000000
Esto en el cálculo da, Retraso = 0.0019968s
El siguiente conjunto de líneas es para configurar los puertos de E / S.
/ ***** Configuración de puerto para E / S ****** / TRISB0 = 1; // Indique a la MCU que el pin 0 de PORTB se utiliza como entrada para el botón 1. TRISB1 = 1; // Indique al MCU que el pin 1 de PORTB se utiliza como entrada para el botón 1. TRISD = 0x00; // Indique a la MCU que todos los pines del PUERTO D tienen salida PORTD = 0x00; // Inicializar todos los pines a 0 / *********** ______ *********** /
Esto es lo mismo que el de nuestro tutorial anterior, ya que estamos usando el mismo hardware. Excepto que hemos agregado otro botón como entrada. Esto se hace mediante la línea TRISB1 = 1.
A continuación, el bucle while de adentro hacia afuera infinito tenemos dos bloques de código. Uno se utiliza para obtener la entrada del temporizador del usuario y el otro para ejecutar la secuencia de retardo sobre los LED. Los he explicado usando comentarios en cada línea.
while (1) {cuenta = 0; // No ejecutar el temporizador mientras está en el bucle principal // ******* Obtener el retraso numérico del usuario **** ////// if (RB0 == 0 && flag == 0) // Cuando entrada dada {get_scnds + = 1; // get_scnds = get_scnds + http: // Indicador de variable de incremento = 1; } if (RB0 == 1) // Para evitar incrementos continuos flag = 0; / *********** ______ *********** /
Una variable llamada get_scnds se incrementa cada vez que el usuario presiona el botón 1. Se utiliza una variable de bandera (definida por software) para mantener el proceso de incremento hasta que el usuario retira el dedo del botón.
// ******* Ejecutar secuencia con retardo **** ////// while (RB1 == 0) {PORTD = 0b00000001 <
El siguiente bloque entra en acción si se presiona el botón dos. Dado que el usuario ya ha definido el retardo de tiempo requerido usando el botón uno y se ha guardado en la variable get_scnds. Usamos una variable llamada hscnd, esta variable es controlada por el ISR (rutina de servicio de interrupción).
La rutina del servicio de interrupción es una interrupción que se llamará cada vez que el Timer0 se desborde. Veamos cómo lo está controlando el ISR en el siguiente bloque, como si quisiéramos incrementar el retardo de tiempo en medio segundo (0.5s) en cada pulsación de botón, luego necesitamos incrementar la variable hscnd por cada medio segundo. Como hemos programado nuestro temporizador para que se desborde cada 0.0019968s (~ 2ms), para contar la variable de conteo de medio segundo debe ser 250 porque 250 * 2ms = 0.5 segundo. Entonces, cuando el conteo obtiene 250 (250 * 2ms = 0.5 segundo), significa que ha pasado medio segundo, por lo que incrementamos hscnd en 1 e inicializamos el conteo a cero.
void interrupt timer_isr () {if (TMR0IF == 1) // La bandera del temporizador se ha activado debido a un desbordamiento del temporizador {TMR0 = 100; // Carga el temporizador Valor TMR0IF = 0; // Borrar el conteo de banderas de interrupción del temporizador ++; } si (cuenta == 250) {hscnd + = 1; // hscnd se incrementará por cada medio segundo count = 0; }}
Así que usamos este valor y lo comparamos con nuestro hscnd y cambiamos nuestro LED según el tiempo definido por el usuario. También es muy similar al último tutorial.
Eso es todo, tenemos nuestro programa entendido y funcionando.
Diagrama de circuito y simulación de Proteus:
Como de costumbre, primero verifiquemos la salida usando Proteus, he vinculado aquí los archivos esquemáticos de Proteus.
Agregue un botón a nuestra placa LED anterior y nuestro hardware está listo para funcionar. Debería verse algo como esto:
Una vez realizada la conexión, cargue el código y verifique la salida. Si tiene algún problema, utilice la sección de comentarios. También consulte el video a continuación para comprender todo el proceso.