2020-09-30

Electronica Practica Aplicada

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.


Fig. 1

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.


Fig. 4 Tabla de direcciones.

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:

//                  (Adds,En,Rw,Rs,D4,D5,D6,D7)
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:

Password password = Password("123A4566"); // entre su passwor

El siguiente cambio esta en la declaración del mapeado del teclado:

#include "Keypad.h"
  const byte ROWS = 4; //four rows
  const byte COLS = 4; //four columns
  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.

// vigile el orden de los pines.
byte rowPins[ROWS] = {9, 8, 7, 6}; // pines digitales - filas
byte colPins[COLS] = {5, 4, 3, 2}; // pines digitales - columnas

Debemos declarar el segundo I2C que utilizaremos para el teclado.

  int i2caddress = 0x38; // 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:

 // Secuencia para crear la matriz del teclado (Keypad)
 Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

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:

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:

    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.

// 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.