Lettura ingresso digitale (lezione 7)
Introduzione
Qualsiasi sistema elettronico, per avere una utilità pratica, deve interagire con l’ambiente esterno, tramite: sensori, periferica di comunicazione, display, ingressi digitali ecc.. In questo post vedremo come collegare ad Arduino un pulsante e faremo un’analisi meccanica del suo comportamento e quali sono le soluzioni da adottare per risolvere il problema del bounce (rimbalzo).
Anche in questo caso, come abbiamo visto per il post sull’accensione di un diodo LED, collegare un semplice pulsante ad Arduino, potrebbe sembrare un’operazione semplice da eseguire, come vedremo in seguito, bisogna tenere conto del comportamento meccanico del pulsate nel transitorio. La struttura che deve attivare il contatto è realizzata, generalmente, con una lamina conduttrice molto sottile, dopo la sollecitazione, dovuta alla pressione del pulsante essa vibra per qualche ms, in questo intervallo di tempo il contatto non è stabile e continua a vibrare.
In questo post analizzeremo i seguenti argomenti:
- Leggere un ingresso digitale, pilotato da un pulsante
- Come gestire il rimbalzo di un pulsante ed evitare le multiple letture
Schema elettrico
Di seguito ho riportato lo schema elettrico per la connessione di un pulsante ad un ingresso di Arduino:
L’impedenza d’ingresso di un dispositivo elettronico digitale è molto alta, pertanto, l’assorbimento di corrente, per un sistema con tecnologia CMOS, è dell’ordine di qualche uA, quindi, anche un segnale di bassa energia, come il rumore che si accoppia all’ingresso, può far commutare il suo stato.
Per il motivo appena decritto è stato aggiunto un resistore tra l’ingresso digitale di Arduino e massa, infatti, quando il pulsante è aperto, se non ci fosse il resistore, l’ingresso digitale risulterebbe floating (non collegato a nessuna sorgente), in questo caso, la connessione elettrica funge da antenna dove potrebbe accoppiarsi del rumore che può provocare continue commutazioni dello stato dell’ingresso.
Conclusione: con il resistore R1, forniamo all’ingresso digitale di Arduino, un riferimento stabile e prevedibile, quando il pulsante è aperto. L’ingresso digitale può trovarsi in due stati, in funzione della condizione del pulsante, come riportato nei punti di seguito:
- Quando il pulsante è aperto , l’ingresso di Arduino è nello stato basso
- Quando il pulsante è chiuso, l’ingresso di Arduino è nello stato alto
Filtrare le vibrazioni del pulsante
Come accennato nell’introduzione, quando applichiamo una pressione ad un pulsante, esso ha una fase transitoria, la quale deve essere gestita per evitare false letture dello stato d’ingresso di Arduino. Nel momento in cui, il pulsante cambia stato (da aperto a chiuso), se collegamo un oscilloscopio sull’ingresso, osserveremo delle oscillazioni della tensione applicata, che passa, in modo randomico, dallo stato alto a quello basso, questo fenomeno, provoca continue commutazioni dello stato d’ingresso di Arduino.
La fase transitoria del pulsante, che dura qualche ms, deve essere mitigata per evitare false commutazioni dell’ingresso, le soluzioni principali che si possono adottare sono due:
- Inserire un filtro passa basso con un Trigger di Smith
- Eseguire un filtraggio software.
Sarebbe molto interessante eseguire un piccolo esperimento, potremmo scrivere due codici, uno che legge lo stato dell’ingresso, dove e collegato il pulsante, e lo scrive su un’uscita di Arduino senza il filtro software, l’altro codice, simile, ma con l’introduzione del filtro software.
Se sull’uscita colleghiamo un oscilloscopio potremmo osservare che nel primo caso si ha una commutazione del suo stato, nella fase transitoria, mentre nel secondo caso l’uscita commuterà solo alla fine del transitorio. Per chi ha un oscilloscopio consiglio di fare questa prova.
Per verificare la corretta lettura dello stato d’ingresso di Arduino, ho collegato un diodo LED sull’uscita che commuta su ogni transizione, da basso ad alto, dell’ingresso dove è collegato il pulsante.
Soluzione software per filtrare il rimbalzo del pulsante
In questo esempio utilizzeremo la soluzione del filtraggio software, perché’: è più efficiente, più semplice e soprattutto non dobbiamo inserire altri due componenti al circuito d’ingresso, la soluzione ha un costo d’implementazione più basso.
Quando si progetta un circuito elettronico, bisogna sempre valutare la possibilità di una soluzione che abbia un costo inferiore, a parità di prestazione, le aziende sono molto sensibili ai costi di produzione, perché questo è uno dei parametri che determina il successo di un prodotto oltre a voler sempre massimizzare i margini di guadagno. Nei passi indicati di seguito e’ descritta la logica utilizzata per la risoluzione del problema:
- Chiamiamo la funzione “debounce” che legge lo stato d’ingresso del pulsante, se e’ diverso da quello precedentemente memorizzato, si effettua un filtraggio dell’ingresso per 5ms per poi ritornare lo stato del pulsante.
- Se il precedente stato del pulsante era basso e quello attuale è alto (questa tecnica si chiama derivata sul fronte di salita, in partica rileva il fronte di salita della commutazione) si esegue un “toggle” sull’uscita dove è connesso il diodo LED.
const int LED=9; // Colleghiamo il LED al pin 9 const int PULSANTE=2; // Colleghiamo il pulsante al pin 2 boolean lettura_prcedente_pulsante = LOW; // la variabile che contiene la precedente lettura //dello stato del LED boolean lettura_corrente_pulsante= LOW; // la variabile che contiene la lettura corrente //dello stato del LED boolean ledOn = false; // Lo stato presente del LED (ON/OFF) void setup() { pinMode (LED, OUTPUT); // setta il pin connesso al LED come una uscita pinMode (PULSANTE, INPUT); // Setta il pin connesso al PULSANTE come ingresso } // Funzione antiribalzo boolean debounce(boolean last) { boolean current = digitalRead(PULSANTE); // leggo lo stato del PULSANTE if (last != current) // se e' diverso { delay(5); // aspetta 5ms current = digitalRead(PULSANTE); // leggi ancora l'ingresso } return current; // ritorna il valore dello stato del pulsante } void loop() { lettura_corrente_pulsante = debounce(lettura_prcedente_pulsante); //Funzione che filtra l'ingresso if (lettura_prcedente_pulsante == LOW & & lettura_corrente_pulsante == HIGH) //se rileviamo un fronte di salita { ledOn = !ledOn; //Toggle il valore del LED } lettura_prcedente_pulsante = lettura_corrente_pulsante; digitalWrite(LED, ledOn); // }