jueves, 4 de julio de 2024

Uso de Teclado Matricial con LCD

 Teclado Matricial con LCD

Este sitio fue creado para compartir el mutuo interés en la electrónica y en especial la programación de microcontroladores PIC. Agradecido por visitar mi blog te quiero recordar que estoy atento a critica constructiva relacionada con esta publicación. 

En esta ocasión veremos como hacer uso de un Teclado Matricial con una pantalla LCD que son de los elementos mas utilizados para implementar una interfaz de usuario en un sistema electrónico.

La programación se realizara utilizando MPLABX y el compilador XC8 ambos disponibles en la pagina de microchip. Aquí dejo los enlaces de las versiones utilizadas para nuestro ejemplo:  <MPLABX v6.20>   <XC8 v2.45>

Mencionar también que es necesario contar con conocimientos mínimos sobre programación en lenguaje C y el uso de microcontroladores PIC16.

Introducción al Tema

Con el objetivo de mostrar como hacer uso de un teclado matricial y una pantalla LCD, implementaremos en nuestro circuito una interfaz de usuario que permite validar una clave numérica de cuatro dígitos, mostrando los respectivos mensajes de solicitud y validación en la pantalla LCD.
Es importante mencionar que existe en internet una amplia informacion de las características y usos de estos dos dispositivos, por lo que recomiendo revisar algunas de estas referencias.

Referencia <Teclado Matricial 1> y <Teclado Matricial>    

Referencia <Pantalla LCD 1> y <Pantalla LCD 2 >

Considerando la necesidad de implementar una interfaz de usuario con Teclado Matricial y Pantalla LCD he descrito un resumen de estos dispositivos considerando el circuito que se montara para la practica.

Teclado Matricial 4x4

La figura 1, muestra la disposición interna de un teclado matricial 4x4, es decir cuatro filas y cuatro columnas, conformando así un total de 16 pulsadores o botones. Notara que el principio de funcionamiento es bastante simple, por ejemplo si presionamos el botón 3 entrara en contacto la fila 0[ROW0] con la columna 2[COL2], y se mantendrá cerrado hasta liberar el botón.

Fig1. Teclado Matricial 4x4

Bajo este principio consideraremos para fines prácticos que las columnas son las salidas y las filas son las entradas del Microcontrolador (MCU), por lo tanto conectar un Teclado Matricial 4x4 requiere al menos 8 pines del MCU.

Las figuras 2 y 3, muestran la distribución de pines de algunos Teclados que mas se comercializan, pero debe considerar que esta informacion debe verificarse con la hoja de datos que proporciona el fabricante.

Fig2. Teclado Matricial tipo Rígido

Fig3. Teclado Matricial tipo Membrana

El proceso del MCU para hacer la lectura de un teclado matricial consiste en realizar un barrido en las salidas, donde únicamente se activa una salida por vez, el método aplicado con las funciones que utilizaremos es un barrido de ceros(walking zeros), y hacer que la entrada o fila tenga un nivel logico bajo cuando se presiona un botón, para esto se requiere colocar resistencias pull-ups en las entradas[ROW] del teclado.
Considerando estos aspectos describiremos los procedimiento y funciones de la librería keypad que utilizaremos.

  • KBSetup(): Configura el Puerto donde se conectara el teclado, es importante mencionar que se debe editar las siguientes definiciones en la cabecera keypad.h
/* USER PORT DEFINITION */
#define KB_PORT PORTB //Puerto asociado
#define KB_TRIS TRISB
//Registro Tris asociado
/* END USER PORT DEFINITIOS */

La disposición del teclado con relación a los pines del puerto asignado, es que los cuatro bits de menor peso(salidas) corresponden a las columnas y los cuatro de mayor peso serán(entradas) las filas, recuerde que las filas necesitas de resistencias pull-ups.
  • KBScan(): Efectúa un ciclo con barrido de ceros en las columnas (walking zeros) para detectar si existe un botón presionado haciendo lectura de las entradas,  esta función retorna cero si no hay un botón presionado. En caso de presionar un botón del teclado la función retorna un código binario(res) que indica la posición(fila, columna) de la matriz. Considerando que un ciclo de barrido requiere pocos ciclos de reloj, es necesario llamar a la función continuamente hasta que el valor de retorno sea diferente a cero, una vez recibido el código del botón, también es importante considerar que el teclado deberá liberarse para evitar una validación continua, a continuación se muestra un ejemplo simple de como leer un botón y esperar hasta que el botón se libere.
res = KBScan(); //Ejecuta el barrido y guarda resultado
if(res != 0)
//Si el resultado, es diferente de 0
{  
/* Codigo para boton presionado */
    valor = KBGetValue(res);
//Convierte el codigo a numero
    while(KBScan()) {};
//Espera liberacion del boton
}
El código descrito anteriormente puede bloquear al programa, si el usuario mantiene presionado el botón de forma indefinida, por lo que se deben tomar medidas adicionales para evitar esta situación.
  • KBGetChar(n): Esta función se utiliza para convertir el código binario del teclado que retorna la función KBScan a un carácter de tipo ascii, si el código no corresponde con un carácter valido, la función devuelve '?'.
  • KBGetValue(n): A diferencia de la anterior función, este convierte el código binario del teclado en un numero decimal, si el código no corresponde con un numero valido, la función devuelve 0xFF.

La Pantalla LCD 20x2

La configuracion de pines para la pantalla LCD corresponde con la distribución que se muestra en la figura 4.

Fig4. Mapa de pines del LCD

GND:  Conexión a tierra 0V
VCC:  Alimentación a 5V
VEE:  Contraste 0V-5V
RS:   Selector modo comando o dato
R/W:  Selector Lectura o Escritura
EN:   Señal de habilitación
DBx:  Bus datos paralelo 8-bit/4-bit
Led+: Ánodo LED para luz de fondo
Led-: Cátodo LED para luz de fondo

Una ventaja de estos módulos LCD, es que cuentan con el modo de operación paralelo de cuatro bit (4-bit mode) que sumado a las lineas de control RS y EN, necesitaremos únicamente 6 pines del MCU para su uso. 

Las capacidades que tiene le modulo LCD van mas allá de lo que se utiliza en esta publicación, para nuestro caso el LCD lo utilizaremos solo para mostrar mensajes con los símbolos ASCII por defecto que posee en su memoria, es por esta razón que no se requieren operaciones de lectura y por lo tanto el pin de control R/W permanecerá en nivel bajo.

Para que nuestro MCU pueda mostrar mensajes en el LCD, se debe completar un proceso de inicialización de acuerdo a requerimientos de tiempo descritos en la hoja de datos del fabricante, considerando de forma general los tiempos máximos para la temporización las señales, la librería lcd que utilizaremos en nuestra implementación,  contiene una sección de código para definir estos valores de acuerdo a un modelo especifico.  A continuación se describen algunos de los procedimientos de mayor uso en nuestro programa.

  • LCD_Setup(): Este procedimiento configura el puerto asociado al los pines del LCD, donde es posible definir los cuatro pines de menor peso de cualquier puerto del MCU y de forma separadas los dos pines de control RS y EN. En segunda instancia este procedimiento lleva a cabo la inicialización del modulo LCD, siendo por defecto la siguiente configuracion:
1) Bus de datos en modo 4-bit y multi-linea;
2) Incremento de posición automático;
3) Muestra el cursor sin destellar;
4) Limpia la pantalla e inicializa el cursor.

La definición del puerto asociado a los pines del LCD y los valores de temporización se lleva a cabo modificando las siguientes lineas de código en la cabecera lcd.h. Por defecto los cuatro pines DB4 al DB7 del LCD corresponden con los primeros cuatro bits del puerto en el PIC, es posible cambiar la asignación a los últimos cuatro bits del puerto agregando la #define LCD_UPPER_DB en la cabecera.

/* USER PORT DEFINITION */
#define LCD_PORT PORTD  //Puerto asociado
#define LCD_TRIS TRISD 
//Registro Tris asociado
#define LCD_RS PORTDbits.RD4
//Pin RS Asociado
#define LCD_EN PORTDbits.RD5
//Pin EN Asociado
#define LCD_RS_TRIS TRISDbits.TRISD4
//Pin Tris RS
#define LCD_EN_TRIS TRISDbits.TRISD5
//Pin Tris EN
#ifndef _XTAL_FREQ
    #define _XTAL_FREQ 8000000
//Define Frecuencia
#endif  

/* END USER PORT DEFINITIONS */

  • LCD_WriteCMD(Cmd): Este procedimiento permite enviar un comando de la lista de definiciones al modulo LCD, siendo algunos ejemplos de uso, los siguientes:
LCD_WriteCmd(LCD_CLEAR); //Limpia la pantalla LCD
LCD_WriteCmd(LCD_DISPLAY & LCD_DCURSOROFF); //Sin cursor
LCD_WriteCmd(LCD_DISPLAY & LCD_DBLINKOFF); //Sin destello
LCD_WriteCmd(LCD_HOME); //Iniciliza el cursor
  • LCD_WriteMsg(*str): El procedimiento sirve para mostrar un mensaje de texto en la pantalla LCD, considerando que el mensaje iniciara en la posición que tiene el cursor. El contenido del mensaje(str) corresponde a un arreglo de caracteres con carácter nulo al final(null_string).
  • LCD_WriteChar(data): El procedimiento muestra en la pantalla LCD y en la posición del cursor, un único carácter val, el dato(data) debe formar parte de la tabla de caracteres ascii. 
  • LCD_WriteNum(num, padn): A diferencia del anterior procedimiento, este muestra en el LCD desde la posición del cursor un valor decimal entero de 16-bits(val), mismo que puede alinearse con una cantidad de ceros a la izquierda (padn).
  • LCD_GotoXY(col, row): El procedimiento permite posicionar el cursor en la pantalla LCD, considerando una distribución de filas y columnas donde las filas(row) representan la cantidad de lineas que generalmente son:
    • 0: Linea 1
    • 1: Linea 2
    • 2: Linea 3
    • 4: Linea 4
Las columnas este caso son las posiciones del cursor en cada linea, en el caso de una pantalla de 16x2, las columnas(col) serán de 0 al 15.

Esquema del Circuito

Diagrama de circuito elaborado en ISIS Proteus V8.0

Fig5. Esquema del circuito electrónico
Como se observa en la figura 5, el PIC16F887 tiene conectado seis lineas del PORTD[5:0] a los pines de la pantalla LCD, y ocho lineas del PORTB[7:0] al Teclado Matricial, las entradas del PORTB tendrán activadas las resistencias pull-up internas. Aclarar que el circuito de este diagrama tiene las conexiones mínimas para la simulación en Proteus, por esta razón no se muestran las conexiones de alimentación del PIC16F y el pin de contraste VEE.
Notara también que el teclado utilizado en el diagrama es una matriz 4x3, por lo tanto no hay columna 4, sin embargo esto no afectara el funcionamiento del programa, siempre que respete el orden correcto en las conexiones al puerto del PIC considerando la distribución de las figuras 2 y 3.
Para conocer si el programa esta en funcionamiento normal, se conecta un LED al pin RE2 mismo que destellara cada segundo. 

Programa del Microcontrolador

El programa que implementaremos para ensayar el Teclado Matricial y pantalla LCD tendrá como propósito, mostrar en la pantalla un Mensaje de solicitud de contraseña "PASSWORD", para que el usuario introduzca con el teclado una contraseña de cuatro dígitos y luego validar con el código "3022", y dependiendo de esta validación se mostrara un mensaje de "CORRECTO" o "ERROR". El proceso que sigue el programa se ilustra en el diagrama de la figura 6.

Fig6. Secuencia del programa
En la codificación del programa se considera que la frecuencia de operación de PIC16F887 es de 8MHz, con esta definición se configura el temporizador TMR0 para generar interrupciones de 1ms, esto lapso de tiempo es la base para llamar consecutivamente al procedimiento que recibirá y validara la contraseña. La siguiente entrada <TMR0 configuracion y uso>, muestra con mayor detalle el uso del modulo TMR0.

/*Programa Principal*/
void main(void)

{
    setupMCU();
//Configuracion del PIC
    LCDSetup();
//Inicia el modulo LCD
    KBSetup(); 
//Inicia el KeyPad
    while(1)
    {
        if(tick1ms)
//Se valida cada 1ms
        {
            tick1ms = 0;
//Limpia bandera
            taskLED(); 
//Tarea destello LED
            taskAPP()
//Tarea de la Aplicación
        }
    }
}
 

/*Tarea de la Aplicacion*/
void taskAPP(void)
{
    static uint8_t keycnt, state = 0;
//variables no volátiles
    static uint16_t cnt = 0;
//variable contador
    uint8_t res, value;
//variables temporales
    switch(state)
    {
        case 0:
//S0-Muestra mensaje
            LCDGotoXY(0,0);
//Posiciona el cursor linea 1
            LCDWriteMsg(" PASSWORD");
            LCDGotoXY(1,0);
//Posiciona el curso linea 2
            LCDWriteMsg("  [    ]");
            LCDGotoXY(1,3);
//Posiciona linea 2, col 3
            cnt = 0;
//inicia contador de ms
            keycnt = 0;
//Inicia contador de dígitos
            state = 1;
//carga estado 1
            break;
        case 1:
//S1-Lectura del teclado
            res = KBScan();
//Lectura del Teclado
            if(res)
//Si hay dato valido
            {
                if(cnt++ > 99)
//Repite para confirmación del botón
                {
                    value = KBGetChar(res);
//Recupera valor a char
                    LCDWriteChar(value);
//Escribe valor en pantalla
                    state = 2;
//Carga estado 2
                }
            } else cnt = 0;
            break;
        case 2:
//Contador de dígitos ingresados
            password[keycnt] = value;
//Agrega dígito al password 
            keycnt++;
//Incrementa contador de dígitos
            if(keycnt > 3)
//Mas de tres dígitos recibidos
            {
                password[keycnt] = 0;
                state = 4;
//Carga estado 4 para validar password
            }
            else state = 3;
//Carga estado 3 para recibir otro dígito
            break;
        case 3:
//Espera liberación del botón
            if(!KBScan()) state = 1;
//Lectura del siguiente dígito
            break;
        case 4:
//Compara contraseña
            LCDGotoXY(1,0);
//Posiciona Cursor linea 2
            res = (uint8_t) strcmp("3022", password);
//Compara
            if(res == 0) LCDWriteMsg(" Correcto");
//Código correcto
            else LCDWriteMsg("  Error ");
//Código incorrecto
            state = 5;
//Carga estado 5
            break;
        case 5:
//Genera retardo antes de reiniciar
            if(cnt++ > 1999)
//Espera hasta 2000ms
            {
                LCDWriteCMD(LCD_CLEAR);
//Limpia la pantalla
                state = 0;
//Carga estado 0
            }
            break;
    }
}

Funcionamiento

Una vez cargado el programa en el PIC16F, el circuito comienza a destellar el LED una vez por segundo, esto indica que el programa se encuentra en funcionamiento normal, así mismo la pantalla LCD mostrara el mensaje "PASSWORD", solicitando ingresar la contraseña, entonces puede ingresar los dígitos utilizando el teclado, en el instante que ingrese el cuarto dígito, se procederá a validar el código y mostrar en la pantalla si es "Correcto" o "Error", este mensaje se mantendrá un par se segundos para luego reiniciar el proceso, donde se pedirá nuevamente ingresar otra contraseña. La figura 7 muestra la implementación física del circuito.

Fig7. Implementacion del circuito
Los dígitos ingresados se muestran en la pantalla, y deben corresponder con el numero de botón del teclado, lo que nos indica que la conexión es correcta, caso contrario debe revisar la distribución de los pines.

Conclusiones

Se verifico correctamente el funcionamiento del Teclado Matricial y la pantalla LCD con el PIC16F887, completando así el propósito de esta publicación.
Aquí dejo los enlaces para que puedas descargar el proyecto MPLABX, mismo que se encuentran comprimidos con gzip,

También de dejo vídeo donde explico como abrir el proyecto MPLABX y compilar con otro PIC diferente al utilizado. 

 
Sin mas que mencionar agradezco tu visita al blog y espero que el ejemplo visto pueda ser útil en tu formación y el proyecto que desarrollas.
Atte. Pablo Zárate Arancibia
email: pablinza@me.com / pablinzte@gmail.com, @pablinzar
Santa Cruz de la Sierra - Bolivia


 


No hay comentarios.:

Publicar un comentario