Come utilizzare un keypad a 12 tasti (tastiera 4×3) con Arduino UNO
Gestire una tastiera 4×3 o comunemente tastierino numerico, permette di sviluppare applicazioni nelle quali l’utente ha la possibilità di interagire con Arduino UNO immettendo codici numerici, come ad esempio password per accedere ad aree riservate o impostare parametri per far funzionare in modo corretto un apparecchio.
La lettura dello stato dei pulsanti del tastierino avviene eseguendo un continuo scansionamento (pooling) degli stessi.
Un tipico tastierino 4×3 è composto da una matrice di pulsanti disposti in 4 righe e 3 colonne. Quando premiamo un pulsante della tastiera viene collegata elettricamente una riga con una colonna.
Per capire quale sia il pulsante premuto, dovremmo alimentare in sequenza le 3 colonne e contemporaneamente controllare il livello di tensione in ogni singola riga. La figura seguente mostra cosa avviene quando premiamo uno dei tre pulsanti della prima riga.
Ogni colonna viene messa al livello logico alto (5Vdc) in modo continuo.
Se premiamo il primo pulsante della prima riga (mentre è presente la tensione di 5Vdc nella prima colonna), otterremo che all’uscita della riga sarà disponibile un livello logico alto.
Questo avviene anche premendo il secondo ed il terzo pulsante rispettivamente quando la seconda e la terza colonna sono alimentate.
Quindi, cosa dobbiamo fare se vogliamo capire quale sia il pulsante premuto, dato che all’uscita della riga otteniamo lo stesso valore?
La logica del software deve considerare il valore della riga in base alla colonna alimentata.
In parole semplici, so che quando alimento la prima colonna ed in uscita dalla prima riga ho un valore logico alto il pulsante premuto è certamente il primo. Quando alimento la seconda colonna e ottengo anche in questo caso un valore logico alto in uscita dalla prima riga, capisco che il pulsante premuto è il numero 2, questo perché l’attivazione delle colonne deve avvenire sempre in modo univoco.
Questo procedimento deve essere fatto in modo ciclico per tutte le colone e per tutte le righe.
Quindi avendo quattro righe il codice deve alimentare la prima colonna e controllare l’uscita delle quattro righe per verificare dove si trova il livello logico alto (nel caso si prema un pulsante):
Il circuito elettrico
Lo schema seguente mostra come collegare una comune tastiera 4×3 ad Arduino UNO.
Pin Arduino | Pin Tastiera 4×3 |
2 | R1 |
3 | R2 |
4 | R3 |
5 | R4 |
6 | C1 |
7 | C2 |
8 | C3 |
Il codice di gestione
Il codice per poter gestire la tastiera 4×3 è riportato di seguito. Viene utilizzata la classe Serial per poter inviare al monitor seriale il valore del tasto premuto.
Possiamo notare che per ridurre i componenti necessari alla realizzazione del circuito, ho sfruttato la funzione che permette di attivare le resistenza di pull-up. Attivando questa funzione ottengo che sulle righe R1, R2, R3 e R4 è presente uno stato logico alto (dovuto appunto alle resistenze).
Per capire se un tasto è premuto, al contrario della teoria vista precedentemente, devo verificare quando la riga va a livello logico basso.
Per far ciò i livelli logici sulle colonne devono essere invertiti di segno nel senso che se nella teoria ponevo ciclicamente un livello logico alto, ora dovremmo metterne uno basso.
con l’attivazione delle resistenze di pull-up il circuito risulta in questo modo:
di conseguenza dato che i pin 2, 3, 4 e 5 sono degli ingressi, per capire se un pulsante è premuto dovremmo verificare che il livello logico sia basso in quanto la pressione di un pulsante permetterà di collegare la resistenza di pull-up a massa.
Ad esempio se in un dato istante sulle colonne imposto C1 livello basso, C2 livello alto, C3 livello alto e premo il primo pulsante della riga R1, sul pin2 di Arduino UNO avrò un livello logico basso e quindi capirò che il pulsante premuto è il numero 1 della tastiera 4×3.
[c]
void setup()
{
Serial.begin(9600);
//questi ingressi servono per collegare
//le righe della tastiera
//notare l’attivazione delle resistenze di pull-up
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
//prima colonna
pinMode(6, OUTPUT);
//setto alto il livello
//per disabilitare la colonna
digitalWrite(6, HIGH);
//seconda colonna
pinMode(7, OUTPUT);
//setto alto il livello
//per disabilitare la colonna
digitalWrite(7, HIGH);
//terza colonna
pinMode(8, OUTPUT);
//setto alto il livello
//per disabilitare la colonna
digitalWrite(8 , HIGH);
}
void loop()
{
//antirimbalzo
delay(40);
//Seleziono la prima colonna
digitalWrite(6, LOW);
//Controllo il primo pulsante
//della prima riga
if(digitalRead(2) == LOW)
Serial.println("1");
//Controllo il primo pulsante
//della seconda riga
if(digitalRead(3) == LOW)
Serial.println("4");
//Controllo il primo pulsante
//della terza riga
if(digitalRead(4) == LOW)
Serial.println("7");
//Controllo il primo pulsante
//della quarta riga
if(digitalRead(5) == LOW)
Serial.println("*");
//Deseleziono la prima colonna
digitalWrite(6, HIGH);
//Seleziono la seconda colonna
digitalWrite(7, LOW);
//Controllo il secondo pulsante
//della prima riga
if(digitalRead(2) == LOW)
Serial.println("2");
//Controllo il secondo pulsante
//della seconda riga
if(digitalRead(3) == LOW)
Serial.println("5");
//Controllo il secondo pulsante
//della terza riga
if(digitalRead(4) == LOW)
Serial.println("8");
//Controllo il secondo pulsante
//della quarta riga
if(digitalRead(5) == LOW)
Serial.println("0");
//Deseleziono la seconda colonna
digitalWrite(7, HIGH);
//Seleziono la prima colonna
digitalWrite(8, LOW);
//Controllo il primo pulsante
//della prima riga
if(digitalRead(2) == LOW)
Serial.println("3");
//Controllo il primo pulsante
//della seconda riga
if(digitalRead(3) == LOW)
Serial.println("6");
//Controllo il primo pulsante
//della terza riga
if(digitalRead(4) == LOW)
Serial.println("9");
//Controllo il primo pulsante
//della quarta riga
if(digitalRead(5) == LOW)
Serial.println("#");
//Deseleziono la prima colonna
digitalWrite(8, HIGH);
}
[/c]
Il codice funziona ma ha un problema che rende quasi inutilizzabile la tastiera. Infatti aprendo il serial monitor e premendo un tasto avremmo una serie di letture. Questo perché nel momento in cui pigiamo il tasto, il codice è talmente veloce che riesce a scansionare il pulsante premuto varie volte:
Esistono più soluzioni per ovviare a questa situazione, la più banale è quella di far eseguire ad Arduino un ciclo infinito fintanto che il pulsante è premuto.
In questo modo avremmo che sul serial monitor verrà inviato solo un carattere anche tenendo a lungo premuto il pulsante relativo:
[c]
void setup()
{
Serial.begin(9600);
//questi ingressi servono per collegare
//le righe della tastiera
//notare l’attivazione delle resistenze di pull-up
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
//prima colonna
pinMode(6, OUTPUT);
//setto alto il livello
//per disabilitare la colonna
digitalWrite(6, HIGH);
//seconda colonna
pinMode(7, OUTPUT);
//setto alto il livello
//per disabilitare la colonna
digitalWrite(7, HIGH);
//terza colonna
pinMode(8, OUTPUT);
//setto alto il livello
//per disabilitare la colonna
digitalWrite(8 , HIGH);
}
void loop()
{
//antirimbalzo
delay(40);
//Seleziono la prima colonna
digitalWrite(6, LOW);
//Controllo il primo pulsante
//della prima riga
if(digitalRead(2) == LOW)
{
Serial.println("1");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(2) == LOW)
;
}
//Controllo il primo pulsante
//della seconda riga
if(digitalRead(3) == LOW)
{
Serial.println("4");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(3) == LOW)
;
}
//Controllo il primo pulsante
//della terza riga
if(digitalRead(4) == LOW)
{
Serial.println("7");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(4) == LOW)
;
}
//Controllo il primo pulsante
//della quarta riga
if(digitalRead(5) == LOW)
{
Serial.println("*");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(5) == LOW)
;
}
//Deseleziono la prima colonna
digitalWrite(6, HIGH);
//Seleziono la seconda colonna
digitalWrite(7, LOW);
//Controllo il secondo pulsante
//della prima riga
if(digitalRead(2) == LOW)
{
Serial.println("2");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(2) == LOW)
;
}
//Controllo il secondo pulsante
//della seconda riga
if(digitalRead(3) == LOW)
{
Serial.println("5");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(3) == LOW)
;
}
//Controllo il secondo pulsante
//della terza riga
if(digitalRead(4) == LOW)
{
Serial.println("8");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(4) == LOW)
;
}
//Controllo il secondo pulsante
//della quarta riga
if(digitalRead(5) == LOW)
{
Serial.println("0");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(5) == LOW)
;
}
//Deseleziono la seconda colonna
digitalWrite(7, HIGH);
//Seleziono la prima colonna
digitalWrite(8, LOW);
//Controllo il primo pulsante
//della prima riga
if(digitalRead(2) == LOW)
{
Serial.println("3");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(2) == LOW)
;
}
//Controllo il primo pulsante
//della seconda riga
if(digitalRead(3) == LOW)
{
Serial.println("6");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(3) == LOW)
;
}
//Controllo il primo pulsante
//della terza riga
if(digitalRead(4) == LOW)
{
Serial.println("9");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(4) == LOW)
;
}
//Controllo il primo pulsante
//della quarta riga
if(digitalRead(5) == LOW)
{
Serial.println("#");
//fintanto che il pulsante è premuto non
//uscire dal ciclo while
while(digitalRead(5) == LOW)
;
}
//Deseleziono la prima colonna
digitalWrite(8, HIGH);
}
[/c]
Il codice può essere decisamente più compatto utilizzando dei cicli for e delle matrici di variabili, o addirittura utilizzando una libreria esterna già pronta. Questo articolo serve soprattutto a quelle persone che vogliono capire cosa succede effettivamente quali sono i collegamenti interni della tastiera e quali sono le problematiche nella gestione software.
Related posts
3 Comments
Lascia un commento Annulla risposta
Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.
Articoli popolari
Sorry. No data so far.
.Net micro framework Arduino Arduino Webserver Domotica Flyport I2C IOT Netduino OpenPicus raspberry RTC Speed Test
Ciao Marco…innanzitutto voglio farti i complimenti per il tuo ottimo lavoro con i tutorial su Arduino ma vorrei chiederti un aiuto riguardo un problema che ho è ti chiedo scusa per il fatto che non riguardi l’articolo su cui lascio il commento ma è l’unico che riesco a commentare.
Allora il mio problema è il seguente:
Sto cercando di realizzare un piccolo robot comandato via internet con un server in labview da cui invio i comandi e un Arduino mega 2560 con scheda ethernet che li riceve come client.
Arduino riceve i comandi ma non riesco a utilizzarli…cioè ho visto la tua guida che risolve un problema simile è con il comando che hai usato tu in quel caso riesco a creare una stringa con i termini char che ricevo da client.read ma non riesco a utilizzarli…sai come potrei fare per estrarre ogni volta solo il comando che il quel momento mi interessa?
Ad esempio invio da labview la stringa “led1on/led2off”, come faccio a estrarre il comando dalla stringa per scendere il led?
Io ho fatto così ma non funziona:”
a = client.read();
String comando +=a;
int led1 = comando.indexOf(led1on);
Serial.println(led1);
Da labview parte una stringa che può essere :”led1on” oppure “led1off” ma sulla seriale indipendente da cosa arriva a Arduino mi trovo sempre il valore “-1” corrispondente alla variabile led1 come potrei fare?
Grazie mille in anticipo e ancora complimenti!
Complimenti per il tutorial e per il sito in generale. Volevo sugerire un metodo migliore per evitare le ripetizioni, invece del while che blocca il loop perché non memorizzare semplecemente il tasto in una variabile temporanea e visualizzarlo solo se è diverso dal precedente?
Ciao Emanuele
sicuramente esistono molti metodi per ottimizzare il codice, oltre alla tua idea si potrebbero usare anche gli interupt. L’articolo serve soprattutto per spiegare in maniera molto elementare cosa avviene dietro le quinte.
Grazie per i complimenti e per il commento.
Marco