Allenamento per l’esame di maturità
Percorso di laboratorio con Arduino per studenti di quinta ITIS

Obiettivo didattico
Scansionare una tastiera 4×4 senza usare una libreria esterna, acquisire una sequenza di tasti, confrontarla con un codice corretto e fornire un feedback di esito positivo o errore. L’attività allena gestione di matrici di pin, scansione righe/colonne, buffer di input e logica non bloccante.
Materiali suggeriti
- Arduino UNO R3 o UNO R4;
- tastiera 4×4;
- LED verde;
- LED rosso,
- buzzer opzionale;
- 2 resitori da 220 Ohm (per i LED);
- breadboard;
- cavetti jumper.
Schema di collegamento
Richiamo teorico
Una tastiera a matrice riduce il numero di fili usando righe e colonne. Il microcontrollore attiva una riga alla volta e legge le colonne. Se una colonna va a livello attivo, il tasto corrispondente a quella riga e colonna è premuto. Anche qui bisogna evitare il rimbalzo e gestire l’ingresso come sequenza di eventi.
Schema logico dell’attività
Il programma scansiona una riga alla volta. Quando rileva un tasto stabile, lo aggiunge al buffer. Se viene premuto # confronta il buffer con il codice atteso. Se il codice è corretto accende il LED verde. Se è errato accende il LED rosso, svuota il buffer e ricomincia.
Diagramma di flusso
Diagramma di flusso Mermaid
flowchart TD
A[Inizio] --> B[Configura righe, colonne e LED]
B --> C[Scansione tastiera]
C --> D{Tasto valido trovato?}
D -- No --> C
D -- Sì --> E{Tasto uguale a # ?}
E -- No --> F[Aggiungi carattere al buffer]
F --> C
E -- Sì --> G[Confronta buffer con codice]
G --> H{Codice corretto?}
H -- Sì --> I[Feedback verde e reset buffer]
H -- No --> J[Feedback rosso e reset buffer]
I --> C
J --> C
Programma
/*
Prof. Maffucci Michele
Esercizio 2: Tastiera 4x4 non bloccante con codice di accesso e feedback di errore
*/
// ---------------------------
// Pin delle 4 righe
// ---------------------------
const int righe[4] = { 2, 3, 4, 5 };
// ---------------------------
// Pin delle 4 colonne
// ---------------------------
const int colonne[4] = { 6, 7, 8, 9 };
// ---------------------------
// Mappa dei tasti
// ---------------------------
char mappaTasti[4][4] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
// ---------------------------
// LED di feedback
// ---------------------------
const int PIN_LED_VERDE = 10;
const int PIN_LED_ROSSO = 11;
// ---------------------------
// Codice corretto da inserire
// ---------------------------
char codiceCorretto[] = "2580";
// ---------------------------
// Buffer di ingresso utente
// ---------------------------
char bufferInput[8];
int indiceInput = 0;
// ---------------------------
// Variabili per antirimbalzo
// ---------------------------
char ultimoTastoLetto = '\0';
char ultimoTastoConfermato = '\0';
unsigned long istanteCambio = 0;
const unsigned long TEMPO_DEBOUNCE = 40;
void setup() {
// Le righe vengono pilotate in uscita.
for (int i = 0; i < 4; i = i + 1) {
pinMode(righe[i], OUTPUT);
digitalWrite(righe[i], HIGH);
}
// Le colonne sono ingressi con pull-up.
for (int i = 0; i < 4; i = i + 1) {
pinMode(colonne[i], INPUT_PULLUP);
}
pinMode(PIN_LED_VERDE, OUTPUT);
pinMode(PIN_LED_ROSSO, OUTPUT);
Serial.begin(9600);
svuotaBuffer();
}
void loop() {
// Leggo il tasto corrente tramite scansione.
char tastoCorrente = leggiTastiera();
// Se è cambiato il valore grezzo, aggiorno il tempo.
if (tastoCorrente != ultimoTastoLetto) {
ultimoTastoLetto = tastoCorrente;
istanteCambio = millis();
}
// Se il valore è stabile da abbastanza tempo, lo confermo.
if ((millis() - istanteCambio) >= TEMPO_DEBOUNCE) {
if (tastoCorrente != ultimoTastoConfermato) {
ultimoTastoConfermato = tastoCorrente;
// Elaboro il tasto solo quando è reale e non nullo.
if (ultimoTastoConfermato != '\0') {
gestisciTasto(ultimoTastoConfermato);
}
}
}
}
// ----------------------------------------------------------
// Scansione manuale della tastiera.
// Attivo una riga alla volta e leggo tutte le colonne.
// ----------------------------------------------------------
char leggiTastiera() {
for (int r = 0; r < 4; r = r + 1) {
// Prima porto tutte le righe alte.
for (int i = 0; i < 4; i = i + 1) {
digitalWrite(righe[i], HIGH);
}
// Poi attivo solo la riga corrente.
digitalWrite(righe[r], LOW);
// Leggo tutte le colonne.
for (int c = 0; c < 4; c = c + 1) {
if (digitalRead(colonne[c]) == LOW) {
return mappaTasti[r][c];
}
}
}
// Se non trovo alcun tasto, restituisco nullo.
return '\0';
}
// ----------------------------------------------------------
// Gestione del carattere ricevuto.
// * cancella, # conferma, altri tasti vengono memorizzati.
// ----------------------------------------------------------
void gestisciTasto(char tasto) {
Serial.print("Tasto ricevuto: ");
Serial.println(tasto);
if (tasto == '*') {
svuotaBuffer();
Serial.println("Buffer cancellato");
} else if (tasto == '#') {
verificaCodice();
} else {
if (indiceInput < 7) {
bufferInput[indiceInput] = tasto;
indiceInput = indiceInput + 1;
bufferInput[indiceInput] = '\0';
}
}
}
// ----------------------------------------------------------
// Confronto del buffer con il codice corretto.
// ----------------------------------------------------------
void verificaCodice() {
bool corretto = true;
for (int i = 0; codiceCorretto[i] != '\0'; i = i + 1) {
if (bufferInput[i] != codiceCorretto[i]) {
corretto = false;
}
}
// Verifico anche la lunghezza.
if (indiceInput != 4) {
corretto = false;
}
if (corretto == true) {
Serial.println("CODICE CORRETTO");
digitalWrite(PIN_LED_VERDE, HIGH);
delay(500);
digitalWrite(PIN_LED_VERDE, LOW);
} else {
Serial.println("CODICE ERRATO");
digitalWrite(PIN_LED_ROSSO, HIGH);
delay(500);
digitalWrite(PIN_LED_ROSSO, LOW);
}
svuotaBuffer();
}
// ----------------------------------------------------------
// Ripulisce il buffer e rimette l'indice a zero.
// ----------------------------------------------------------
void svuotaBuffer() {
for (int i = 0; i < 8; i = i + 1) {
bufferInput[i] = '\0';
}
indiceInput = 0;
}






