Teclado numérico 3×4 con LCD Deja un comentario

Prologo.

En otro artículo ya hice un esbozo superficial sobre las pantallas de cristal líquido LCD, distinguiendo dos grandes grupos, las pantallas alfanuméricas y las pantallas gráficas. Por el momento, nos referiremos las pantallas LCD alfanuméricas, en concreto las de cuatro líneas y 40 columnas. En la actualidad la mayoría de los LCD están controlados con el conocido HD44780 de Hitachi. El cual puede ser configurado para manejar un display de matriz de puntos de cristal líquido bajo el control de un microprocesador de 4 u 8 bits.

En este artículo, pretendo hacer una aplicación que tenga utilidad para quien disponga de un LCD y quiera realizar una aplicación que le sirva de ayuda en su trabajo o para una aplicar en un proyecto. Hay muchas aplicaciones descritas en gran cantidad de artículos y webs de distintos autores y en todas ellas subyace un ‘toque’ personal que hace la diferencia, espero que en este, también encuentren la novedad o el punto que buscaban.

El propósito de este artículo es reunir una serie de unidades sencillas, como base de los ejemplos, con pantalla de cristal líquido LCD, que se encuentran disponibles para trabajar con Arduino. Se describen algunos ejercicios para comprender los principios de uso y sin perder el carácter didáctico de lo descrito.

Display LCD.

El uso de este dispositivo se ha extendido en los últimos años debido a la proliferación de los microcontroladores con sus cada ves mayores prestaciones y los sistemas de desarrollo que los sustentan. Hay esencialmente dos tipos de pantalla para elegir, serie y paralelo, en referencia a cómo se conectan y se comunican con el mismo PC.

En cuanto a los LCD, en el mercado pueden encontrarse distintos modelos que se adaptan a las necesidades de los proyectos que se planteen. Así, podemos encontrar LCD de una línea y 8 a 40 caracteres, 4 líneas por 40 caracteres y tantas líneas y caracteres que se necesiten. Los LCD gráficos están avanzando tanto que sus precios son cada día más asequibles a cualquier necesidad.

La mayoría de los LCD paralelos son muy similares, usan chips de interfaz estándar en la industria (como el HD44780 o HD44100) para la asignación de pines, a menudo son idénticos.

En este artículo, sólo trataré de los LCD de cuatro líneas y 20 caracteres o columnas. Naturalmente por que es el que tengo a mi disposición. Para controlar pantallas Cristal Liquido (LCD) basada en el Hitachi HD44780 (o compatible) se necesita la «Nueva librería LiquidCrystal» que nos proporciona FM, como se le conoce en el foro. Además, también utilizaremos un teclado 3×4 similar al de la imagen de abajo, dos resistencias, dos LED’s, dos pulsadores y algunos hilos de colores para conectar todo.No voy a entrar sobre los pros y los contras de cada uno, ya que este no es el objetivo del presente artículo, sin embargo, lo que voy a decir es que que, fundamentalmente, la decisión se reduce a su costo en comparación con la facilidad de uso, es la cuestión.

Si bien los display’s serie son más fáciles de poner en marcha y tienen un poco mejor ayuda con el software, además de tener algunas características adicionales. Por otro lado, los LCD paralelos, necesita cablearlas usted mismo, pero son mucho más baratos y en su mayor parte se puede mostrar la misma información.

Lo que pretendo realizar es un teclado, con el que introducir una clave de un número de entre 4, 6 o más dígitos y el programa compare los dígitos que se pulsan por el usuario, con la clave guardada y si hay coincidencia que, haga una cosa, en caso de no coincidir que, haga otra cosa. En principio, se ve sencillo.

Para abordar el proyecto, necesitamos unos pocos materiales a parte de la placa Arduino y el LCD, como estos mostrados.

El más importante, el teclado, este tipo de teclados, a pesar de que es de los años 80 (foto de Futurlec), es bastante corriente y fácil de encontrar en el mercado. El resto de componentes, es de uso común. El circuito electrónico que voy a utilizar se muestra en la imagen que sigue.

Mediante la ayuda de un teclado de 12 pulsadores, podemos entrar una serie de dígitos que, formen el código «secreto» para activar un sistema, si existe coincidencia o por el contrario, pondrá en acción otro sistema que indique que, se está forzando el acceso no autorizado a la instalación, por un desconocido.

Para esto, en primer lugar debemos configurar la librería Keypad.zip y declararemos los 7 pines de Arduino que conformaran el teclado, por un lados las 4 líneas (rows) y las 3 columnas (cols) y la conformación que tomarán los contactos, como se puede ver a continuación:

El primer paso es incluir la librería y las constantes que vamos a utilizar:

 #include "Keypad.h" 

 const byte ROWS = 4; //four rows 
 const byte COLS = 3; //three columns 
 char keys[ROWS][COLS] = { 
  {'1','2','3'}, 
  {'4','5','6'}, 
  {'7','8','9'}, 
  {'*','0','#'} 
 };

El paso que sigue es, reservar memoria en bytes, para los valores de los pulsadores y la asignación del pin que se corresponde con los de Arduino. Sin embargo, hay que observar que, vamos a necesitar un número alto de pines en este y los siguientes ejemplos. Por este motivo, la asignación de pines, se hace con vistas a no tener que cambiar con frecuencia dicha disposición. Además, se asignaran otras variables, en función de las necesidades que surjan.

  byte rowPins[ROWS] = {5, 4, 3, 2}; //conecta los pinouts row del keypad 
  byte colPins[COLS] = {8, 7, 6}; //conecta los pinouts column del keypad

Este es el momento de ‘crear’ el teclado propiamente dicho, es decir, con esta sentencia, el programa generará una matriz que verá como un teclado, al que se remitirá, cuando tenga que representar un dígito. Esto se consigue con la siguiente línea:

 Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

Tenemos que guardar una clave, luego, necesitamos hacer una reserva de memoria y además, el código que introduzca el usuario, también requiere un espacio de memoria. Posteriormente, con sólo comparar ambas matrices, obtendremos fácilmente si hay coincidencia entre ambas. Veamos como se hace:

  char PIN[6]={'1','2','3','4','5','6'}; // o numero secreto (!) 
  char attempt[6]={0,0,0,0,0,0}; // usado para comparar

En la asignación de las dos matrices de 6 dígitos, utilizamos la función char para almacenar los bytes de cada matriz. Una, para los dígitos de entrada llamada attempt, se compararán con la otra matriz, contenida en PIN. Sólo, si hay coincidencia, la clave es correcta y actuará la salida correspondiente. Se han dispuesto dos salidas complementarias, las cuales se pueden conectar a los dispositivos adecuados que, deriven la potencia necesaria para sus actuadores.

En el setup, configuramos los distintos pines, según convenga a cada uno, se declara el puerto serie y su velocidad:

 pinMode(sal1, OUTPUT); 
 pinMode(sal2, OUTPUT); 
 Serial.begin(9600); //Configura la velocidad del puerto serie 

 keypad.setHoldTime(500); // Default is 1000mS 
 keypad.setDebounceTime(250); // Default is 50mS

Destacar las funciones que afectan al rebote de los pulsadores que, están integrados en la librería keypad representados por keypad.setHoldTime y keypad.setDebounceTime. Aquí. se ha reducido su tiempo de mantenimiento como se puede apreciar en el propio código.

Además, se ha incluido el mensaje que presentará al inicio del programa. En este mensaje, se puede hacer una descripción corta de lo que hay que hacer para entrar el código PIN. Esto se ha hecho con el siguiente código:

 Serial.println(" Debe introducir la secuencia: "); 
 Serial.print(" * X X X X X X # "); 
 Serial.println(" >> X = del 0 al 9"); 
 incorrectPIN();Serial.print(" "); 
 Serial.println(" Intentelo: ");

En este punto, para una mayor claridad, se deben declarar las rutinas que intervengan en el programa, acuérdese de hacer comentarios, para poder comprender qué hace cada rutina. Así pues, se declara la rutina void correctPIN() que, se ejecutará en el caso de haber coincidencia, es decir:

 digitalWrite(10, LOW); // desactiva un contacto pin 1 
 digitalWrite(11, HIGH); // activa un contacto pin 2

Y le seguirá la rutina void incorrectPIN() que se ejecutará en el caso contrario. Que hace exactamente lo mismo pero invertidos

 digitalWrite(11, LOW); // desactiva un contacto pin 2 
 digitalWrite(10, HIGH); // activa un contacto pin 1

Se ha incluido una rutina para activar un sistema (en este caso, visual) para activar un LED en su caso. Con void readKeypad(), se lee cualquier entrada de teclado, o sea, hace un chequeo del teclado, de modo que cuando se presione un pulsador o llave. Esto lo consigue mediante este código, asignando a char key, todo lo que llegue por el teclado con: char key = keypad.getKey(); si no se produce una entrada, permanecerá en espera. Gracias a esta sentencia de if (key != NO_KEY), en la cual permanecerá la ejecución del programa, esperando a que se produzca una entrada. Así que, este es el listado:

 char key = keypad.getKey(); 
 if (key != NO_KEY)

Le sigue la función switch (key) que es capaz de detectar la tecla que se ha pulsado. Cuando se produce una entrada del teclado, se guarda en la variable attempt, lo reconoce y evalúa con PIN[] si es exactamente igual, sale de esta subrutina y salta a la subrutina correctPIN() y sigue hasta el final de la misma.

En caso de que la evaluación no sea exacta, salta a la subrutina incorrectPIN(); y cuando termina, vuelve hasta la línea: for (int zz=0; zz<6; zz++) // borrar tentativa, para borrar la tentativa actual.

En último lugar está el lazo o loop() que, en este caso, contiene la llamada a readKeypad(); que ejecutará continuamente.

Veamos un primer ejemplo, este es el código para el programa de reconocimiento de clave:

Número PIN

// 
// pin_clave.pde - keypad switch con seis-digitos para el PIN 
// basado en un programa de: http://tronixstuff.wordpress.com/ 

/* Usando el actual ejemplo de hardware se pueden activa algo o
desactivar mediante el teclado - emulando lo que se puede 
encontrar en algunos sistemas de alarma y así­ sucesivamente. 
Nuestro objetivo con este ejemplo es muy simple. El sistema 
espera para obtener un PIN que se guarda previamente. 
Si el PIN es correcto, hacer algo. Si el PIN es incorrecto, 
hacer otra cosa. Este ejemplo es para darle un concepto y un 
marco para construir ideas propias. 
 19.10.2011 funciona bien. 
*/ 
#include "Keypad.h" 
const byte ROWS = 4; //four rows 
const byte COLS = 3; //three columns char 
keys[ROWS][COLS] = { 
 {'1','2','3'}, 
 {'4','5','6'}, 
 {'7','8','9'}, 
 {'*','0','#'}}; 

byte rowPins[ROWS] = { 
 5, 4, 3, 2}; //connect to the row pinouts of the keypad 
byte colPins[COLS] = { 
 8, 7, 6}; //connect to the column pinouts of the keypad 

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

char PIN[6]={'1','2','3','4','5','6'}; // su numero secreto (!) 
char attempt[6]={0,0,0,0,0,0}; // usado para comparar int z=0; 
int led13= 13; int sal1 = 10; // salida1, pin A4 
int sal2 = 11; // salida2, pin A5 

void setup() 
{ 
 pinMode(sal1, OUTPUT); 
 pinMode(sal2, OUTPUT); 
 Serial.begin(9600); //Configura la velocidad del puerto serie 
 keypad.setHoldTime(500); // Default is 1000mS 
 keypad.setDebounceTime(250); // Default is 50mS 
 Serial.println(" Debe introducir la secuencia: "); 
 Serial.print(" * X X X X X X # "); 
 Serial.println(" >> X = del 0 al 9"); 
 incorrectPIN();
 Serial.print(" "); 
 Serial.println(" Intentelo: "); 
} 
void correctPIN() // hacer esto. Si el PIN escrito es correcto 
{ 
 digitalWrite(10, LOW); // desactiva un contacto pin 1 
 digitalWrite(11, HIGH); // activa un contacto pin 2 
 Serial.print(" Correcto "); 
 Serial.print(attempt); 
} 
void incorrectPIN()    // hacer esto. Si el PIN escrito es incorrecto 
{ 
 digitalWrite(11, LOW); // desactiva un contacto 
 digitalWrite(10, HIGH); // activa un contacto 
 Serial.print("Incorrecto "); 
 //Serial.print(" "); 
} 
void led() 
{ 
 if (led13 == LOW) 
 led13= HIGH; 
 else 
 { 
  led13 = LOW; 
 } 
} 
void checkPIN() 
{ 
 int correct=0; 
 for (int q=0; q<=5; q++) 
  {   
  if (attempt[q]==PIN[q]) 
   { correct++; 
   } 
  } 
  if (correct==6) 
  { correctPIN(); 
  } else 
  { incorrectPIN(); 
  } 
  for (int zz=0; zz<6; zz++) // borrar tentativa 
   { attempt[zz]=0; 
   } 
 } 
void readKeypad() 
{ 
 char key = keypad.getKey(); 
 if (key != NO_KEY) 
 { 
  switch(key) 
 { 
  case '*': z=0; 
  Serial.println(" "); 
  break; 
  case '#': delay(50); 
  Serial.println(" "); 
  checkPIN(); 
  break; 
  default: attempt[z]=key; z++; 
 } 
  Serial.print("*"); 
  led(); 
  } 
} 
void loop() 
{ 
 readKeypad(); 
}

Este código, es susceptible de ser modificado y mejorado, sin duda. Por ese motivo, vamos a seguir en nuestro empeño en descubrir nuevos modos de lograr ese resultado e incluso mejorarlo. A continuación, veremos otra forma de enfocar el proyecto para lograr el mismo resultado.

Ejemplo PIN con LCD.

Esto esta listo, sin embargo, si le añadimos un LCD, tendremos un proyecto mucho más profesional que, podremos incluir en un proyecto que requiera de un sistema de seguridad que, incluya una clave de 6 o más dígitos. Veamos los pasos a seguir, para comprender cómo lograrlo.

EL CIRCUITO.

En primer lugar, presento el esquema electrónico es muy sencillo, a pesar de los cables que necesita utilizar para el conexionado de los distintos componentes. Se adjunta el archivo Fritzing, aunque lleva pequeñas modificaciones (el teclado y el PCF8574 son de mi creación).

Como previsiblemente se van a necesitar muchos puertos del Arduino, he pensado en aplicar un expansor de puertos, para actualizar y refrescar conocimientos, se puede leer el expansor de puerto. Aquí, lo utilizamos para interconectar el teclado, porque necesita 7 entradas/salidas, de igual modo, se podría haber utilizado para el LCD. En este ejemplo, se ha dotado de un display LCD de 20×4 como se aprecia en el circuito anterior.

El código.

El siguiente es el código del segundo ejemplo, en este listado, he introducido unos cambios que permitirán una mayor flexibilidad, en el especto de margen de clave a utilizar, gracias a usar la librería Password que, nos facilita esta labor a la hora de crear y comparar una matriz de n dígitos.

La idea es la misma descrita en el ejemplo anterior. La inclusión de un LCD, para su control, hace necesario el uso de la librería LiquidCrystal, por supuesto, también hace falta usar las librerías incluidas en el ejemplo anterior que, no es necesario repetir.

Un punto a resaltar es que debido a que necesitamos más puertos del Arduino, en este caso, vamos a utilizar las entradas analógicas como entradas digitales, esto es posible si los declaramos con el numeral que le corresponde, es decir, en Arduino, los pines digitales normalmente, van del pin0 al pin13. Según el playground de Arduino:

Mapeo de Pins. 

·Los pines de Arduino correspondientes a los pines analógicos son desde el 14 al 19. 
·Observa que esto son pines de Arduino y no corresponden con los números 
 de los pines físicos del chip Atmega. Los pines analógicos, pueden usarse 
 de manera idéntica que los digitales, así que por ejemplo, podrías ver un 
 código como este para configurar un pin analógico, y establecerlo a HIGH: 

  pinMode(14, OUTPUT); 
  digitalWrite(14, HIGH);

Aquí, usaremos los siguientes, del pinA0 por pin14 a pinA3 por pin17, procurando no utilizar los pines analógicos pinA4 y pinA5, por si se emplean en algún momento como E/S I2C.

 byte rowPins[ROWS] = {5, 4, 3, 2}; // pines a conectar los row del teclado. 
 byte colPins[COLS] = {16, 15, 14}; // AN0, AN1 y AN2. Por falta de pines 
 const int buttonPin = 6; // para los relés mediante una R de 10k y un transistor NPN 
 int sal1 = 17; // pin A4 salida a rele 
 int sal2 = 18; // pin A5 salida a rele

En la subrutina: «void keypadEvent(KeypadEvent eKey)» se hace atiende al teclado y compara con la clave guardada. La subrutina: «void guessPassword()» es la que, mediante la ayuda de un transistor universal NPN, permite activar o desactivar un relé con el que, podemos manejar la potencia necesaria para abrir o cerrar el sistema de acceso, si es el caso.

Número PIN largo.

/* password_lcd.pde 
Basado en artículos de la red. 
Modificado y adaptado el 07.11.2011 por V. Garcia. 
Para hispavila.com Utilizamos las librerías: 
[Password.h LiquidCrystal.h Keypad.h] que puede 
encontrar en:
http://www.hispavila.com/3ds/atmega/clavenum.html 
Usando el actual ejemplo de hardware se pueden activa 
algo o desactivar mediante el teclado - emulando lo 
que se puede encontrar en algunos sistemas de alarma y 
así­ sucesivamente. Nuestro objetivo con este ejemplo 
es muy simple. Un sistema de espera para obtener un PIN 
que se especifique previamente. Si el PIN es correcto, 
hacer algo. Si el PIN es incorrecto, hacer otra cosa. 
Lo que las acciones pueden llegar a hacer. Con el proyecto 
vamos a activar o desactivar una salida digital. 
Este ejemplo es para darle un concepto y un marco para 
adaptar o construir ideas propias. 
Usa 4654 bytes con el IDE v. 00013 
*/ 
#include  
#include  
#include  
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); Password 
password = Password( "1234456" ); // aquí puede poner su pasword 
const byte ROWS = 4; // Cuatro rows 
const byte COLS = 3; // Tres columns 
// Define el Keymap 
char keys[ROWS][COLS] = { 
 {'1','2','3',}, 
 {'4','5','6',}, 
 {'7','8','9',}, 
 {'*','0',' ',} }; 
// Conectar keypad ROW0, ROW1, ROW2 y ROW3 a los pines de Arduino. 
byte rowPins[ROWS] = {5, 4, 3, 2}; // pines a conectar los row del teclado. 
byte colPins[COLS] = {16, 15, 14}; // AN0, AN1 y AN2. Por falta de pines 
const int buttonPin = 6; //   
int buttonState = 0; 
int i; 
int sal1 = 17; // pin A4 salida a rele 
int sal2 = 18; // pin A5 salida a rele 

// Crear el Keypad 
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); 
#define ledPin 13 

void setup()
{ 
 pinMode(buttonPin, INPUT); 
 pinMode(sal1, OUTPUT); 
 pinMode(sal2, OUTPUT); 
 pinMode(ledPin, OUTPUT); 
 lcd.begin(20, 4); 
 digitalWrite(ledPin, LOW);   // pone el LED off 

 Serial.begin(9600); 
 keypad.addEventListener(keypadEvent); //añad. un evento listener para el keypad 
 keypad.setDebounceTime(250); 
 lcd.clear();     //Borra el LCD 
 lcd.setCursor(0,0); 
 lcd.print("Entre secuencia PIN:"); 
 lcd.setCursor(2,2); 
 lcd.print("* Para terminar"); 
 lcd.setCursor(0,3);  
 lcd.print(" Intentelo: "); 
} 
void loop()
{ 
 keypad.getKey(); 
 buttonState = digitalRead(buttonPin); 
 if (buttonState == HIGH) 
 { 
  lcd.clear(); 
 } 
} 
// atender algunos eventos especiales 
void keypadEvent(KeypadEvent eKey)
{ 
 switch (keypad.getState())
 { case 
 PRESSED: lcd.print(eKey); 
 switch (eKey)
  { 
   case ' ': guessPassword(); 
   break; 
   default: password.append(eKey); 
  } 
 } 
} 
void guessPassword()
{ 
 if (password.evaluate())
 { 
  digitalWrite(ledPin,HIGH); // activa el LED de la puerta .5 seg. delay(500); 
  digitalWrite(ledPin,LOW); // desactiva LED de la puerta 
  digitalWrite(sal1, HIGH); // activa relé1 de la puerta 
  digitalWrite(sal2, LOW);  // desactiva relé2 de la puerta 
  lcd.clear(); 
  lcd.setCursor(0,0); 
  lcd.print("PASSWORD VALIDO "); // 
  password.reset(); //resetea password despues de entrada correcta
  delay(1000); 
  lcd.setCursor(0,0); 
  lcd.print("Bienvenido, Sr."); 
  delay(1000); 
  for (int positionCounter = 0; positionCounter < 22; positionCounter++) 
   { 
   // scroll one position right: 
    lcd.scrollDisplayRight(); // espera un poco 
    delay(150); 
   } 
   delay(35000); // espera 35 segundos antes de volver añ inicio 
   setup(); // al inicio 
   } else
   { 
    i = i++; 
    digitalWrite(ledPin,LOW); 
    digitalWrite(sal1, LOW); 
    digitalWrite(sal2, HIGH); 
    lcd.clear(); 
    lcd.print("PASSWORD INVALIDO "); 
    password.reset(); //resets password after INCORRECT entry 
    delay(2000); // tiempo de retardo 
    lcd.clear(); 
    lcd.setCursor(0,2); 
    lcd.print(" Intentelo: "); 
   } 
   if (i==3) 
   { 
    lcd.setCursor(0,1); 
    lcd.print("Lo siento... "); 
    lcd.setCursor(0,2); 
    lcd.print("Intentelo mas tarde"); 
    delay(30000); 
    lcd.clear(); 
    lcd.setCursor(0,2); 
    lcd.print(" Intentelo: "); 
    i=0; 
   } 
 }

A estas subrutinas, se les ha incluido unos mensajes que, están acordes en cada caso, para hacer comprender al usuario, la situación que impera en cada momento. De modo que al iniciar el proceso, rige un mensaje que invita a introducir un número PIN y la forma de hacer su entrada mediante la pulsación de la tecla «*» (asterisco), como confirmación del PIN introducido.

Mediante la librería Pasword, se evalúa el PIN introducido y se produce un destello de un LED por un corto período de tiempo 1/2 segundo cuando hay coincidencia con la clave correcta. En ese momento, el mensaje que muestra la pantalla LCD, cambia a un nuevo mensaje que, le indica al usuario que ha obtenido el acceso y termina el proceso.

Un tiempo después (este intervalo de tiempo se puede ajustar a su gusto, antes de compilar), se vuelve a inicia todo el proceso, a la espera de un nuevo intento por un nuevo usuario.

Este ejemplo es un proyecto «completo», ya que como elementos externos, sólo necesita de dos resistencias de 10k, dos transistores universales NPN y dos diodos 1N4007 y dos relés de 12V con doble contacto o similar, para poder activar cargas de mayor consumo. Para terminar el presente tutorial, se muestra un archivo AVI que ilustra el proyecto.

Por supuesto que pude utilizar un dispositivo expansor de puertos como el conocido PCF8574. No lo he incluido en este diseño, por que los pines del Arduino Diecimila, están «clavados», es decir, el proyecto no necesita más de los que ya tiene. Sin embargo se muestra una distribución del mismo proyecto utilizando el PCF8574, por si alguien lo quisiera incluir.

En este diseño, para mayor claridad, no se han incluido los relés y los componentes asociados para su control.

Nota.- En estos ejemplos, se utilizado un LCD de 20×4, sin duda que el usuario, puede adaptar otro tipo de LCD, modificando los pines que se dedican al control de cada tipo de LCD.

Las librerías utilizadas en este artículo o tutorial se pueden descargar desde estos enlaces:

  LiquidCrystal.
  Keypad.zip.
  Password.
  Esquema.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Enviar Whatsapp
Hola 👋
¿En qué podemos ayudarte?