.. note::

    ¡Hola! Bienvenido a la comunidad de entusiastas de SunFounder para Raspberry Pi, Arduino y ESP32 en Facebook. Únete para profundizar en Raspberry Pi, Arduino y ESP32 junto a otros apasionados.

    **¿Por qué unirte?**

    - **Soporte de Expertos**: Resuelve problemas post-venta y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
    - **Aprende y Comparte**: Intercambia consejos y tutoriales para mejorar tus habilidades.
    - **Avances Exclusivos**: Obtén acceso anticipado a anuncios de nuevos productos y vistas previas.
    - **Descuentos Especiales**: Disfruta de descuentos exclusivos en nuestros productos más recientes.
    - **Promociones Festivas y Sorteos**: Participa en sorteos y promociones de temporada.

    👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy.

3.1.9 Bloqueo por Contraseña
=================================

Introducción
----------------

En este proyecto, utilizaremos un teclado y una pantalla LCD para crear un 
bloqueo con combinación. La LCD mostrará un mensaje para que ingreses tu 
contraseña en el teclado. Si la contraseña es correcta, se mostrará "Correcto".

En base a este proyecto, podemos añadir componentes electrónicos adicionales, 
como un zumbador, LED, etc., para implementar diferentes fenómenos experimentales 
relacionados con la entrada de la contraseña.

Componentes
---------------

.. image:: img/list_Password_Lock.png
    :align: center

Diagrama Esquemático
-----------------------

============ ======== ======== ===
T-Board Name physical wiringPi BCM
GPIO18       Pin 12   1        18
GPIO23       Pin 16   4        23
GPIO24       Pin 18   5        24
GPIO25       Pin 22   6        25
GPIO17       Pin 11   0        17
GPIO27       Pin 13   2        27
GPIO22       Pin 15   3        22
SPIMOSI      Pin 19   12       10
SDA1         Pin 3             
SCL1         Pin 5             
============ ======== ======== ===

.. image:: img/Schematic_three_one9.png
   :align: center

Procedimientos Experimentales
----------------------------------

**Paso 1:** Construye el circuito.

.. image:: img/image262.png
   :alt: 3.1.3_PasswordLock_bb_看图王
   :width: 800

**Para Usuarios de Lenguaje C**
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Paso 2**: Cambia de directorio.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/davinci-kit-for-raspberry-pi/c/3.1.9/

**Paso 3**: Compila.

.. raw:: html

   <run></run>

.. code-block:: 

    gcc 3.1.9_PasswordLock.cpp -lwiringPi

**Paso 4:** Ejecuta.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo ./a.out

Después de ejecutar el código, utiliza el teclado para ingresar la contraseña. 
Si aparece "CORRECTO" en el LCD1602, la contraseña es correcta; de lo contrario, 
aparecerá "CLAVE INCORRECTA".

.. note::

    Si no funciona después de ejecutarlo, o aparece un mensaje de error: \"wiringPi.h: No such file or directory", consulta :ref:`C code is not working?`.

**Explicación del Código**

.. code-block:: c

    #define ROWS  4 
    #define COLS  4
    #define BUTTON_NUM (ROWS * COLS)
    #define LENS  4

    unsigned char KEYS[BUTTON_NUM] {  
    '1','2','3','A',
    '4','5','6','B',
    '7','8','9','C',
    '*','0','#','D'};

    char password[LENS]={'1','9','8','4'};

Aquí, definimos la longitud de la contraseña LENS, una matriz de valores de 
teclas KEYS y el array que almacena la contraseña correcta.

.. code-block:: c

    void keyRead(unsigned char* result);
    bool keyCompare(unsigned char* a, unsigned char* b);
    void keyCopy(unsigned char* a, unsigned char* b);
    void keyPrint(unsigned char* a);
    void keyClear(unsigned char* a);
    int keyIndexOf(const char value);

Declaración de las subfunciones para el código de teclado matricial. 
Consulta :ref:`2.1.5 Keypad` de este documento para más detalles.

.. code-block:: c

    void write_word(int data);
    void send_command(int comm);
    void send_data(int data);
    void lcdInit();
    void clear();
    void write(int x, int y, char const data[]);

Declaración de las subfunciones para el código LCD1062. Consulta 
:ref:`1.1.7 I2C LCD1602` de este documento para más detalles.

.. code-block:: c

    while(1){
            keyRead(pressed_keys);
            bool comp = keyCompare(pressed_keys, last_key_pressed);
            ...
                    testword[keyIndex]=pressed_keys[0];
                    keyIndex++;
                    if(keyIndex==LENS){
                        if(check()==0){
                            clear();
                            write(3, 0, "WRONG KEY!");
                            write(0, 1, "please try again");
                            }
                    ...

Lee el valor de la tecla y lo almacena en el array de prueba testword. 
Si el número de valores almacenados supera los 4, se verifica automáticamente 
la corrección de la contraseña, y el resultado se muestra en la pantalla LCD.

.. code-block:: c

    int check(){
        for(int i=0;i<LENS;i++){
            if(password[i]!=testword[i])
            {return 0;}
        }
        return 1;
    }


Verifica la corrección de la contraseña. Devuelve 1 si la contraseña es 
correcta y 0 en caso contrario.

**Para Usuarios de Lenguaje Python**
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Paso 2:** Cambia de directorio.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/davinci-kit-for-raspberry-pi/python/

**Paso 3:** Ejecuta.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo python3 3.1.9_PasswordLock.py

Después de ejecutar el código, utiliza el teclado para ingresar la 
contraseña:1984. Si aparece "CORRECTO" en el LCD1602, la contraseña 
es correcta; de lo contrario, aparecerá "CLAVE INCORRECTA".

**Código**

.. note::

    Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a continuación. Pero antes, necesitas dirigirte a la ruta del código fuente, como ``davinci-kit-for-raspberry-pi/python``. 

.. raw:: html

    <run></run>

.. code-block:: python

    import RPi.GPIO as GPIO 
    import time
    import LCD1602

    ##################### AQUÍ ESTÁ LA LIBRERÍA DEL TECLADO TRANSFERIDA DESDE Arduino ############
    #class Key:Define algunas de las propiedades de Key
    class Keypad():

        def __init__(self, rowsPins, colsPins, keys):
            self.rowsPins = rowsPins
            self.colsPins = colsPins
            self.keys = keys
            GPIO.setwarnings(False)
            GPIO.setmode(GPIO.BCM)
            GPIO.setup(self.rowsPins, GPIO.OUT, initial=GPIO.LOW)
            GPIO.setup(self.colsPins, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

        def read(self):
            pressed_keys = []
            for i, row in enumerate(self.rowsPins):
                GPIO.output(row, GPIO.HIGH)
                for j, col in enumerate(self.colsPins):
                    index = i * len(self.colsPins) + j
                    if (GPIO.input(col) == 1):
                        pressed_keys.append(self.keys[index])
                GPIO.output(row, GPIO.LOW)
            return pressed_keys

    ################ CÓDIGO DE EJEMPLO INICIA AQUÍ ################        
    LENS = 4
    password=['1','9','8','4']
    testword=['0','0','0','0']
    keyIndex=0
    
    def check():
        for i in range(0,LENS):
            if(password[i]!=testword[i]):
                return 0
        return 1

    def setup():
        global keypad, last_key_pressed
        rowsPins = [18,23,24,25]
        colsPins = [10,22,27,17]
        keys = ["1","2","3","A",
                "4","5","6","B",
                "7","8","9","C",
                "*","0","#","D"]
        keypad = Keypad(rowsPins, colsPins, keys)
        last_key_pressed = []
        LCD1602.init(0x27, 1)    # init(dirección esclava, luz de fondo)
        LCD1602.clear()
        LCD1602.write(0, 0, 'WELCOME!')
        LCD1602.write(2, 1, 'Enter password')
        time.sleep(2)

    def destroy():
        LCD1602.clear()
        GPIO.cleanup()

    def loop():
        global keyIndex
        global LENS
        global keypad, last_key_pressed
        while(True):
            pressed_keys = keypad.read()
            if len(pressed_keys) != 0 and last_key_pressed != pressed_keys:
                LCD1602.clear()
                LCD1602.write(0, 0, "Enter password:")
                LCD1602.write(15-keyIndex,1, pressed_keys)
                testword[keyIndex]=pressed_keys
                keyIndex+=1
                if (keyIndex is LENS):
                    if (check() is 0):
                        LCD1602.clear()
                        LCD1602.write(3, 0, "WRONG KEY!")
                        LCD1602.write(0, 1, "please try again")
                    else:
                        LCD1602.clear()
                        LCD1602.write(4, 0, "CORRECT!")
                        LCD1602.write(2, 1, "welcome back")
                keyIndex=keyIndex%LENS

            last_key_pressed = pressed_keys
            time.sleep(0.1)
            
    if __name__ == '__main__':     # El programa comienza desde aquí
        try:
            setup()
            loop()
        except KeyboardInterrupt:  # Cuando se presiona 'Ctrl+C', se ejecuta destroy().
            destroy()


**Explicación del Código**

.. code-block:: python

    LENS = 4
    password=['1','9','8','4']
    ...
    rowsPins = [18,23,24,25]
    colsPins = [10,22,27,17]
    keys = ["1","2","3","A",
            "4","5","6","B",
            "7","8","9","C",
            "*","0","#","D"]



Aquí definimos la longitud de la contraseña LENS, el array keys que
almacena las teclas del teclado matricial y el array password que
guarda la contraseña correcta.

.. code-block:: python

    class Keypad():
        def __init__(self, rowsPins, colsPins, keys):
            self.rowsPins = rowsPins
            self.colsPins = colsPins
            self.keys = keys
            GPIO.setwarnings(False)
            GPIO.setmode(GPIO.BCM)
            GPIO.setup(self.rowsPins, GPIO.OUT, initial=GPIO.LOW)
            GPIO.setup(self.colsPins, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    ...

Esta clase contiene el código que lee los valores de las teclas presionadas. Consulta
:ref:`2.1.5 Teclado` de este documento para más detalles.

.. code-block:: python

    while(True):
            pressed_keys = keypad.read()
            if len(pressed_keys) != 0 and last_key_pressed != pressed_keys:
                LCD1602.clear()
                LCD1602.write(0, 0, "Enter password:")
                LCD1602.write(15-keyIndex,1, pressed_keys)
                testword[keyIndex]=pressed_keys
                keyIndex+=1
    ...



Lee el valor de la tecla y lo almacena en el array de prueba testword. Si el
número de valores de teclas almacenados supera los 4, se verifica automáticamente la
corrección de la contraseña, y los resultados de la verificación se muestran en la interfaz LCD.

.. code-block:: python

    def check():
        for i in range(0,LENS):
            if(password[i]!=testword[i]):
                return 0
        return 1

Verifica la corrección de la contraseña. Devuelve 1 si la contraseña es
correcta y 0 si no lo es.

Imagen del Fenómeno
------------------------

.. image:: img/image263.jpeg
   :align: center