jueves, 12 de abril de 2012

CONTADOR 0 - 99 CON CARGA ASÍNCRONA INGRESADA POR KEYPAD


PROYECTO Nº 2: CONTADOR 0 – 99 CON CARGA ASÍNCRONA INGRESADA POR KEYPAD

                Seguimos viendo cómo manejar los puertos del PIC para realizar funciones determinadas por nosotros. En este caso, el circuito tiene por objetivo iniciar una cuenta de 00 a 99 y reiniciarse, salvo por que desde un keypad podremos ingresar un número, y el PIC lo cargará a los contadores para que la cuenta se inicie desde este número. Si ingresásemos 21, sea en donde esté la cuenta, el sistema comenzará a contar a partir de 21. Para ello, nuevamente, analizaremos primero el hardware necesario para su implementación.
                La clave del circuito son los contadores síncronos con cuenta en BCD. Si no sabe que es síncrono o BCD, a continuación explicaré brevemente lo que significa, estos términos. Un contador síncrono es aquel que requiere una señal de reloj (la cual debe ser la misma para todos los contadores del sistema, para evitar faltas de sincronización) para que su salida cambie de un estado a otro. Es decir, que con cada pulso de reloj, el contador aumenta su cuenta en 1. El término BCD es un código de información que consiste en convertir cada cifra del número a su equivalente binario. Por ejemplo:

21=10101(2) Pero: 21=0010 0001 en BCD

Vemos como cada cifra del número se convierte a binario para formar el código BCD. De esta forma vemos que si queremos convertir un número de tres cifras, requeriremos 12 bits; si queremos hacerlo con un número de cuatro, 16 bits.
                Si aún tiene dudas, busque información adicional en Internet o bien deje su comentario expresando sus dudas para ver si podemos aclararlas. Es necesario conocer bien cómo funciona el sistema BCD para poder comprender el código usado para convertir un número ASCII en un número BCD. ¿Y por qué ASCII? El keypad generará un código ASCII que se cargará en la memoria del PIC.
                Los contadores usados son los 74HC160. Estos contadores tienen entradas de carga asíncrona (se activan en cualquier momento, independientemente del reloj), con reseteo asíncrono. Las entradas ENT y ENP son las entradas de una operación AND que se encarga de habilitar al contador. La salida RCO se encarga de generar una señal bandera cada vez que el contador de unidades llega a la cifra máxima. Es decir, cuando el contador de unidades llega a 9, RCO es 1 y habilita al contador de decenas para sume 1. La salida RCO del segundo contador se conecta a tierra mediante un resistor de 10K, pues es un pin que no se usará y que puede atraer ruido y consumir corriente en vano. Vemos también un circuito de reseteo, conocido desde al proyecto anterior. La señal de reloj puede ser generada por un timer 555, o un circuito oscilador (nuevamente los cristales de cuarzo son recomendados dada su gran estabilidad). Sea cual sea el circuito que utilice para generar la señal de reloj, su frecuencia deberá ser de 1 Hz, para que la cuenta sea de segundo en segundo.
                El PIC utilizado es el 16F876. Este microprocesador tiene 3 puertos. Con el puerto B “leeremos” los datos obtenidos del keypad. El puerto C mandará el número leído, ya convertido en BCD para cargar a los contadores. El puerto A emitirá la señal de carga activa en bajo de los dos contadores para iniciar la carga asíncrona.  
                El último punto a explicar sobre el hardware son los displays. Estos tienes entradas configuradas para cargarse con código BCD.



Simulación del proyecto utilizando PROTEUS de LabCenter Electronics

                Ahora, pasemos con el código empleado para manejar este sistema.

********************************************************************************

#include <16f876.h>
#fuses XT,NOWDT,NOPUT
#use delay (clock=4000000)

#define use_portb_kbd TRUE      //Activamos el puerto B para manejar al keypad

#include <kbd.c>

#use standard_io(A)
#use standard_io(C)

void main()
{
kbd_init();     //Inicializa el driver de manejo del keypad
port_b_pullups(TRUE);    //Activa los resistores de puesta en alto de las entradas del puerto B.

char c_ingresado;
int cifra[2];  //Almacenará las cifras
int numero;   //Numero total para cargar a los contadores
int i; //Recorrer vector

output_high(PIN_A0);    //Deshabilita la carga de los contadores

while(1)
{
i=0;
while(i<2)
   {
   c_ingresado=kbd_getc();
   if((c_ingresado!=0)&&(c_ingresado!='*')&&(c_ingresado!='#'))
      {
      cifra[i]=c_ingresado-48;
      i++;
      }
   }

numero=16*cifra[0]+cifra[1];  //Conversión de Decimal a BCD
output_c(numero);
output_low(PIN_A0);   //Inicia carga
delay_ms(500);
output_high(PIN_A0);  //Finaliza carga y prosigue conteo
}
}

*********************************************************************************

Ahora analicemos este código:
La directiva #define use_portb_kbd TRUE se encargará de seleccionar al puerto B para controlar al keypad. Ello debido a que para manejar al keypad hacemos uso de un driver controlador manejado por la librería kbd.c, la cual en su código, predetermina al puerto D para manejar al keypad. Pero como en este caso usaremos el puerto B, la directiva se encarga de seleccionar al puerto B. La directiva #include <kbd.c> se encarga de configurar el driver necesario para controlar al keypad.
Ahora llegamos a una directiva muy importante: #use standard_io(puerto). Esta es una de las llamadas directivas de los puertos. Estas directivas son un total de tres: #use fast_io(puerto),   #use standard_io(puerto),   #use fixed_io(puerto_outputs=pin*,…)Estas se encargan de manejar los registros PORT y TRIS de una manera en particular.
La directiva #use fast_io(puerto) maneja los puertos sin modificar el registro TRIS correspondiente. Por ello es necesario utilizar la instrucción set_tris_puerto(código_para_configurar_el_puerto). Por ejemplo, el código 0b00001111 configura a los cuatro bits de más peso como salidas, y los cuatro bits de menor peso, como entradas. Mediante la instrucción output_puerto(código_a_sacar_por_el_puerto) saca el código selecciona por el puerto correspondiente. Para ello código debió configurarse como salidas. La instrucción input_puerto() lee el código que se tiene en el puerto correspondiente, habiéndose configurado el puerto como entradas.
La directiva #use standard_io(puerto) si modifica el registro TRIS correspondiente al puerto. Esta directiva es la pre-establecida por el PIC. Es decir, mediante la instrucción output_puerto (código_a_sacar_por_el_puerto) se configuro el registro TRIS como salidas, y saca el código. De la misma manera, con la instrucción input_puerto(código_a_leer_por_el_cuerpo).
La directiva #use fixed_io(puerto_outputs=pin*,…) es más compleja. Determina qué pines del puerto serán de salidas. El resto como entradas. La manera de manejar es mediante instrucciones de output_high(bit_del_puerto) y output_low(bit_del_puerto) los cuales ponen a 1 ó a 0 al bit especificado. La instrucción output_toggle(bit_del_puerto) complementa el estado lógico del bit especificado.
Ahora ingresemos a la función principal del programa:
La instrucción kbd_init(); debe ser la primer instrucción en llamarse. Su función es configurar al driver del keypad. Luego, la directiva port_b_pullups(TRUE); activa a los resistores de puesta en alto del puerto B. Esto es necesario para manejar correctamente al driver kbd.
Luego, la declaración de variables. En c_ingresado almacenaremos el código leído del keypad. En cifra[2] almacenaremos los dos número leídos del keypad. En numero almacenaremos el código del número de 2 cifras leído del keypad, convertido a BCD. La variable i es una variable de control de bucle while.
Luego deshabilitamos inicialmente la carga asíncrona mediante output_high(PIN_A0).
Ahora ingresamos al bucle de repetición infinita en el que almacenará el código principal de la función principal.
El bucle while(i<2){} se encarga de que no se activa la carga asíncrona sino hasta que se carguen dos números.
La instrucción c_ingresado=kbd_getc(); lee el valor ingresado por el keypad y lo almacena en la variable c_ingresado. La función kbd_getc() devuelve el código ASCII del carácter ingresado en el keypad. Si no se ingresa nada, esta función devuelve un 0.
Mediante la condicional if((c_ingresado!=0)&&(c_ingresado!='*')&&(c_ingresado!='#')){} se verifica el caso de que no se haya presionado ninguna tecla, o bien se hayan ingresado los caracteres no numéricos “#”  ó “*”. En caso de que no se den esos casos, indica que si se ingresó un número. Entonces almacenamos el carácter en c_ingresado. Ahora, lo convertimos a decimal y lo guardamos en cifra[]. Para hacer esta conversión sólo hace falta restarle al carácter el número 48 (30 en hexadecimal). Ello debido que a partir de ese número recién llegan los números ASCII.
Acabado el proceso de lectura, y teniendo ya los dos números almacenados en el vector cifra[], pasamos a convertir este número decimal a BCD. En vista de que para hacer la conversión, tenemos que convertir cada cifra a binario. Para ello, la cifra de decenas tiene que correr cuatro bits antes de convertirse a binario. Esos cuatro bits implican un factor de 24, de donde vemos que tenemos que multiplicar a la cifra de decenas por 16 y sumarle las unidades. Listo, ya tenemos el código en BCD. Veamos:

Si n=30. Según nuestro algoritmo, nBCD=3*16+0=48. Ahora lo convertimos a binario y obtenemos: 00110000, que es el código BCD esperado.
                Si n=75. Según nuestro algoritmo, nBCD=7*16+5=117. Ahora lo convertimos a binario y obtenemos: 01110101, que es el código en BCD esperado.

                Este resultado lo almacenamos en numero y listo.
                Ahora se preguntarán, ¿por qué no usamos un algoritmo para convertir el número obtenido binario? Pues no es necesario. La función output_puerto(código) sea cual sea la base de numeración del código, convierte a binario para sacarlo por el puerto. Por ello que basta con tener el número en decimal, pues es más sencillo manejarlo así.
                Siguiendo con el código, vemos que está la instrucción output_c(numero); para tener el código en el puerto C. Luego ponemos en bajo al pin A0 para activar la carga asíncrona. Esperamos medio segundo para asegurar una correcta carga y luego desactivamos la carga asíncrona. Y listo, ya tenemos lo necesario para que el sistema funcione.
Nuevamente proporciono links de descarga en donde tendrán un archivo .rar que contendrá la simulación en PROTEUS del circuito, el archivo C con el código y el archivo en .HEX para cargar al PIC. Culaquier duda o sugerencia para mejorar el código, sólo coméntenla. Bueno, hasta el siguiente artículo, y tengan paciencia y empeño, que la electrónica lo vale. 


http://www.mediafire.com/?2cbo3tpciwafxu5