Il sensore
Il sensore ha l’aspetto di un classico transistor (package TO-92), esteriormente è sovrapponibile ad un DS18B20 e come quest’ultimo presenta 3 soli pin: VCC, uscita analogica e GND. Con Arduino UNO non dobbiamo far altro che alimentare il sensore con la linea a 5V, collegare la terra ed il pin analogico in uno degli ingressi analogici di Arduino. Già perché questo sensore a differenza del DS18B20 e il DHT11 non è digitale per cui non bisogna instaurare nessun tipo di comunicazione digitale. E’ sufficiente leggere l’uscita analogica per ricavare la temperatura. Semplice no? Talmente semplice da chiederci perché esistano sensori più complessi come quelli visti in precedenza. Capirlo in realtà è facile, basta che analizziamo il funzionamento del sensore. Esso ci restituisce un valore analogico che varia di 10mV per ogni grado Celsius per cui leggendo il voltaggio possiamo ricavare la temperatura. Se però usiamo un cavo di collegamento molto lungo, questo fornisce una resistenza al passaggio della corrente per cui la tensione letta da Arduino in parte è alterata dalla resistenza del cavo il che determina un errore di lettura. Certo possiamo pensare a una routine di calibrazione ma le cose si fanno più complesse per cui se l’esigenza è quella di porre un sensore molto lontano da Arduino la scelta dovrebbe ricadere su un sensore digitale. Un altro limite è dato dal fatto che per ogni sensore dobbiamo occupare un nuovo ingresso analogico, è impensabile usare questi sensori ad esempio per monitorare 20 valori di temperatura in contemporanea, cosa agilmente fattibile con i DS18B20. Inoltre come vedremo ci sono piccoli grandi problemi che riducono la precisione di lettura del sensore, tutti fattori che vengono eliminati alla fonte con i sensori digitali.
Collegamenti e calcoli
Il collegamento con Arduino UNO lo potete vedere nella figura qui accanto, ma come dicevamo è estremamente semplice. E’ sufficiente collegare VCC, GND ai rispettivi pin di Arduino e l’uscita ad uno degli ingressi analogici, io ho scelto lo zero solo perché era il più vicino. Diciamo subito che anche se troverete questo tipo di configurazione nel 90% dei tutorial “copia e incolla” che trovate in rete, in questo modo non sarete in grado di sfruttare appieno le capacità di questo sensore. Intanto l’accuratezza scende a mezzo grado a temperatura ambiente e un grado agli estremi, inoltre lo stesso range di temperatura misurabili cambia, infatti sarete in grado di misurare temperature da 2 a 150 gradi. Vediamo di fare due calcoli:
Arduino UNO permette di campionare segnali analogici a 10 bit, ossia 1024 possibili valori. Se l’ingresso va da 0 a 5V significa che abbiamo 5/1023=0.0048875 ossia Arduino UNO riesce a misurare tensioni a passi di circa 5mV (4.88). Dato che l’LM35 fornisce una variazione di 10mV/C diventa evidente che Arduino avrà una precisione di lettura di circa mezzo grado (5/10=0.5), indipendentemente da quella che è la reale precisione del sensore. Se il sensore fornisce 10mV a grado e la temperatura massima è di 150°C significa che il sensore produrrà in uscita una tensione da 0 a 1.5V. Dalla proporzione 1.5:x=5:1024 otteniamo circa 307 il che significa che il nostro Arduino andrà a leggere valori compresi fra 0 e 307 per cui i restanti 716, per raggiungere i 1024, saranno del tutto inutilizzati cosa che riduce ovviamente la precisione della misura.
Ora vediamo come convertire la lettura in temperatura. Facciamo finta che Arduino in un determinato momento legge un segnale analogico pari a 43. Sappiamo che ogni unità letta corrisponde a 4.88mV per cui 43×4.88 fanno 210mV. Se il sensore fornisce 10mV/C otteniamo 21 gradi (210/10), di fatto è sufficiente moltiplicare il valore della lettura per 0.48875. Partendo da questo presupposto lo sketch necessario a leggere la temperatura è quasi banale:
#define potPin A0 void setup() { Serial.begin(9600); } void loop () { int aRead = 0; aRead = analogRead(potPin); Serial.print("Analog = "); Serial.print(aRead); float tempC = aRead * 0.48875; Serial.print(" Temp = "); Serial.println(tempC); delay(1000); }
Come vedete il listato non fa altro che leggere l’ingresso analogico e stamparne il valore sulla porta seriale, sia come dato grezzo che come conversione in
AREF
Visto che il tipo di sensore in mio possesso non mi permette ulteriori esperimenti, ho pensato di illustrarvi alcuni spunti sulla misurazione dei segnali analogici. Sinora vi ho sempre raccontato che Arduino UNO può leggere segnali analogici compresi fra 0 e 5V. Beh, non è del tutto vero, legge segnali analogici fra 0 e una soglia di riferimento. Questa soglia di base è impostata a 5V, ma la cosa interessante è che è modificabile. Per farlo si utilizza la funzione analogReference e, se non altrimenti specificato, è sottintesa la funzione analogReference(DEFAULT) all’avvio di Arduino, infatti questa funzione pone il riferimento a 5V, cosa che avviene non tanto all’accensione di Arduino, quanto alla prima lettura su un pin analogico o digitale. Attenzione che se intendete usare questa funzione, essa deve essere usata PRIMA della analogRead(). Con Arduino UNO (schede diverse hanno parametri diversi!) possono essere passati altri due valori a questa funzione, il primo è INTERNAL. Usando la funzione analogReference(INTERNAL) il riferimento viene impostato a 1.1V perciò da quel punto Arduino dividerà in 1024 parti gli 1.1V ottenendo una risoluzione di 0,00107421875V, ossia 1,07mV, notevolmente meglio dei quasi 5mV che otteniamo di base. Attenzione però che una volta impostata questa funzionalità dovrà essere assolutamente evitato di portare sugli ingressi analogici un voltaggio superiore a 1.1V pena la possibilità di danneggiare irreparabilmente Arduino. Nell’articolo odierno avremmo potuto usare anche questo trucco, infatti gli 1.1V corrisponderebbero a 110°C per cui se non vi fosse la necessità di leggere temperature superiori si sarebbe potuto ottenere un miglioramento della precisione di lettura. Ovviamente il listato necessita di alcune piccole modifiche:
void setup() { Serial.begin(9600); analogReference(INTERNAL); } void loop () { int aRead = 0; float ref=1.1; aRead = analogRead(A0); Serial.print("Analog = "); Serial.print(aRead); float tempC = aRead * ref/1023*100; float volt = aRead*ref/1023; Serial.print(" V = "); Serial.print(volt); Serial.print(" - Temp = "); Serial.println(tempC); delay(1000); }
Questo trucchetto può essere usato tutte le volte in cui abbiamo la certezza di non superare gli 1.1V in ingresso al fine di migliorare la risoluzione della misura, il tutto
Una cosa molto importante da sapere è che il resistore da 32K viene “attivato” solamente al momento in cui utilizziamo la funzione analogReference(EXTERNAL), in caso contrario alla prima lettura di un valore analogico o digitale, di default verrà “creato” un collegamento diretto a massa, ciò significa che se applichiamo un carico al pin AREF non ci sarà nulla a limitare la corrente con conseguente frittura dell’ATMega di Arduino. Per questo motivo se volete usare il pin AREF per settare una tensione di riferimento, è obbligatorio usare un resistore che limiti la corrente e il cui valore sia settato correttamente per ottenere il voltaggio voluto attraverso il partitore di tensione che si viene a formare. Potreste pensare “beh, sto molto attento, scrivo bene il codice affinché venga impostata analogReference(EXTERNAL) per avere la protezione del resistore interno, discorso corretto, ma basta una piccola svista sul versante software per fare un piccolo disastro per cui non posso che invitarvi caldamente ad inserire sempre un resistore sul pin AREF nel caso vogliate utilizzarlo per impostare una precisa tensione di riferimento. Se volete usare un partitore esterno anziché il singolo resistore, potete usare la mia app impostando a 32K il valore di RL andando poi a settare i valori R1 ed R2 del partitore; in questo caso il voltaggio ottenuto sarà dato da V2L. Potete anche partire dal voltaggio e far calcolare alla mia App il valore di R1. Una domanda cruciale è quale sia il valore minimo del resistore esterno. Non ho trovato un dato certo nel datasheet dell’ATMega328p, forse anche perché sono 650 pagine e potrebbe essermi sfuggito, ma pare, da tutta la documentazione che ho letto, che il valore minimo del resistore sia di 5K il che permette di ottenere una tensione di 4.32V. Aumentando la resistenza del resistore si riduce il valore di tensione per cui possiamo dire che tramite l’utilizzo del pin AREF posso modificare la tensione di riferimento da 4.32 a 1.1V.
Considerazioni finali
Abbiamo visto che tutto sommato è abbastanza semplice collegare questo sensore ad Arduino, ma ci sono tutta una serie di piccole imprecisioni ed insidie dietro l’angolo. Diciamo che se dovete usare un singolo sensore, vicino ad Arduino, misurare temperature non inferiori a 2 gradi e vi accontentate di un piccolo margine d’errore, allora questo sensore può fare al caso vostro. In caso contrario è preferibile l’uso di un sensore digitale, è vero che questo è estremamente più difficile da pilotare, ma ci sono le librerie già pronte all’uso per cui la differenza per che non è un esperto è davvero minima. Un altro caso che mi viene in mente poter far pendere la bilancia verso il sensore analogico, è quello in cui abbiamo uno sketch particolarmente complesso che non ci lascia spazio per le librerie che controllano i sensori digitali, in tal caso una semplice lettura analogica può fare al caso nostro. Per finire ho fatto un piccolo test comparativo fra l’LM35 ed il DS18B20. Ho lasciato “acclimatare” i sensori per una quindicina di minuti e poi ho guardato i valori letti: il DS18B20 mi segna 19.0°C mentre l’LM35 19.8 circa, con una differenza perciò di circa 8 decimi di grado. Paradossalmente se invece di usare il riferimento di 1.1V uso i 5V ottengo 19.55, con una misura persino più stabile nel tempo e una differenza dal DS18B20 di circa 4.5 decimi (anche se lo scatto successivo è stato a 20.04 quando il DS18B20 era a 19.2 con uno scarto di 8 decimi). Ovviamente senza uno strumento di misura di precisione non ho la possibilità di dire dove stia la verità, ma il mio personale parere è che questi LM35 non siano poi così precisi.