.. note:: 

    Ciao, benvenuto nella Community di SunFounder per appassionati di Raspberry Pi, Arduino e ESP32 su Facebook! Approfondisci le tue conoscenze su Raspberry Pi, Arduino ed ESP32 insieme ad altri appassionati.

    **Perché unirti?**

    - **Supporto Esperto**: Risolvi i problemi post-vendita e le sfide tecniche con l'aiuto della nostra community e del nostro team.
    - **Impara e Condividi**: Scambia suggerimenti e tutorial per migliorare le tue competenze.
    - **Anteprime Esclusive**: Ottieni accesso anticipato agli annunci di nuovi prodotti e anteprime.
    - **Sconti Speciali**: Approfitta di sconti esclusivi sui nostri prodotti più recenti.
    - **Promozioni Festive e Giveaway**: Partecipa ai concorsi e alle promozioni festive.

    👉 Pronto a esplorare e creare insieme a noi? Clicca [|link_sf_facebook|] e unisciti oggi stesso!

2.1.5 Tastierino
==================

Introduzione
----------------

Un tastierino è un array rettangolare di pulsanti. In questo progetto, lo 
useremo per inserire caratteri.

Componenti
-------------

.. image:: img/list_2.1.5_keypad.png

Principio
-----------

**Tastierino**

Un tastierino è un array rettangolare di 12 o 16 pulsanti OFF-(ON). 
I contatti sono accessibili tramite un connettore adatto per un cavo 
a nastro o per l'inserimento in un circuito stampato. In alcuni tastierini, 
ogni pulsante è collegato a un contatto separato nel connettore, mentre tutti 
i pulsanti condividono una massa comune.

.. image:: img/image314.png

Più spesso, i pulsanti sono codificati a matrice, il che significa che ognuno di 
essi collega una coppia unica di conduttori in una matrice. Questa configurazione 
è adatta per un polling da parte di un microcontrollore, programmato per inviare 
un impulso di uscita su ciascuno dei quattro fili orizzontali a turno. Durante 
ogni impulso, controlla in sequenza i restanti quattro fili verticali per 
determinare quale di essi, se presente, sta trasmettendo un segnale. Per evitare 
comportamenti imprevedibili degli ingressi del microcontrollore quando non è 
presente alcun segnale, dovrebbero essere aggiunti resistori di pullup o pulldown ai 
fili di ingresso.

Schema Elettrico
-------------------

.. image:: img/image315.png

.. image:: img/image316.png


Procedure Sperimentali
-------------------------

**Passo 1:** Assembla il circuito.

.. image:: img/image186.png
    :width: 800

Per gli Utenti di Linguaggio C
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Passo 2:** Apri il file del codice.

.. raw:: html

   <run></run>

.. code-block::

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

**Passo 3:** Compila il codice.

.. raw:: html

   <run></run>

.. code-block::

    gcc 2.1.5_Keypad.cpp -lwiringPi

**Passo 4:** Esegui.

.. raw:: html

   <run></run>

.. code-block::

    sudo ./a.out

Dopo l'esecuzione del codice, i valori dei pulsanti premuti sul tastierino 
(Valore del pulsante) verranno visualizzati sullo schermo.

.. note::

    Se non funziona dopo l'esecuzione o viene visualizzato un messaggio di errore: \"wiringPi.h: No such file or directory\", fai riferimento a :ref:`Il codice C non funziona?`.
**Codice** 

.. code-block:: c

    #include <wiringPi.h>
    #include <stdio.h>

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

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

    unsigned char rowPins[ROWS] = {1, 4, 5, 6}; 
    unsigned char colPins[COLS] = {12, 3, 2, 0};

    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);

    void init(void) {
        for(int i=0 ; i<4 ; i++) {
            pinMode(rowPins[i], OUTPUT);
            pinMode(colPins[i], INPUT);
        }
    }

    int main(void){
        unsigned char pressed_keys[BUTTON_NUM];
        unsigned char last_key_pressed[BUTTON_NUM];

        if(wiringPiSetup() == -1){ //in caso di errore nella configurazione iniziale, stampa un messaggio a schermo
            printf("setup wiringPi failed !");
            return 1; 
        }
        init();
        while(1){
            keyRead(pressed_keys);
            bool comp = keyCompare(pressed_keys, last_key_pressed);
            if (!comp){
                keyPrint(pressed_keys);
                keyCopy(last_key_pressed, pressed_keys);
            }
            delay(100);
        }
        return 0;  
    }

    void keyRead(unsigned char* result){
        int index;
        int count = 0;
        keyClear(result);
        for(int i=0 ; i<ROWS ; i++ ){
            digitalWrite(rowPins[i], HIGH);
            for(int j =0 ; j < COLS ; j++){
                index = i * ROWS + j;
                if(digitalRead(colPins[j]) == 1){
                    result[count]=KEYS[index];
                    count += 1;
                }
            }
            delay(1);
            digitalWrite(rowPins[i], LOW);
        }
    }

    bool keyCompare(unsigned char* a, unsigned char* b){
        for (int i=0; i<BUTTON_NUM; i++){
            if (a[i] != b[i]){
                return false;
            }
        }
        return true;
    }

    void keyCopy(unsigned char* a, unsigned char* b){
        for (int i=0; i<BUTTON_NUM; i++){
            a[i] = b[i];
        }
    }

    void keyPrint(unsigned char* a){
        if (a[0] != 0){
            printf("%c",a[0]);
        }
        for (int i=1; i<BUTTON_NUM; i++){
            if (a[i] != 0){
                printf(", %c",a[i]);
            }
        }
        printf("\n");
    }

    void keyClear(unsigned char* a){
        for (int i=0; i<BUTTON_NUM; i++){
            a[i] = 0;
        }
    }

    int keyIndexOf(const char value){
        for (int i=0; i<BUTTON_NUM; i++){
            if ((const char)KEYS[i] == value){
                return i;
            }
        }
        return -1;
    }

**Spiegazione del Codice**

.. code-block:: c

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

    unsigned char rowPins[ROWS] = {1, 4, 5, 6}; 
    unsigned char colPins[COLS] = {12, 3, 2, 0};

Dichiara ciascun tasto della tastiera a matrice nell'array keys[] e definisce
i pin di ogni riga e colonna.

.. code-block:: c

    while(1){
            keyRead(pressed_keys);
            bool comp = keyCompare(pressed_keys, last_key_pressed);
            if (!comp){
                keyPrint(pressed_keys);
                keyCopy(last_key_pressed, pressed_keys);
            }
            delay(100);
        }

Questa parte della funzione principale legge e stampa il valore del pulsante
premuto.

La funzione keyRead() legge lo stato di ogni pulsante.

KeyCompare() e keyCopy() vengono utilizzate per verificare se lo stato di un
pulsante è cambiato (cioè se è stato premuto o rilasciato).

keyPrint() stampa il valore del pulsante che si trova attualmente ad un livello
alto (cioè il pulsante è premuto).

.. code-block:: c

    void keyRead(unsigned char* result){
        int index;
        int count = 0;
        keyClear(result);
        for(int i=0 ; i<ROWS ; i++ ){
            digitalWrite(rowPins[i], HIGH);
            for(int j =0 ; j < COLS ; j++){
                index = i * ROWS + j;
                if(digitalRead(colPins[j]) == 1){
                    result[count]=KEYS[index];
                    count += 1;
                }
            }
            delay(1);
            digitalWrite(rowPins[i], LOW);
        }
    }

Questa funzione assegna un livello alto a ciascuna riga a turno, e quando viene
premuto un pulsante in una colonna, la colonna in cui si trova il pulsante ottiene un
livello alto. Dopo il giudizio del ciclo a due livelli, la compilazione dello stato del
pulsante genererà un array (result[]).

Quando si preme il pulsante 3:

.. image:: img/image187.png


RowPin[0] scrive il livello alto e colPin[2] ottiene il livello alto.
ColPin[0], colPin[1], colPin[3] ottengono il livello basso.

Questo produce 0,0,1,0. Quando rowPin[1], rowPin[2] e rowPin[3] sono scritti ad un livello alto, 
colPin[0]~colPin[4] ottengono un livello basso.

Dopo il completamento del giudizio del ciclo, si genera un array:

.. code-block:: c

    result[BUTTON_NUM] {  
    0, 0, 1, 0,
    0, 0, 0, 0,
    0, 0, 0, 0,
    0, 0, 0, 0};

.. code-block:: c

    bool keyCompare(unsigned char* a, unsigned char* b){
        for (int i=0; i<BUTTON_NUM; i++){
            if (a[i] != b[i]){
                return false;
            }
        }
        return true;
    }

    void keyCopy(unsigned char* a, unsigned char* b){
        for (int i=0; i<BUTTON_NUM; i++){
            a[i] = b[i];
        }
    }

Queste due funzioni vengono utilizzate per determinare se lo stato del tasto è cambiato,
ad esempio quando si rilascia il pulsante premuto \'3\' o si preme \'2\', keyCompare()
restituisce false.

KeyCopy() viene utilizzata per riscrivere il valore corrente del pulsante per l'array a
(last_key_pressed[BUTTON_NUM]) dopo ogni confronto. Così possiamo confrontarli la
volta successiva.

.. code-block:: c

    void keyPrint(unsigned char* a){
    //printf("{");
        if (a[0] != 0){
            printf("%c",a[0]);
        }
        for (int i=1; i<BUTTON_NUM; i++){
            if (a[i] != 0){
                printf(", %c",a[i]);
            }
        }
        printf("\n");
    }

Questa funzione stampa il valore del pulsante attualmente premuto. Se viene premuto
il pulsante '1', verrà stampato '1'. Se vengono premuti i pulsanti '1' e '3', verrà
stampato '1, 3'.


Per Utenti Python
^^^^^^^^^^^^^^^^^^^^^^^^^

**Passo 2:** Apri il file del codice.

.. raw:: html

   <run></run>

.. code-block:: 

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

**Passo 3:** Esegui.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo python3 2.1.5_Keypad.py

Dopo aver eseguito il codice, i valori dei pulsanti premuti sulla tastiera (valore del pulsante)
verranno visualizzati sullo schermo.

**Codice**

.. note::

    Puoi **Modificare/Reimpostare/Copiare/Eseguire/Interrompere** il codice qui sotto. Prima di procedere, devi accedere al percorso del codice sorgente come ``davinci-kit-for-raspberry-pi/python``.

.. raw:: html

    <run></run>

.. code-block:: python

    import RPi.GPIO as GPIO
    import time

    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

    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 = []

    def loop():
        global keypad, last_key_pressed
        pressed_keys = keypad.read()
        if len(pressed_keys) != 0 and last_key_pressed != pressed_keys:
            print(pressed_keys)
        last_key_pressed = pressed_keys
        time.sleep(0.1)

    # Definisci una funzione di distruzione per pulire tutto al termine dello script
    def destroy():
        # Rilascia risorse
        GPIO.cleanup() 

    if __name__ == '__main__':     # Il programma inizia da qui
        try:
            setup()
            while True:
                loop()
        except KeyboardInterrupt:   # Quando viene premuto 'Ctrl+C', la funzione destroy() viene eseguita.
            destroy()
**Spiegazione del Codice**

.. code-block:: python

    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 = []

Dichiara ogni tasto della tastiera a matrice nell'array keys[] e definisce
i pin di ogni riga e colonna.

.. code-block:: python

    def loop():
        global keypad, last_key_pressed
        pressed_keys = keypad.read()
        if len(pressed_keys) != 0 and last_key_pressed != pressed_keys:
            print(pressed_keys)
        last_key_pressed = pressed_keys
        time.sleep(0.1)

Questa è la parte della funzione principale che legge e stampa il valore
del tasto premuto.

La funzione keyRead() legge lo stato di ogni tasto.

L'istruzione if len(pressed_keys) != 0 and last_key_pressed != pressed_keys 
viene utilizzata per determinare se è stato premuto un tasto e lo stato del 
tasto stesso. (Se premi '3' mentre premi '1', la condizione è vera.)

Stampa il valore del tasto premuto attualmente quando la condizione è verificata.

L'istruzione last_key_pressed = pressed_keys assegna lo stato di ogni verifica a 
un array last_key_pressed per facilitare il prossimo ciclo di verifica.

.. code-block:: python

    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

Questa funzione assegna un livello alto a ciascuna riga a turno e, quando
viene premuto il tasto in una colonna, la colonna in cui si trova il tasto
ottiene un livello alto. Dopo aver eseguito il loop a due livelli, il valore 
del tasto il cui stato è 1 viene memorizzato nell'array pressed_keys.

Se premi il tasto '3':

.. image:: img/image187.png


rowPins[0] viene impostato su alto, e colPins[2] ottiene il livello alto.

colPins[0], colPins[1], colPins[3] ottengono livello basso.

Gli stati sono quattro: 0, 0, 1, 0; e scriviamo '3' in pressed_keys.

Quando rowPins[1], rowPins[2], rowPins[3] sono impostati su alto,
colPins[0] ~ colPins[4] ottengono livello basso.

Il ciclo si interrompe e viene restituito pressed_keys = '3'.

Se premi i tasti '1' e '3', verrà restituito pressed_keys = ['1','3'].

Immagine del Fenomeno
--------------------------

.. image:: img/image188.jpeg


