Dispense Arduino
Materiale tratto dal nostro corso di base Arduino, con esempi ed esercizi

Lettura di sensori
In questa lezione vedremo come usare i pin digitali di Arduino come input, ovvero abilitarli alla lettura di impulsi esterni. Approfondiremo la differenza fra la lettura digitale e analogica, imparando a leggere sia dei semplici impulsi che degli stati di tensione variabili.
Pulsanti e interruttori

Dalla figura vediamo che i pushbuttons hanno solitamente due pin opposti sempre connessi
fra loro (in questo caso AC e BD); premendo il bottone si chiude un contatto che cortocircuita
le coppie adiacenti AC e BD. Vorremmo adesso applicare questo su Arduino, realizzando
un programma che accende un led se il bottone è premuto.
Nota: in definitiva l'effetto del pushbutton è quello di connettere due parti di curcuito,
quindi una coppia di pin è ridondante, e serve esclusivamente per comodità nel realizzare
circuiti stampati.
Se impostato in lettura, un pin digitale va a determinare lo stato di tensione
che vi si applica: così come per l'output possiamo leggere uno stato HIGH
,
compreso fra i 5 e i 2.5 Volt, e uno stato LOW
,
fra i 2.5 e gli 0 Volt.
La circuiteria è la seguente: un capo del pulsante è collegato all'alimentazione positiva (5v),
l'altro capo arriva sia al pin di Arduino (digital 2
), sia ad una resistenza collegata
alla massa (GND); con il pulsante a riposo la lettura è LOW
, poiché è presente
la resistenza collegata a massa. Premendo il pulsante, il pin si viene a trovare a potenziale 5v,
e si avra di conseguenza la lettura HIGH
.
La funzionalità della resistenza è duplice:
se si rimuovesse del tutto si avrebbe una lettura instabile nelle condizioni a riposo, poiché
il pin di Arduino, scollegato, sarebbe soggetto a qualsiasi tipo di interferenza
elettrostatica (scariche dalle mani, correnti indotte sulla scheda o sulla breadboard...);
Se invece si effettuasse un collegamento diretto a massa, premendo il bottone si avrebbe
un cortocircuito. Per questo la resistenza deve avere un valore alto, tale da non
provocare inutili correnti, ovvero dell'ordine dei 10kΩ. Puoi verificare, applicando la legge di
Ohm, che la corrente che la attraversa in caso pulsante attivo è di circa 500uA, pressoché
nulla.
Una resistenza posta in questa configurazione è detta pull-down, per la sua funzionalità di mantenere un segnale basso stabile. Si può porre, analogamente, una resistenza in pull-up collegandola invece al positivo: Si può provare come esercizio a realizzare circuito e programma in tale configurazione.
// Pin del bottone const byte PIN_BOTTONE = 2; // Pin del LED const byte PIN_LED = 13; // Variabile di stato del bottone byte statoBottone = 0; void setup() { pinMode(PIN_LED, OUTPUT); // LED in INPUT pinMode(PIN_BOTTONE, INPUT); // bottone in OUTPUT } void loop(){ // Leggo il bottone e memorizzo lo stato statoBottone = digitalRead(PIN_BOTTONE); // Se il pin del bottone è HIGH (premuto)... if (statoBottone == HIGH) { // Accendo il LED digitalWrite(PIN_LED, HIGH); } // Altrimenti... else { // Spengo il LED digitalWrite(PIN_LED, LOW); } delay(10); }
Pull-up interno
// Pin del bottone const byte PIN_BOTTONE = 2; // Pin del LED const byte PIN_LED = 13; // Variabile di stato del bottone byte statoBottone = 0; void setup() { pinMode(PIN_LED, OUTPUT); // LED in INPUT // bottone in OUTPUT, e abilito il PullUp interno pinMode(PIN_BOTTONE, INPUT_PULLUP); } void loop(){ // Leggo il bottone e memorizzo lo stato statoBottone = digitalRead(PIN_BOTTONE); // Se il pin del bottone è LOW (premuto)... if (statoBottone == LOW) { // Accendo il LED digitalWrite(PIN_LED, HIGH); } // Altrimenti... else { // Spengo il LED digitalWrite(PIN_LED, LOW); } delay(10); }
Il chip integrato di Arduino ha, per ogni pin di output, una resistenza
integrata collegata a +5V (pull-up). Questa può essere collegata
internamente (nella figura questa possibilità è stata resa con un
interruttore "interno" al chip). L'abilitazione viene fatta nel codice
in fase di inizializzazione, impostando il pin come INPUT_PULLUP
anziché come INPUT
.
Il circuito esterno si semplifica notevolmente, non essendoci più
necessità di inserire la resistenza esterna. Nel codice, invece,
avremo un'inversione negli stati del bottone: quando non è
premuto la lettura è HIGH
, quando è premuto LOW
.
Ottimizzazione del codice
Le righe 16-20 dei precedenti listati possono essere semplificate
accorgendosi che, in configurazione pull-down, lo stato del bottone
corrisponde allo stato del LED
(bottone LOW
→ led LOW
).
const byte PIN_BOTTONE = 2; // pin del bottone const byte PIN_LED = 13; // pin del led byte statoBottone = 0; // variabile di stato del bottone void setup() { pinMode(PIN_LED, OUTPUT); // il pin del LED è in OUTPUT pinMode(PIN_BOTTONE, INPUT); } void loop(){ digitalWrite(PIN_LED, digitalRead(PIN_BOTTONE)); delay(20); }
Esercizi
- Luce passo passo: premendo e rilasciando il bottone, il led si accende, ripetendo l'operazione si spegne;
- Luci colorate: riprendi l'esercizio di "luce passo passo" ed estendilo per 5 led. Premendo il bottone l'accensione dovrà seguire una sequenza predefinita a tua scelta;
- Memory: collega 5 led e 5 bottoni e realizza un gioco di abilità dove ti viene mostrata una sequenza di accensioni via via più complesse: l'obiettivo è ripeterle correttamente premendo i bottoni corrispondenti;
Pulsanti temporizzati
Può essere utile assegnare ad un singolo bottone più
funzioni, discriminando il tempo di pressione. Per far questo
si ricorre alla funzione millis()
, che restituisce
il tempo da quando il programma è stato avviato, in millisecondi.
Siccome questo è un valore che può essere molto grande, deve
essere memorizzato in variabili adatte a contenerlo, in particolare
si usa una unsigned long int
, che consente
di memorizzare un tempo fino a circa 50 giorni.
L'obiettivo del listato è accendere il primo led se si clicca
sul pulsante, il secondo se si preme per un secondo, il terzo
se si preme per due, infine spegnere tutto se si preme più
a lungo.
La struttura del listato riprende l'esercizio "Luci passo passo".
Il segnale analogico

I pin Analog
di Arduino sono provvisti di una
circuiteria hardware supplementare, detta convertitore
Analogico-Digitale (ADC) che consente di decodificare un segnale
di tensione compresa fra 0~5 Volt in un valore intero leggibile da
microcontrollore.
Questo ADC ha una risoluzione di 10bit, questo significa che i valori letti da programma saranno compresi fra 0 e 1023, e che ogni singola unità corrisponde ad una variazione di tensione di circa 5mV (5V/1024).
Possiamo suddividere i sensori analogici in due categorie, che hanno
un diverso approccio circuitale: le resistenze variabili e
sensori integrati.
Come suggerisce il nome, le resistenze variabili sono componenti
con la proprietà di variare la resistenza ai propri capi in funzione
delle variazioni esterne. I più comuni sono:
- Potenziometro: sensore costituito da una striscia di materiale resistivo, collegata agli estremi a due morsetti. Sulla striscia è poggiato un contatto mobile, connesso ad un terzo morsetto. Si tratta quindi di una resistenza regolabile manualmente;
- Fotoresistenza: componente che varia resistenza con la luminosità, in particolare passa da qualche centinaia di megaOhm al buio a pochi kiloOhm se molto illuminata;
- Termistore: sensore legato alla temperatura, e in base al materiale con cui è realizzato risponde innalzamenti di temperatura con l'aumento di resistenza (PTC, Positive Temperature Coefficent) o la diminuzione (NTC, Negative Temperature Coefficent);
Abbiamo detto che Arduino va a misurare differenze di potenziale: vedremo che i precedenti sensori dovranno essere combinati con una resistenza fissa per poterne leggere le variazioni. Al contrario, i sensori integrati sono già provvisti di una circuiteria specifica che, una volta alimentata dagli appositi pin, restituisce un segnale di tensione variabile sul morsetto di uscita. Alcuni sensori di temperatura (TMP36) ed accelerometri (ADXL3xx) sono così realizzati.


Vediamo quindi come collegare dei sensori resistivi ad Arduino.
Il circuito da costruire viene detto partitore di tensione,
è composto da due resistenze in serie ai cui capi è
presente una differenza di potenziale fissata: nel punto di giunzione
è sempre presente una tensione intermedia, che varia in funzione
delle resistenze.
Il potenziometro è già un partitore di tensione, per cui se si
collegano i morsetti laterali all'alimentazione, sul centrale
abbiamo una tensione dipendente dalla posizione della manopola
La fotoresistenza va invece messa in serie ad una resistenza fissa,
che abbia un valore più o meno intermedio al range coperto dal sensore,
ovvero circa 10kOhm. Osservando il circuito sottostante,
analizziamo cosa succede nei due casi limite:
- Al buio la resistenza è massima, molto più grande dei 10kOhm: il partitore di tensione è quindi sbilanciato verso la minore resistenza, e la tensione letta è vicina agli 0V;
- Se illuminata la resistenza è minima, molto inferiore a quella fissata, e lo sbilanciamento questa volta è verso i 5V;
Con il seguente listato andiamo a leggere i valori di tensione
sui pin analog0
e analog1
,
per poi inviarli al computer via USB: puoi leggerli cliccando su
dall'IDE Arduino.


const byte PIN_POTENZIOMETRO = A0; // Pin del potenziometro const byte PIN_FOTORESISTENZA = A1; // Pin della fotoresistenza int valoreSensore = 0; // Valriabile con il valore letto void setup() { Serial.begin(9600); // Avvia la comunicazione } // seriale a 9600 baud void loop() { //Legge il valore del sensore, e lo stampa valoreSensore = analogRead(PIN_POTENZIOMETRO); Serial.print("potenziometro = "); Serial.println(valoreSensore); valoreSensore = analogRead(PIN_FOTORESISTENZA); Serial.print("fotoresistenza = "); Serial.println(valoreSensore); delay(1000); // 1 secondo di pausa per poter } // leggere i valori
La funzione chiave è analogWrite(pin analogico)
,
che restituisce il valore compreso fra 0 e 1023, proporzionale
alla tensione letta sul pin analogico specificato. C'è da notare
che il pin non deve essere indicato come input
nel
setup, poiché la circuiteria dell'ADC è gestita in
automatico quando si effettua la lettura.
Bisogna fare un cenno alle funzioni Serial
, che
riguardano la comunicazione con il computer:
Serial.begin(velocità)
apre la comunicazione seriale alla velocità specificata (solitamente 9600 baud). Siccome i pinDigital 0
eDigital 1
assolvono anche a questa funzionalità, bisogna evitare di usarli per altro se si intende usare la comunicazione seriale;Serial.print(dati)
invia variabili o testo via seriale; lo stesso perprintln
che aggiunge anche un ritorno a capo. Nota bene: il testo (anche detto stringa, deve essere racchiuso fra doppi apici);
Una trattazione maggiore sarà fatta più avanti, insieme ad altri metodi di comunicazione.
Generazione di numeri casuali
Parlando del bottone si è fatto riferimento ad eventuali interferenze
ambientali da evitare; non sempre queste sono un fenomeno indesiderato,
ma possono essere sfruttate per la generazione di valori casuali:
con la funzione random([minimo,] massimo)
che restituisce un valore compreso fra minimo e massimo (se non
si specifica un valore minimo, questo è sottointeso come zero).
La generazione trae il suo fattore di casualità effettuando letture
da un pin analogico scollegato, e quindi sottoposto a rumore
ambientale. Questo deve essere sempre specificato nella
setup attraverso la funzione randomSeed(pin analogico)
.
Trovi qui un semplice esempio, che non richiede alcun tipo di circuito.
void setup() { // Usa Analog 0 come pin per la lettura randomSeed(analogRead(A0)); // Uso la comunicazione seriale Serial.begin(9600); } void loop() { byte casuale; // un numero casuale da 1 a 29 casuale = random(1, 30); Serial.println(casuale); delay(500); }
Esercizi
- Termostato: realizza un sistema che accenda un led se l'ambiente supera una determinata temperatura, usando la termoresistenza;
- Crepuscolare: usando la fotoresistenza, accendi un led se è troppo buio. Tieni conto che il sensore potrebbe percepire momentanei oscuramenti accidentali;
- Termostato regolabile: aggiungi un potenziometro al tuo termostato per regolare la soglia di intervento;
