Registro de Entrada por Número PIN.
Con teclado matricial 4×4 con LCD.
PROLOGO.
En otro artículo sobre teclados ya vimos un ejemplo de cómo crear un acceso mediante un PIN a una estancia, en aquella ocasión utilizábamos un teclado de 3×4 y un LCD numérico de 20×4, ambos muy conocidos. se servían de unas librerías que actualmente se han mejorado. En esta ocasión vamos a utilizar el mismo ejemplo y las herramientas o mejor dicho los dispositivos los hemos actualizado para que el interesado pueda extraer mejores resultados y utilice los nuevos dispositivos y librerías.
El display empleado es el mismo un LCD de 4 lineas y 20 dígitos, en esta ocasión con la ayuda de un adaptador serial comercial y por otra parte un teclado de 4×4 por adaptarse bien al proyecto y ser muy económico ambos los vemos a continuación.
El convertidor o mochila serie lo aplicaremos al display para reducir los puertos o pines del Arduino, además se muestra un PCB de un adaptador mediante un PCF8574A para el teclado matricial, que puede realizar con el pdf adjunto.
Fig. 2 PCB del convertidor de 8Bits.
También puede adquirir un convertidor comercial como el mostrado en la siguiente figura.
Fig. 3 Convertidor de 8Bits comercial.
En cualquiera de los dos casos, no olvide declarar la dirección del conversor, usted puede elegir entre las posibles.
Por otra parte hemos dispuestos las nuevas librerías necesarias para el actualizado código para manejar la entrada del PIN mediante el teclado matricial. El primer cambio esta en la declaración del teclado:
1 2 |
<span style="color: #336600;">// (Adds,En,Rw,Rs,D4,D5,D6,D7)</span> LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3,POSITIVE); |
El segundo cambio esta en la declaración del passwor, como ya se vio en el anterior artículo tenemos que crear una clave, el código que introduzca el usuario:
1 |
Password password = Password("123A4566"); <span style="color: #336600;">// entre su passwor</span> |
El siguiente cambio esta en la declaración del mapeado del teclado:
1 2 3 4 5 6 7 8 |
#include "Keypad.h" const byte ROWS = 4; <span style="color: #336600;">//four rows</span> const byte COLS = 4; <span style="color: #336600;">//four columns</span> char keys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'} }; |
Donde hacemos constar que son 4 filas y 4 columnas, en la declaración del mapa del teclado añadimos las teclas de la cuarta columna A, B, C y D. También declaramos los pines del mapa del teclado.
1 2 3 |
<span style="color: #336600;">// vigile el orden de los pines.</span> byte rowPins[ROWS] = {9, 8, 7, 6}; <span style="color: #336600;">// pines digitales - filas</span> byte colPins[COLS] = {5, 4, 3, 2}; <span style="color: #336600;">// pines digitales - columnas</span> |
Debemos declarar el segundo I2C que utilizaremos para el teclado.
1 |
<span class="kwrd"> int</span> i2caddress =<span style="color: #ff0000;"><strong> 0x38</strong></span>; // por ej. |
Ahora es el momento de ‘crear’ el teclado propiamente dicho, es decir, con una 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:
1 2 |
<span style="color: #336600;">// Secuencia para crear la matriz del teclado (Keypad)</span> Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); |
1 2 |
char PIN[6]={'1','2','3','A','4','5','6','6'}; // o numero secreto (!) char attempt[6]={0,0,0,0,0,0,0,0}; <span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start"></span><span style="color: #00ff00;"><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_end"></span>// usado para comparar</span> |
-->
En el caso de disponer de un convertidor I2C que contiene al chip PCF8574, lo podemos utilizar para el teclado con la siguiente línea:
1 |
Keypad_I2C kpd = Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, i2caddress ); |
El resto del código lo hemos mejorado sólo un poco. En el setup() se incluye la sentencia lcd.setBacklight(HIGH); // para activar el backlight para lo que se indica en ella. El resto de del código es bastante explicito por lo que sólo se comentará algo cuando se crea de interés. Por ejemplo, en el loop(), se han añadido las siguientes líneas:
1 2 3 4 5 6 7 8 9 10 |
if (buttonState == LOW) { Serial.println("Ha pulsado el boton ...."); for(int z=0; z<6; z++){ lcd.setCursor(1,3); lcd.print("ALARMA ACTIVADA!"); delay(1000); lcd.setCursor(1,3); lcd.print(" "); delay(500); } setup(); //incorrectPIN(); |
Para presentar el estado de alarma en el caso de pulsar el botón dispuesto para tal fin. Ahora veamos el código completo en el que hemos dispuesto un sólo adaptador para el display.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
// clave_pin_I2C.ino - keypad switch con ocho digitos para el PIN // // // clave_pin_lcd.pde - keypad switch con ocho digitos para el PIN // basado en el chapter 42 de // http://tronixstuff.wordpress.com/tutorials // /* El circuito: * LCD 20x4 basado en el HD44780 * 2 botones a los pines 6 y 7. Marcha/Paro y Puesta a Cero. * LED en pin 13 (opcional para indicar la pulsacion de los botones) PINES PINES LCD Arduino 4 7 5 GND 6 8 11 9 12 10 13 11 14 12 Definicion de funciones de control LCD printtime(); Escribe el tiempo clearLCD(); Borrar el LCD lcd.setCursor(0,0); columna -y- fila lcd.setCursor(0,0); Escribir en la columna 1, 1a linea lcd.setCursor(0,1); Escribir en la columna 1, 2a linea lcd.setCursor(2,2); Escribir en la columna 3, 3a linea lcd.setCursor(0,3); Escribir en la columna 1, 3a linea Usando hardware descrito, se pueden activa o desactivar algo mediante el teclado - reproduciendo lo que se puede encontrar en algunos sistemas de alarma y asi aplicar las sugerencias que se nos ocurran. El objetivo con este ejemplo es, simular - los sistemas de acceso para obtener un PIN previamente especifico. Si el PIN es correcto, hacer algo. Si el PIN no es correcto, hacer otra cosa. Las acciones que se puedan ocurrir, pero para el ejemplo vamos a activar o desactivar una salida digital. Este ejemplo es para aprender un concepto y un marco, para desarrollar ideas propias. Se utiliza una clave con seis dígitos para el PIN. El signo '#' del teclado, se emplea como la función ENTER. 09.11.2011 funciona bien. Usando IDE v.0013/0023 con 4506 bytes adaptado por V. García. para hispavila.com */ #include "Password.h" // lib. Password //#include "LiquidCrystal.h" // necesitamos esta lib. LiquidCrystal.h para los comandos de LCD #include "LiquidCrystal_I2C.h" // lib. LiquidCrystal_I2C.h para mochila I2C #include "Keypad_I2C.h" // lib. Keypad_I2C.h para módulo conversor #include "Keypad.h" // libreria Keypad.h para teclado // inicializa la libreria con los numeros de interface de los pines // lcd (RS,RW, E, D4,D5, D6, D7) // LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // **** si no usa I2C // El valor 0x27, debe adecuarse al elegido en los pines A0, A1 y A2 // del adaptador serie, este valor 0x27 corresponde a estos 3 pines a HIGH // LiquidCrystal_I2C lcd(0x27); // o 39. Set the LCD I2C address // set the LCD address to "0x27"(or "0x3f") for a 16 chars and 2 line display // set the LCD address to "0x3f"(or "0x27") for a 16 chars and 2 line display // En la versión LiquidCrystal_I2C de 2019, se debe usar como sigue: // (Adds,En,Rw,Rs,D4,D5,D6,D7) LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3,POSITIVE); Password password = Password("123A4566"); // entre su password const byte ROWS = 4; // Cuatro filas const byte COLS = 4; // Tres columns, cambio añado A B C D // Define el Keymap char keys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0',' ','D'}}; // vigile el orden de los pines. byte rowPins[ROWS] = {11, 10, 9, 8}; // pines digitales - filas byte colPins[COLS] = {5, 4, 3, 2}; // pines analógicos - column (AN2, AN1 y AN0) const int buttonPin = 6; // pin 2 para un pulsador. int buttonState = 0; // Secuencia para crear el teclado (Keypad) Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); int ledPin = 13; // para uso indistinto. int sal1 = 12; // pin 10 digital. Rele de potencia //int sal2 = 12; // pin 11 digital. Rele de potencia void setup(){ // lcd.setBacklightPin(3,POSITIVE); // ya declarado lcd.setBacklight(HIGH); // para activar el backlight pinMode(buttonPin, INPUT); digitalWrite(buttonPin, HIGH); digitalWrite(ledPin, LOW); // pone el LED en off digitalWrite(sal1, LOW); buttonState = digitalRead(buttonPin); // lee el estado inicial pinMode(ledPin, OUTPUT); pinMode(sal1, OUTPUT); // pinMode(sal2, OUTPUT); Serial.begin(9600); lcd.begin(20, 4); keypad.addEventListener(keypadEvent); //add an event listener for this keypa keypad.setDebounceTime(250); // retardo anti-rebote Serial.println("clave_pin_i2c.ino Listo \n"); lcd.clear(); //Borra el LCD delay(500); lcd.setCursor(1,0); lcd.print("clave_pin_I2C.ino"); delay(2500); lcd.clear(); //Borra el LCD delay(500); lcd.setCursor(0,0); lcd.print("Entre secuencia PIN:"); lcd.setCursor(0,1); lcd.print(" 8 digitos + # "); // X X X X X X + # lcd.setCursor(0,2); lcd.print("Intentelo: "); // las 2 lineas que siguen aseguran los contactos de puertas digitalWrite(sal1, LOW); // desactiva un contacto // digitalWrite(sal2, HIGH); // activa un contacto } void loop(){ keypad.getKey(); buttonState = digitalRead(buttonPin); if (buttonState == LOW) { Serial.println("Ha pulsado el boton ...."); digitalWrite(buttonPin, HIGH); lcd.clear(); for(int z=0; z < 6; z++){ lcd.setCursor(0,2); lcd.print(" "); digitalWrite(ledPin, HIGH); delay(10); lcd.setCursor(0,2); lcd.print("ALARMA ACTIVADA! "); digitalWrite(ledPin, LOW); delay(10); delay(200); lcd.setCursor(0,2); lcd.print(" "); delay(100); } paraAlarma(); // setup(); //incorrectPIN(); } } void paraAlarma(){ // digitalWrite(buttonPin, LOW); lcd.setCursor(0,2); lcd.print(" "); lcd.setCursor(0,2); lcd.print("Pulsa parar Alarma"); keypad.getKey(); buttonState = digitalRead(buttonPin); if (buttonState == HIGH) { // delay(2000); Serial.println("PIT-PIT"); return; } // } void correctPIN() // hacer esto. Si el PIN escrito es correcto { digitalWrite(sal1, HIGH); // activa un contacto pin 12 // digitalWrite(sal2, HIGH); // activa el contacto del pin 2 lcd.clear(); lcd.setCursor(2,1); // set cursor to column 2, row 0 (the first row) lcd.print("PASSWORD VALIDO!"); Serial.println("PASSWORD VALIDO"); // password.reset(); //resetea password después de entrada correcta delay(1000); lcd.setCursor(2,1); lcd.print(" "); for (int z=0; z>3; z++) { for (int positionCounter = 0; positionCounter < 21; positionCounter++) //desplaza text { lcd.setCursor(1,0); lcd.print("Bienvenido..."); lcd.setCursor(2,1); lcd.print(" "); // // scroll una posición a derecha: lcd.scrollDisplayRight(); // esperar un poco. delay(120); } } delay(5000); setup(); } void incorrectPIN() // hacer esto. Si el PIN escrito es incorrecto { digitalWrite(sal1, LOW); // desactiva un contacto // digitalWrite(sal2, HIGH); // activa un contacto lcd.clear(); lcd.setCursor(0,0); lcd.print("PASSWORD INVALIDO "); Serial.println("PASSWORD INVALIDO"); delay(1500); lcd.clear(); password.reset(); //resetea password después de entrada INCORRECTA delay(100); lcd.clear(); lcd.setCursor(0,0); lcd.print("Entre secuencia PIN:"); lcd.setCursor(0,2); lcd.print("Reintentar:"); } // atender algunos eventos especiales void keypadEvent(KeypadEvent eKey){ parpadea(); // parpadea switch (keypad.getState()){ case PRESSED: lcd.print(eKey); Serial.print(eKey); switch (eKey){ case ' ': guessPassword(); break; default: password.append(eKey); } } } void parpadea(){ digitalWrite(ledPin, HIGH); delay(10); digitalWrite(ledPin, LOW); } void guessPassword(){ if (password.evaluate()){ digitalWrite(ledPin,HIGH); //activa rele de la puerta delay(800); digitalWrite(ledPin,LOW); //desactiva rele de la puerta .5 sec correctPIN(); } else{ digitalWrite(ledPin,LOW); delay(500); digitalWrite(ledPin,HIGH); //desactiva rele de la puerta .5 sec incorrectPIN(); } } |
Como de costumbre seleccione el código y guárdelo con un nombre apropiado, compílelo y súbalo al Arduino, para comprobar su efectividad. Es muy recomendable actualizar las librerías a la última versión para conseguir que todo vaya bien, si no se menciona lo contrario.
En el vídeo siguiente se puede apreciar que aún conservo el Arduino de cuando empecé (buena señal) y la efectividad del programa.
Vídeo
Si tiene alguna duda haga su pregunta, intentaré responder.