Programación Específica > Soluciones de Hard y Soft
Teclado Matricial y Display 7 Segmentos - ATMEL AVR
(1/1)
netshark:
EL TECLADO MATRICIAL
Implementado con un Micro ATMEL AVR ATMEGA 8535
Para entender un poco sobre el funcionamiento eléctrico de un teclado matricial, lean la siguiente presentación:
Acá la presentación: EL_TECLADO_MATRICIAL_v1_4.pdf (1.6 MB)
Para la práctica se necesita un teclado matricial de 4X4, lo pueden comprar o fabricarlo.
Si tienen los recursos, pueden comprar el teclado, pero les costará alrededor de 135 pesos.
Una forma mucho más económica y didáctica es construirlo ustedes mismos.
Material:
- 16 pushbuttons pequeños
- 1 PCB tipo "Easy Circuit" que pueda alojar todos los botones
- Cable y soldadura
Debemos conectar los switches de forma que toda una fila de ellos tengan una terminal común, así las 4 filas cada una. Después cada columna debe tener la otra terminal común.
Se ve claramente en el diagrama:
Y si prefieren usar un display de 7 segmentos, el circuito es el siguiente:
El display de 7 segmentos está construido de la siguiente forma:
Además una sencilla tabla de cuales segmentos encender para cada número:
Teclado hecho en casa
Se tuvieron que cortar algunas pistas verticales con cutter para separar las columnas, y funciona a la perfección.
En este caso se usó un microcontrolador ATMEL ATMEGA8535 datasheet pero puede bien ser implementado en un microcontrolador más pequeño, como el ATMEGA8 sin mucha dificultad, sólo habría que cambiar el acomodo de los puertos y el cableado, (datasheet)
Se implementó un programa para controlar el teclado matricial, y según la tecla que se presione, aparecerá:
1) LEDs encendidos en una tira de leds en función de la fila-columna
2) Código del 0 a la F en un display de 7 segmentos.
La tira de 10 leds sirve para ver qué tecla se presionó. De izquierda a derecha, los primeros dos leds no se utilizan, los siguientes 4 indican la columna y los ultimos 4 indican el renglón. Hay un led ROJO cercano al AVR (concretamente en el pin PD7) que se prende cuando detecta alguna tecla presionada y se apaga cuando termina la decodificación ó si descarta que se haya presionado (por si fue ruido o un falso contacto)
Ejemplo al presionar la tecla en la ultima fila de la ultima columna...
Aparecen:
Es el programa básico con decodificación de filas y columnas y tiene protección antirrebotes. Ésta es la versión que jala con la tira de LEDs:
--- Código: Text ---;Código decodificador de teclado matricial;Implementado por David Valencia Pesqueira en UPIITA-IPN 2009;Profesor: Dr. Antonio Hernández Zavala;GRUPO 4BM3;; El siguiente programa decodifica un teclado matricial; de 16 teclas. Éste tipo de algoritmo está diseñado para; detectar sólo una tecla a la vez, ya que para detectar; más de una se requieren diodos por cada interruptor en la; construcción del teclado matricial y éso ya queda fuera; del enfoque didáctico de éste programa.;; Para más información sobre la construcción de teclados; matriciales con diodos visitar:; http://www.dribin.org/dave/keyboard/one_html/;;Historial;v0.1 - Pruebas de las resistencias Pull-UP --- OK;v0.2 - Probando la salida del tempscan;v0.3 - Nueva estructura de tempscan -- OK;v0.4 - Salida por tira de leds en PORTA -- OK;;Hardware en un ATMEL ATMega 8535;El teclado está conectado de la siguiente manera:;; COLUMNAS; 0 1 2 3; ; FILAS 0 X X X X PC4;; 1 X X X X PC5;; 2 X X X X PC6;; 3 X X X X PC7; ; PC0 PC1 PC2 PC3;;######################################################;CABECERA.include "m8535def.inc" ;######################################################;Vector de Interrupciones.org 0x00 rjmp reset ;interrupción de Reset;;######################################################;Variables Globales;La variable tempscan se acomoda de la siguiente forma ;tempscan = [fila3,fila2,fila1,fila0,col3,col2,col1,col0];Son "banderas" que se prenden para indicar en qué fila; y qué columna se halla la tecla. .def tempscan=r17.def temp=r16 ;Rutina Principalreset: ;inicializar pila cli ldi temp,low(ramend) out spl,temp ldi temp,high(ramend) out sph,temp sei rjmp init init: ;Inicializar Puertos ;Este código emplea el puerto C, con los bits 0 al 3 para las columnas ;y los bits 4 al 7 para las filas. ;Inicia con las filas como salidas con ceros y las columnas como entradas ;que se mantienen en un nivel alto mientras no estén conectadas ;Para lograr esto, se habilitan las "resistencias pull-up" que conectan ;el pin deseado hacia VCC. ;Para hacerlo se declaran los pines como entradas (DDRC=0) pero ;enviamos 0xFF al registro PORTC para activarlas. ;Declarando al nibble alto como salida y al bajo como entrada ldi temp,0b11110000 out DDRC,temp ;Activando las resistencias pull-up en la parte baja ldi temp,0x0F out PORTC,temp ;Si se presiona una tecla, el "0" de alguna fila será ;detectado por las columnas, y entonces comienza el ;proceso de decodificación. ldi temp,0b10000000 out DDRD,temp ;Puerto D como salida para cuando detecta tecla ser temp out DDRA,temp ;Nibble bajo del puerto A como salida clr temp out PORTA,temp clr tempscan ;Borra el resultado del escaneo rjmp begin begin: clr temp out PORTD,temp ;Probar si algun botón fue presionado in temp,PINC cpi temp,0x0F ;Si hay algun cero en las columnas, buscar la tecla brne antirrebotesrjmp begin antirrebotes:;Esta rutina espera un corto periodo de tiempo mientras el interruptor;se estabiliza para evitar que el micro detecte la misma tecla varias;veces al igual que posible ruido. ;Vuelve a leer las entradas ser temp out PORTD,temp rcall delay in temp,PINC cpi temp,0x0F ;Si detecta el cero de nuevo, procesa la detección brne deteccion ;Si fue un falso contacto, vuelve a empezar rjmp begin;FIN DE ANTIRREBOTES deteccion: clr tempscan ;inicializamos el código de escaneo temporal ldi tempscan,0x00 ;Buscar las columnas colscan: sbis pinc,0 ;prueba la columna 0 ldi tempscan,0x01 sbis pinc,1 ;prueba la columna 1 ldi tempscan,0x02 sbis pinc,2 ;prueba la columna 2 ldi tempscan,0x04 sbis pinc,3 ;prueba la columna 3 ldi tempscan,0x08 cpi tempscan,0x00 ;si no halló la columna, repetir breq init ;Ahora que se encontró la columna, tienen que invertirse ;los sentidos del nibble bajo y el alto para buscar la ;fila rcall invertir ;Ahora invertidos, buscaremos si alguna fila está ;baja in temp,PINC cpi temp,0xF0 ;Si hay algun cero en las columnas, buscar la tecla brne filadetectada rjmp init ;Si no hay fila con cero, devuelve los puertos ;a su estado original y reinicia el programa filadetectada: ;Buscar la fila filascan: ldi temp,0x10 sbis pinc,4 ;Prueba la fila 0 rjmp col0 sbis pinc,5 ;Prueba la fila 1 rjmp col1 sbis pinc,6 ;Prueba la fila 2 rjmp col2 sbis pinc,7 ;Prueba la fila 3 rjmp col3 rjmp init ;Si no halla la fila, reinicia ;A continuación se escribirá el valor correspondiente ;a la fila, se usa el comando ROL para multiplicar por 2 ;pero se limpia antes la bandera de acarreo para evitar ;que se sume y entregue valores erróneos. col0: add tempscan,temp rjmp fincol col1: ldi temp,0x20 add tempscan,temp rjmp fincol col2: ldi temp,0x40 add tempscan,temp rjmp fincol col3: ldi temp,0x80 add tempscan,temp rjmp fincol fincol: ;Toca procesar el código temporal para sacarlo ;por los leds, en este caso sale en 4 leds en puertoA out PORTA,tempscan clr tempscan rcall desinvertir ;devolver los puertos al estado original rjmp begin ;Subrutinas delay: cli ;Respaldar variables globales en la pila push r16 push r17 ;Inicia secuencia de retraso loop0: ldi r17,0x04 loop1: ldi r16,0xFF loop2: dec r16 brne loop2 dec r17 brne loop1 sei ;Restaurar las variables desde la pila pop r17 pop r16ret invertir: ;Inversión de los pines ldi temp,0b00001111 out DDRC,temp ;Activando las resistencias pull-up en la parte alta ldi temp,0xF0 out PORTC,temp ;Ahora la parte alta es entrada con pullup y la parte ;baja son salidas con cerosret desinvertir: ;Devolver los pines al estado inicial ldi temp,0b11110000 out DDRC,temp ;Activando las resistencias pull-up en la parte alta ldi temp,0x0F out PORTC,temp ;Ahora la parte baja es entrada con pullup y la parte ;alta son salidas con cerosret ;FIN DEL PROGRAMA TECLADO MATRICIAL
Esta otra versión saca qué tecla fue presionada en un display de 7 segmentos:
Aquí unas fotos:
--- Código: Text ---;Código decodificador de teclado matricial;Implementado por David Valencia Pesqueira en UPIITA-IPN 2009;Profesor: Dr. Antonio Hernández Zavala;GRUPO 4BM3;; El siguiente programa decodifica un teclado matricial; de 16 teclas. Éste tipo de algoritmo está diseñado para; detectar sólo una tecla a la vez, ya que para detectar; más de una se requieren diodos por cada interruptor en la; construcción del teclado matricial y éso ya queda fuera; del enfoque didáctico de éste programa.;; Para más información sobre la construcción de teclados; matriciales con diodos visitar:; http://www.dribin.org/dave/keyboard/one_html/;;Historial;v0.1 - Pruebas de las resistencias Pull-UP --- OK;v0.2 - Probando la salida del tempscan;v0.3 - Nueva estructura de tempscan -- OK;v0.4 - Salida por tira de leds en PORT_DISP -- OK;v0.5 - Salida por tira de leds en 4 pines de PORT_DISP -- OK;;Hardware en un ATMEL ATMega 8535;El teclado está conectado de la siguiente manera:;; COLUMNAS; 0 1 2 3; ; FILAS 0 X X X X PC4;; 1 X X X X PC5;; 2 X X X X PC6;; 3 X X X X PC7; ; PC0 PC1 PC2 PC3;;######################################################;CABECERA.include "m8535def.inc" ;######################################################;EQUIVALENCIAS;Puerto para el teclado.equ PORT_K=PORTC.equ PIN_K=PINC.equ DDR_K=DDRC;Puerto de salida para el display de Siete Segmentos.equ PORT_DISP=PORTA.equ DDR_DISP=DDRA ;######################################################;Vector de Interrupciones.org 0x00 rjmp reset ;interrupción de Reset;;######################################################;Variables Globales;La variable tempscan se acomoda de la siguiente forma ;tempscan = [-,-,-,-,fila01,fila00,col01,col00];Son "banderas" que se prenden para indicar en qué fila;y qué columna se halla la tecla.; .def tempscan=r17.def temp=r16 ;Rutina Principalreset: ;inicializar pila cli ldi temp,low(ramend) out spl,temp ldi temp,high(ramend) out sph,temp sei rjmp init init: ;Inicializar Puertos ;Este código emplea el puerto C, con los bits 0 al 3 para las columnas ;y los bits 4 al 7 para las filas. ;Inicia con las filas como salidas con ceros y las columnas como entradas ;que se mantienen en un nivel alto mientras no estén conectadas ;Para lograr esto, se habilitan las "resistencias pull-up" que conectan ;el pin deseado hacia VCC. ;Para hacerlo se declaran los pines como entradas (DDR_K=0) pero ;enviamos 0xFF al registro PORT_K para activarlas. ;Declarando al nibble alto como salida y al bajo como entrada ldi temp,0b11110000 out DDR_K,temp ;Activando las resistencias pull-up en la parte baja ldi temp,0x0F out PORT_K,temp ;Si se presiona una tecla, el "0" de alguna fila será ;detectado por las columnas, y entonces comienza el ;proceso de decodificación. ldi temp,0b10000000 out DDRD,temp ;Puerto D como salida para cuando detecta tecla ser temp out DDR_DISP,temp ;Puerto A como salida ldi temp,0b00000010 ;Enviar un guion al puerto A out PORT_DISP,temp clr tempscan ;Borra el resultado del escaneo rjmp begin begin: clr temp out PORTD,temp ;Probar si algun botón fue presionado in temp,PIN_K cpi temp,0x0F ;Si hay algun cero en las columnas, buscar la tecla brne antirrebotesrjmp begin antirrebotes:;Esta rutina espera un corto periodo de tiempo mientras el interruptor;se estabiliza para evitar que el micro detecte la misma tecla varias;veces al igual que posible ruido. ;Vuelve a leer las entradas ser temp out PORTD,temp rcall delay in temp,PIN_K cpi temp,0x0F ;Si detecta el cero de nuevo, procesa la detección brne deteccion ;Si fue un falso contacto, vuelve a empezar rjmp begin;FIN DE ANTIRREBOTES deteccion: clr tempscan ;inicializamos el código de escaneo temporal ldi tempscan,0x00 ;Buscar las columnas colscan: sbis PIN_K,0 ;prueba la columna 0 ldi tempscan,0x00 sbis PIN_K,1 ;prueba la columna 1 ldi tempscan,0x01 sbis PIN_K,2 ;prueba la columna 2 ldi tempscan,0x02 sbis PIN_K,3 ;prueba la columna 3 ldi tempscan,0x03 ;Ahora que se encontró la columna, tienen que invertirse ;los sentidos del nibble bajo y el alto para buscar la ;fila rcall invertir ;Ahora invertidos, buscaremos si alguna fila está ;baja in temp,PIN_K cpi temp,0xF0 ;Si hay algun cero en las columnas, buscar la tecla brne filadetectada rjmp init ;Si no hay fila con cero, devuelve los puertos ;a su estado original y reinicia el programa filadetectada: ;Buscar la fila filascan: sbis PIN_K,4 ;Prueba la fila 0 rjmp fila0 sbis PIN_K,5 ;Prueba la fila 1 rjmp fila1 sbis PIN_K,6 ;Prueba la fila 2 rjmp fila2 sbis PIN_K,7 ;Prueba la fila 3 rjmp fila3 rjmp init ;Si no halla la fila, reinicia ;A continuación se escribirá el valor correspondiente ;a la fila, se usa el comando ROL para multiplicar por 2 ;pero se limpia antes la bandera de acarreo para evitar ;que se sume y entregue valores erróneos. fila0: ldi temp,0x00 add tempscan,temp rjmp fincol fila1: ldi temp,0x04 add tempscan,temp rjmp fincol fila2: ldi temp,0x08 add tempscan,temp rjmp fincol fila3: ldi temp,0x0C add tempscan,temp rjmp fincol fincol: ;Toca procesar el código temporal para sacarlo ;por los leds, en este caso sale en 4 leds en puertoA ;out PORT_DISP,tempscan rcall desinvertir ;devolver los puertos al estado original rcall scantoseven ;Mandar al display 7 segmentos rjmp begin ;Subrutinas delay: cli ;Respaldar variables globales en la pila push r16 push r17 ;Inicia secuencia de retraso loop0: ldi r17,0x20 loop1: ldi r16,0xFF loop2: dec r16 brne loop2 dec r17 brne loop1 sei ;Restaurar las variables desde la pila pop r17 pop r16ret invertir: ;Inversión de los pines ldi temp,0b00001111 out DDR_K,temp ;Activando las resistencias pull-up en la parte alta ldi temp,0xF0 out PORT_K,temp ;Ahora la parte alta es entrada con pullup y la parte ;baja son salidas con cerosret desinvertir: ;Devolver los pines al estado inicial ldi temp,0b11110000 out DDR_K,temp ;Activando las resistencias pull-up en la parte alta ldi temp,0x0F out PORT_K,temp ;Ahora la parte baja es entrada con pullup y la parte ;alta son salidas con cerosret scantoseven: ;Convierte el escaneo a display 7 segmentos catodo común ;Revisar el cableado del display en las hojas adjuntas ;El bit mas alto va al segmento "a" hasta el "g" y luego el punto decimal. cpi tempscan,0x00 breq cero cpi tempscan,0x01 breq uno cpi tempscan,0x02 breq dos cpi tempscan,0x03 breq tres cpi tempscan,0x04 breq cuatro cpi tempscan,0x05 breq cinco cpi tempscan,0x06 breq seis cpi tempscan,0x07 breq siete cpi tempscan,0x08 breq ocho cpi tempscan,0x09 breq nueve cpi tempscan,0x0A breq letraA cpi tempscan,0x0B breq letraB cpi tempscan,0x0C breq letraC cpi tempscan,0x0D breq letraD cpi tempscan,0x0E breq letraE cpi tempscan,0x0F breq letraF rjmp guion cero:ldi temp,0b11111100 rjmp sacarsegmentos uno:ldi temp,0b01100000 rjmp sacarsegmentos dos:ldi temp,0b11011010 rjmp sacarsegmentos tres:ldi temp,0b11110010 rjmp sacarsegmentos cuatro:ldi temp,0b01100110 rjmp sacarsegmentos cinco:ldi temp,0b10110110 rjmp sacarsegmentos seis:ldi temp,0b10111110 rjmp sacarsegmentos siete:ldi temp,0b11100000 rjmp sacarsegmentos ocho:ldi temp,0b11111110 rjmp sacarsegmentos nueve:ldi temp,0b11110110 rjmp sacarsegmentos letraA:ldi temp,0b11101110 rjmp sacarsegmentos letraB:ldi temp,0b00111110 rjmp sacarsegmentos letraC:ldi temp,0b10011100 rjmp sacarsegmentos letraD:ldi temp,0b01111010 rjmp sacarsegmentos letraE:ldi temp,0b10011110 rjmp sacarsegmentos letraF:ldi temp,0b10001110 rjmp sacarsegmentos guion:ldi temp,0b00000010 sacarsegmentos: ;enviar al display siete segmentos out PORT_DISP,tempret ;FIN DEL PROGRAMA TECLADO MATRICIAL
Espero el programa sea claro y cualquier duda por favor dejen un mensaje en este tema.
:D
© Jonathan ©:
Gracias netshark por este interesante post, esta muy bien detallado y facilita mucho la construcción de la placa y la comprensión del código. Por trabajo estoy bastante ausente del foro y veo que ya no tiene la actividad que tenia hace un tiempo, al menos el subforo de microcontroladores, por eso quiero organizar algo para activar nuevamente la actividad del sitio y volver al tiempo en el que el foro se había vuelto adicción :comp:
Comienzo agradeciendo tu aporte y te motivo a que sigas haciendo este tipo de posteos, muy bueno! :good:
netshark:
Saludos!
Y es cierto, me ha parecido que la actividad en el foro está un poco floja, pero mi intención es ayudar poniendo mi granito de arena.
Hasta hace poco no sabía nada de electrónica, ni mucho menos de microcontroladores pero se me ha dado la programación en diversos lenguajes. Tengo compañeros en cuyas escuelas preparatorias les enseñaron a manejar PIC, AVR y otros y me imaginé que era un mundo oscuro y difícil de entender. Ahora en la universidad descubrí que es un universo bastante interesante y con un sinfín de aplicaciones.
Estoy preparando otros programas igualmente didácticos (manejo de LCD, interfaz USART con la computadora, etc) como una forma de introducirse a los microcontroladores AVR, que han tenido un increíble boom en la industria y no es para menos.
Una duda: Tengo en mi poder un fenomenal e-book sobre Lenguaje C para AVR, ¿Hay algún problema si lo subo a este foro?
© Jonathan ©:
Tal como dices, hay un sinfín de aplicaciones y los limites dependen de la imaginación de cada uno, mis felicitaciones por la voluntad para armar los documentos detallados y mas aun por compartirlos con todos nosotros.
Sobre el libro de lenguaje C para AVR, es bienvenido como todo aquello que quieras compartir, tienes a disposición el servidor FTP del foro para subir archivos de gran tamaño, los datos para el acceso los encontraras en el siguiente enlace--> viewtopic.php?t=12696 Dentro del FTP hay carpetas destinadas a las diferentes familias de microcontroladores, creo que el directorio de ATMEL esta vacio :argh: .. luego de subir el libro si quieres puedes poner el enlace en un post para un rápido acceso desde el subforo.
netshark mil gracias y un abrazo :beer:
netshark:
En el primer post puse las fotos del display empleando el segundo código.
Posteriormente pondré el código para lograr esto:
Stay tuned
P.D: @Einstec: Al parecer el FTP está mal, porque intenté entrar con Filezilla y me marca que está mal el password.
Navegación
Ir a la versión completa