Come usare un keypad 3x4 e 4x4 con Arduino: collegamenti e codice

I keypad a membrana 3x4 e 4x4 sono tastiere compatte molto usate nei progetti Arduino. Permettono di inserire numeri, codici, comandi e scelte di menu senza utilizzare molti pulsanti separati. In questa lezione vedremo come funzionano internamente, come riconoscere righe e colonne, come collegarli ad Arduino UNO e come leggerli con la libreria Keypad.

Keypad 3x4 e 4x4: quali sono le differenze?

Confronto tra keypad a membrana 3x4 e keypad 4x4 per Arduino

Il keypad 3x4 contiene 12 tasti: le cifre da 0 a 9, il simbolo * e il simbolo #. È organizzato in 4 righe e 3 colonne e utilizza quindi 7 collegamenti.

Il keypad 4x4 contiene 16 tasti. Oltre ai tasti numerici, * e #, aggiunge normalmente i tasti A, B, C e D. È organizzato in 4 righe e 4 colonne e richiede 8 collegamenti.

I tasti A-D possono essere utilizzati per selezionare modalità, aprire menu, confermare operazioni o assegnare comandi speciali.

Come funziona un keypad a membrana

Un keypad a membrana è formato da sottili strati flessibili con piste conduttive. Tra gli strati è presente uno spazio che mantiene separati i contatti quando nessun tasto viene premuto. Premendo un tasto, le membrane si avvicinano e chiudono elettricamente il contatto tra una riga e una colonna.

Il tasto 5, per esempio, non invia direttamente il carattere “5”. Chiude invece l'incrocio tra la riga e la colonna in cui si trova. Arduino scopre quale tasto è stato premuto identificando quella combinazione di riga e colonna.

Questi keypad sono componenti passivi: non hanno un vero pin VCC e non hanno un pin GND. I fili del connettore corrispondono soltanto alle righe e alle colonne della matrice. Per questo non devi collegare un filo del keypad direttamente ai 5 V o a GND.

Come Arduino legge la matrice

Per leggere la tastiera, Arduino esegue continuamente una procedura chiamata scansione della matrice:

  1. configura le righe come ingressi con resistenza di pull-up;
  2. porta una colonna alla volta a livello LOW;
  3. legge tutte le righe;
  4. se una riga diventa LOW, il tasto all'incrocio tra quella riga e la colonna attiva è premuto;
  5. ripete la procedura molto velocemente per tutte le colonne.

La libreria Keypad svolge automaticamente questa scansione e gestisce anche il normale debounce, cioè i piccoli rimbalzi elettrici che possono apparire quando un contatto viene premuto o rilasciato. Con la libreria non servono normalmente resistori esterni per leggere il keypad.

Pinout dei keypad 3x4 e 4x4

Pinout dei keypad a membrana 3x4 e 4x4 con righe R1-R4 e colonne C1-C4

Con il connettore orientato esattamente come nell'immagine, i contatti sono disposti da sinistra verso destra nel seguente ordine:

  • Keypad 3x4: R1, R2, R3, R4, C1, C2, C3.
  • Keypad 4x4: R1, R2, R3, R4, C1, C2, C3, C4.

Alcuni modelli prodotti da aziende differenti possono presentare un ordine diverso oppure un connettore montato al contrario. Se i tasti risultano scambiati, controlla l'orientamento oppure identifica righe e colonne con la funzione di continuità di un multimetro.

Come collegare un keypad 3x4 ad Arduino UNO

Nel nostro esempio utilizzeremo questi collegamenti:

  • R1 → pin 9
  • R2 → pin 8
  • R3 → pin 7
  • R4 → pin 6
  • C1 → pin 5
  • C2 → pin 4
  • C3 → pin 3

I pin 0 e 1 rimangono liberi per la comunicazione seriale. Puoi utilizzare altri pin digitali, ma devi aggiornare gli array rowPins e colPins nel programma.

Come collegare un keypad 4x4 ad Arduino UNO

  • R1 → pin 9
  • R2 → pin 8
  • R3 → pin 7
  • R4 → pin 6
  • C1 → pin 5
  • C2 → pin 4
  • C3 → pin 3
  • C4 → pin 2

Anche in questo caso non esistono collegamenti VCC o GND: tutti gli otto fili vanno ai pin digitali di Arduino.

collegamenti ad Arduino per entrambi i differenti kaypad

Installare la libreria Keypad di Arduino

Apri il Library Manager dell'Arduino IDE, cerca Keypad e installa la libreria per tastiere a matrice di Mark Stanley e Alexander Brevig. Nel programma sarà poi sufficiente aggiungere:

#include <Keypad.h> // Importa la libreria necessaria per gestire il keypad a matrice.

La libreria permette di scegliere liberamente il numero di righe, il numero di colonne, i pin utilizzati e il carattere associato a ogni posizione.

Codice Arduino per keypad 3x4

keypad_3x4.ino
// https://nemiatools.com
#include <Keypad.h> // Importa la libreria necessaria per gestire il keypad a matrice.

const byte ROWS = 4; // Imposta a quattro il numero di righe del keypad.
const byte COLS = 3; // Imposta il numero di colonne del keypad.

char keys[ROWS][COLS] = { // Inizia la mappa dei caratteri corrispondenti ai tasti.
  {'1', '2', '3'}, // Associa i caratteri alla prima riga della tastiera.
  {'4', '5', '6'}, // Associa i caratteri alla seconda riga della tastiera.
  {'7', '8', '9'}, // Associa i caratteri alla terza riga della tastiera.
  {'*', '0', '#'} // Associa i caratteri alla quarta riga della tastiera.
}; // Termina la dichiarazione della matrice dei tasti.

// R1, R2, R3, R4
byte rowPins[ROWS] = {9, 8, 7, 6}; // Collega le righe R1-R4 ai pin digitali 9, 8, 7 e 6.

// C1, C2, C3
byte colPins[COLS] = {5, 4, 3}; // Associa ciascuna colonna ai rispettivi pin Arduino.

Keypad keypad = Keypad( // Inizia la creazione dell’oggetto che gestisce il keypad.
  makeKeymap(keys), // Passa alla libreria la mappa dei caratteri dei tasti.
  rowPins, // Indica i pin Arduino collegati alle righe.
  colPins, // Indica i pin Arduino collegati alle colonne.
  ROWS, // Comunica all’oggetto il numero di righe.
  COLS // Comunica all’oggetto il numero di colonne.
); // Completa la costruzione dell’oggetto keypad.

void setup() {
  Serial.begin(9600); // Avvia la comunicazione seriale a 9600 baud.
  Serial.println("Keypad 3x4 pronto"); // Mostra il messaggio iniziale nel Monitor Seriale.
}

void loop() {
  char key = keypad.getKey(); // Legge un nuovo tasto premuto, se disponibile.

  if (key != NO_KEY) { // Verifica che sia stato rilevato un tasto valido.
    Serial.print("Tasto premuto: "); // Scrive la descrizione prima del carattere rilevato.
    Serial.println(key); // Stampa il carattere premuto e va a capo.
  } // Termina il controllo sulla presenza di un tasto.
}

Apri il Monitor Seriale a 9600 baud. Ogni volta che premi un tasto, Arduino visualizzerà il carattere corrispondente. La funzione getKey() non blocca il programma: se non è stato premuto nulla, restituisce NO_KEY e il loop continua normalmente.

Come è strutturato il codice del keypad

Le costanti ROWS e COLS definiscono le dimensioni della matrice. Nel 3x4 vengono quindi impostate 4 righe e 3 colonne.

L'array bidimensionale keys descrive la posizione fisica dei caratteri. La prima riga contiene 1, 2 e 3; la seconda contiene 4, 5 e 6 e così via. Se il tuo keypad restituisce tasti sbagliati, questa matrice o l'ordine dei pin potrebbe non corrispondere al cablaggio reale.

Gli array rowPins e colPins indicano quali pin Arduino sono collegati rispettivamente a R1-R4 e alle colonne. La funzione makeKeymap(keys) converte la matrice dei caratteri nel formato utilizzato dalla libreria.

Infine l'oggetto Keypad keypad unisce mappa, pin e dimensioni. Da quel momento keypad.getKey() esegue la scansione e restituisce il carattere premuto.

Codice Arduino per keypad 4x4

keypad_4x4.ino
// https://nemiatools.com
#include <Keypad.h> // Importa la libreria necessaria per gestire il keypad a matrice.

const byte ROWS = 4; // Imposta a quattro il numero di righe del keypad.
const byte COLS = 4; // Imposta il numero di colonne del keypad.

char keys[ROWS][COLS] = { // Inizia la mappa dei caratteri corrispondenti ai tasti.
  {'1', '2', '3', 'A'}, // Associa i caratteri alla prima riga della tastiera.
  {'4', '5', '6', 'B'}, // Associa i caratteri alla seconda riga della tastiera.
  {'7', '8', '9', 'C'}, // Associa i caratteri alla terza riga della tastiera.
  {'*', '0', '#', 'D'} // Associa i caratteri alla quarta riga della tastiera.
}; // Termina la dichiarazione della matrice dei tasti.

// R1, R2, R3, R4
byte rowPins[ROWS] = {9, 8, 7, 6}; // Collega le righe R1-R4 ai pin digitali 9, 8, 7 e 6.

// C1, C2, C3, C4
byte colPins[COLS] = {5, 4, 3, 2}; // Associa ciascuna colonna ai rispettivi pin Arduino.

Keypad keypad = Keypad( // Inizia la creazione dell’oggetto che gestisce il keypad.
  makeKeymap(keys), // Passa alla libreria la mappa dei caratteri dei tasti.
  rowPins, // Indica i pin Arduino collegati alle righe.
  colPins, // Indica i pin Arduino collegati alle colonne.
  ROWS, // Comunica all’oggetto il numero di righe.
  COLS // Comunica all’oggetto il numero di colonne.
); // Completa la costruzione dell’oggetto keypad.

void setup() {
  Serial.begin(9600); // Avvia la comunicazione seriale a 9600 baud.
  Serial.println("Keypad 4x4 pronto"); // Mostra il messaggio iniziale nel Monitor Seriale.
}

void loop() {
  char key = keypad.getKey(); // Legge un nuovo tasto premuto, se disponibile.

  if (key != NO_KEY) { // Verifica che sia stato rilevato un tasto valido.
    Serial.print("Tasto premuto: "); // Scrive la descrizione prima del carattere rilevato.
    Serial.println(key); // Stampa il carattere premuto e va a capo.
  } // Termina il controllo sulla presenza di un tasto.
}

Rispetto alla versione 3x4 cambia il numero di colonne, viene aggiunto il pin C4 e la mappa include A, B, C e D. Il resto del funzionamento rimane identico.

Funzioni più utili della libreria Keypad

  • getKey() → restituisce un nuovo tasto premuto senza bloccare il resto del programma.
  • waitForKey() → aspetta finché non viene premuto un tasto; durante l'attesa il programma rimane bloccato.
  • setDebounceTime(ms) → modifica il tempo di debounce espresso in millisecondi.
  • setHoldTime(ms) → imposta dopo quanti millisecondi un tasto viene considerato mantenuto premuto.
  • addEventListener() → collega una funzione agli eventi del keypad, utile per distinguere pressione, mantenimento e rilascio.
  • getKeys() → aggiorna l'elenco dei tasti attivi ed è utile nei programmi che devono gestire più pressioni.

Esempio pratico: inserire un codice PIN

Questo esempio utilizza il keypad 4x4. Le cifre vengono memorizzate, il tasto * cancella l'inserimento e il tasto # conferma. Se il codice è corretto, il LED integrato di Arduino si accende per un secondo. Lo stesso principio può essere usato con un keypad 3x4 modificando soltanto mappa e collegamenti iniziali.

keypad_pin_code.ino
// https://nemiatools.com
#include <Keypad.h> // Importa la libreria necessaria per gestire il keypad a matrice.
#include <string.h> // Importa le funzioni C per confrontare stringhe, incluso strcmp().

const byte ROWS = 4; // Definisce le quattro righe della tastiera.
const byte COLS = 4; // Definisce le quattro colonne della tastiera.

char keys[ROWS][COLS] = { // Inizia la mappa dei caratteri del keypad 4x4.
  {'1', '2', '3', 'A'}, // Mappa i tasti della prima riga: 1, 2, 3 e A.
  {'4', '5', '6', 'B'}, // Mappa i tasti della seconda riga: 4, 5, 6 e B.
  {'7', '8', '9', 'C'}, // Mappa i tasti della terza riga: 7, 8, 9 e C.
  {'*', '0', '#', 'D'} // Mappa i tasti della quarta riga: *, 0, # e D.
}; // Termina la mappa bidimensionale dei caratteri.

byte rowPins[ROWS] = {9, 8, 7, 6}; // Collega le righe R1-R4 ai pin digitali 9, 8, 7 e 6.
byte colPins[COLS] = {5, 4, 3, 2}; // Collega le colonne C1-C4 ai pin digitali 5, 4, 3 e 2.

Keypad keypad = Keypad( // Inizia la costruzione dell’oggetto keypad.
  makeKeymap(keys), // Fornisce la disposizione dei caratteri alla libreria.
  rowPins, // Passa l’elenco dei pin collegati alle righe.
  colPins, // Passa l’elenco dei pin collegati alle colonne.
  ROWS, // Specifica il numero di righe della matrice.
  COLS // Specifica il numero di colonne della matrice.
); // Conclude la creazione dell’oggetto Keypad.

const char correctCode[] = "2580"; // Definisce il PIN corretto, fissato qui a 2580.
char enteredCode[9]; // Riserva nove caratteri: fino a otto cifre più il terminatore.
byte enteredLength = 0; // Inizializza a zero il numero delle cifre inserite.

void clearCode() {
  enteredLength = 0; // Azzera il conteggio delle cifre memorizzate.
  enteredCode[0] = '\0'; // Inserisce il terminatore per rendere vuota la stringa.
} // Conclude la funzione che cancella il codice inserito.

void setup() {
  Serial.begin(9600); // Attiva la porta seriale a 9600 baud.
  pinMode(LED_BUILTIN, OUTPUT); // Configura il LED integrato di Arduino come uscita.

  keypad.setDebounceTime(25); // Imposta il filtro antirimbalzo a 25 millisecondi.

  Serial.println("Inserisci il codice"); // Invita l’utente a digitare il codice.
  Serial.println("* = cancella, # = conferma"); // Spiega che * cancella e # conferma il codice.
}

void loop() {
  char key = keypad.getKey(); // Legge il tasto premuto in questa iterazione.

  if (key == NO_KEY) { // Controlla se nessun nuovo tasto è stato rilevato.
    return; // Esce subito dal ciclo corrente se non ci sono tasti.
  } // Conclude il controllo sul tasto assente.

  if (key == '*') { // Verifica se è stato premuto il tasto * di cancellazione.
    clearCode(); // Elimina tutte le cifre precedentemente inserite.
    Serial.println("\nCodice cancellato"); // Comunica che l’inserimento è stato cancellato.
  } // Termina la gestione del tasto di cancellazione.
  else if (key == '#') { // In alternativa, verifica se # conferma il codice.
    enteredCode[enteredLength] = '\0'; // Chiude la stringa inserita con il terminatore nullo.

    if (strcmp(enteredCode, correctCode) == 0) { // Confronta il codice inserito con il PIN previsto.
      Serial.println("\nCodice corretto"); // Segnala che il PIN corrisponde a quello corretto.

      digitalWrite(LED_BUILTIN, HIGH); // Accende il LED integrato per segnalare l’esito positivo.
      delay(1000); // Mantiene il LED acceso per 1000 millisecondi.
      digitalWrite(LED_BUILTIN, LOW); // Spegne il LED dopo la segnalazione.
    } // Conclude il ramo eseguito quando il PIN è corretto.
    else { // Gestisce il caso in cui il PIN non corrisponda.
      Serial.println("\nCodice errato"); // Mostra il messaggio relativo al PIN errato.
    } // Conclude il ramo del PIN errato.

    clearCode(); // Svuota l’inserimento dopo ogni conferma.
  } // Conclude la gestione del tasto #.
  else if (key >= '0' && key <= '9') { // Accetta solo caratteri numerici compresi tra 0 e 9.
    if (enteredLength < sizeof(enteredCode) - 1) { // Controlla di lasciare spazio al terminatore di stringa.
      enteredCode[enteredLength] = key; // Memorizza la cifra nella posizione corrente.
      enteredLength++; // Incrementa il numero di cifre inserite.
      enteredCode[enteredLength] = '\0'; // Mantiene la stringa terminata dopo l’ultima cifra.

      Serial.print('*'); // Mostra un asterisco invece della cifra inserita.
    } // Conclude la verifica dello spazio disponibile.
  } // Conclude la gestione di una cifra numerica.
}

Debounce, pressione prolungata e più tasti

Quando premi un contatto meccanico, il segnale può oscillare rapidamente per alcuni millisecondi. La libreria filtra automaticamente questo fenomeno, ma puoi modificare il valore con setDebounceTime(). Un tempo troppo basso può produrre pressioni doppie, mentre un valore troppo alto può rendere la tastiera poco reattiva.

Con setHoldTime() puoi stabilire quando una pressione diventa un evento HOLD. Questa funzione è utile, per esempio, per assegnare un comando diverso alla pressione breve e a quella prolungata.

La libreria può tenere traccia di più tasti, ma i comuni keypad a membrana non contengono diodi su ogni interruttore. Premendo più tasti contemporaneamente possono quindi comparire combinazioni false, chiamate ghosting. Per password e menu è consigliabile premere un solo tasto alla volta.

Applicazioni dei keypad con Arduino

  • serrature elettroniche con codice;
  • menu per display LCD o OLED;
  • calcolatrici e tastierini numerici;
  • selezione di modalità e impostazioni;
  • controllo di robot e piccoli macchinari;
  • inserimento di quantità, tempi o valori di configurazione.

Problemi comuni

Arduino non rileva nessun tasto

Controlla tutti i fili e verifica che l'ordine di righe e colonne corrisponda agli array del programma. Assicurati inoltre di aver installato correttamente la libreria Keypad.

I tasti stampati non corrispondono a quelli premuti

Il connettore potrebbe essere orientato al contrario oppure il tuo modello potrebbe avere un pinout differente. Modifica l'ordine di rowPins e colPins, oppure identifica i contatti con un multimetro.

Un tasto viene letto due volte

Aumenta leggermente il debounce, per esempio con keypad.setDebounceTime(25);. Controlla anche che il connettore sia stabile.

Il keypad 4x4 legge bene i numeri ma non A-D

Controlla il collegamento della quarta colonna C4 e verifica che COLS sia impostato a 4.