Articolo riservato agli utenti registrati
Entriamo nel mondo della conversione analogico-digitale di Arduino, scoprendo il funzionamento dei pin coinvolti e come usarli per le acquisizioni.
Il convertitore analogico/digitale, meglio noto come ADC (acronimo di Analog-Digital Converter), è un dispositivo elettronico in grado di convertire segnali variabili analogici o tensioni continue in un codice binario, tramite la cosiddetta “quantizzazione”.
Nell’ADC di Arduino un segnale analogico variabile tra 0 e 5 V viene tradotto in un codice a 10 bit, cioè 210 = 1024 combinazioni, numerate da 0 a 1023.
A tale riguardo, va detto che quando calcoliamo la “risoluzione”, cioè il valore minimo della nostra scala di 10 bit, lo facciamo dividendo la tensione per i 1024 valori del codice a 10 bit; al momento di calcolare il “range”, quindi l’intera gamma di misura del convertitore, dobbiamo tener presente che i 1024 punti contengono anche lo 0, quindi vanno da 0 a 1023.
Ciò significa che. Partendo per esempio da un’alimentazione di 5 V, la risoluzione sarà di 5V/1024, ovvero 0,004883 V, mentre il range andrà da 0 V a 0,004883 x 1023, ossia 4,995 V. Questo implica che il valore iniziale di 5 V è in “over-range”, vale a dire fuori scala.
Bisogna comunque tener presente che, se anche in questi primi esempi usiamo svariate cifre decimali, nella realtà la precisione del sistema software di Arduino non permette di usarne correttamente più di due, quindi nel prosieguo arrotonderemo i risultati sempre alla seconda cifra decimale; perciò, ad esempio, il valore 0,004883 V lo tratteremo come 4,88 mV, altrimenti sarebbe matematicamente ingestibile.
Molti utenti di Arduino, al momento di utilizzare segnali di tipo analogico, specialmente quando essi hanno ampiezze maggiori o comunque differenti dalla tensione standard di 5 V, incontrano serie difficoltà nell’interfacciamento.
Più di qualcuno, inevitabilmente, danneggia il microcontrollore ATmega328P perché applica ai suoi pin segnali di ampiezza maggiore di quella della tensione di alimentazione, che è di 5 V.
Per tali ragioni abbiamo deciso di sviscerare questo argomento, arricchendo la spiegazione dell’uso dell’ADC e dell’ARef di Arduino con la realizzazione pratica di un partitore resistivo, fisso o variabile, mediante formule semplici ma precise; accenneremo inoltre ad alcuni sensori analogici, illustrandone una tipica applicazione.
I sei pin di Arduino collegati all’ADC interno sono chiamati A0÷A5 e corrispondono ai pin fisici 23÷28 dell’ATmega328P.
Diciamo subito che molti neofiti commettono l’errore di pensare che questi pin operino in modo bidirezionale, trasformandosi all’occorrenza in uscite DAC, quindi in altrettanti convertitori digitale-analogico: ciò non è assolutamente vero!
Questi pin sono dei comuni pin digitali I/O (per questa funzionalità sono usati con la numerazione 14÷19), quindi sia in ingresso (comando digitalRead) che in uscita (comando digitalWrite), ma possono svolgere funzione di ingresso ADC quando sono usati in abbinamento al comando analogRead.
Questo significa, in pratica, che mediante un MOSFET interno al microcontrollore tali pin vengono portati all’ingresso dell’A/D converter.
Arduino dispone poi di ulteriori sei pin digitali (3, 5, 6, 9, 10, e 11 che corrispondono ai pin fisici: 5, 11, 12, 15, 16 e 17) che, all’occorrenza, possono svolgere il ruolo di generatori PWM (Pulse Width Modulation) mediante il comando analogWrite. La Fig. 1 illustra i pin che riguardano l’ADC.
Fig. 1 I pin analogici di Arduino sono siglati ANALOG IN. Nella Arduino Uno Rev. 3 i quattro contatti superiori del connettore a 10 vie (a destra della board) portano le linee GND, ARef e il bus I²C di Arduino.
In questo lavoro concentreremo la nostra attenzione solo sulla funzionalità ADC.
Nel paragrafo Successive Approximation Register ADC trovate un approfondimento sulla tipologia di ADC utilizzata dai microcontrollori AVR dell’Atmel, che è quella che ottiene il valore per approssimazione successiva (esistono anche altri tipi di A/D, ma non riguardano questo tutorial).
Ribadiamo che non sempre una fonte analogica genera tensioni variabili nello stesso range di alimentazione di Arduino, anzi, a volte abbiamo a che fare con tensioni maggiori (ad esempio quelle fornite da sensori che operano a 12V) ed altre possono essere inferiori (per esempio alcuni integrati amplificatori delle termocoppie di tipo K generano tensioni di circa 1 V a 100°C).
Nel primo caso si rischia di danneggiare il microcontrollore, mentre nel secondo si ha una bassa risoluzione (che implica misure imprecise) e una scarsa dinamica (che espone ai disturbi).
ARef e analogReference()
Per adattare il range di misura, Arduino rende disponibile un pin chiamato ARef (corrispondente al pin fisico 21 dell’ATmega328P) e di un comando software analogReference(); vediamo a cosa servono e come si usano. ARef è la tensione di riferimento usata dall’ADC per impostare la scala di misura, ovvero il valore in tensione corrispondente al valore 1024. Il comando analogReference() prevede i tre parametri descritti di seguito.
DEFAULT
È il riferimento di tensione per il fondo scala è quello di alimentazione di Arduino, quindi 5 V.
Se consideriamo le versioni di Arduino a 3,3 V o anche un possibile uso in stand-alone dell’ATmega328, chiaramente il parametro DEFAULT assume questo nuovo valore di tensione.
Con il comando analogReference(DEFAULT) sul pin ARef ci si trova lo stesso valore della tensione di alimentazione, e tale tensione potrebbe essere usata appunto come riferimento per le misure analogiche, a patto che siano sufficienti i circa 30 mA erogabili da questo pin.
Questo parametro si usa in genere per misurazioni in cui non sia richiesta una precisione elevata, proprio in quanto strettamente legato al valore dell’alimentazione che, se non perfettamente stabile e precisa, potrebbe dare origine a risultati indesiderati.
In pratica, lasciando il valore DEFAULT, con una tensione di alimentazione di 5 V esatti, un segnale di 2,5 V darebbe un valore pari a 1024/5V x 2,5V=512; se successivamente la tensione scendesse a 4,9 V lo stesso segnale di 2,5 V darebbe un valore di lettura di 1024/4,9 V x 2,5 V= 522.
Usando il parametro DEFAULT la risoluzione di lettura è:
Risoluzione = VRiferimento / 1024
in cui Risoluzione rappresenta il valore in millivolt (mV) di ognuno dei 1023 punti decimali restituiti dal microcontrollore dopo la lettura di una tensione analogica; VRiferimento invece è la tensione di riferimento fornita all’ADC di Arduino che, in questo caso, corrisponde alla tensione di alimentazione di Arduino (5 V o 3,3 V).
Nel caso dell’alimentazione a 5 V abbiamo: 5 V/1024 = 0,004883 V, cioè ogni punto della scala 1-1023 corrisponde a 4,88 mV (lo 0 ovviamente vale 0 V). Nella configurazione da noi usata per preparare gli sketch di prova abbiamo misurato una VRiferimento di 5,14 V.
Come detto, tale valore è facilmente misurabile sul pin ARef di Arduino e, una volta noto, lo si può assegnare ad una costante predisposta nello sketch, in modo da migliorare la precisione delle misure.
INTERNAL
In questo caso il riferimento di tensione per il fondo scala è fisso a 1,1 V a prescindere dalla tensione di alimentazione.
Il comando analogReference(INTERNAL) si usa in genere quando il valore massimo della tensione analogica è prossimo a 1 V oppure quando si vogliono evitare le possibili influenze delle variazioni della tensione di alimentazione di Arduino sui valori di lettura (immaginiamo un’alimentazione a batteria).
In questo caso la risoluzione diventa 1,1V/1024=0,0011V, cioè ogni punto della scala 1-1023 corrisponde a 1,1 mV. Anche in questo caso il pin ARef riporta tale valore di tensione, utilizzabile come riferimento, e questo dà l’indubbio vantaggio di non dover ricorrere a tensioni esterne (tipicamente circuiti integrati stabilizzati a tensione fissa).
C’è da sottolineare che il datasheet dell’ATMEL ATmega328P consiglia decisamente di collegare un condensatore di disaccoppiamento (ideale è un 100 nF multistrato) tra il pin ARef e GND, in modo da rendere questa tensione ancor più stabile e immune ai disturbi (l’argomento sarà approfondito nel paragrafo successivo); notate che i modelli Arduino MEGA hanno due diverse opzioni per l’INTERNAL, i comandi sono:
– analogReference(INTERNAL1V1) per il riferimento interno di 1,1 V, che si comporta esattamente come il comando appena visto;
– analogReference(INTERNAL2V56) per il riferimento interno di 2,56 V, in questo caso la risoluzione diventa 2,56V/1024=0,0025V, cioè ogni punto della scala 1÷1023 corrisponde a 2,5 mV;
Bisogna fare molta attenzione, quando si attiva il riferimento INTERNAL, che al pin Aref no sia collegata alcuna fonte di alimentazione, in quanto le due tensioni andrebbero in cortocircuito tra loro, provocando danni all’ADC.
EXTERNAL
Con il comando analogReference(EXTERNAL) il pin ARef diventa un ingresso, in quanto ad esso si va ad applicare una tensione esterna che diventa il riferimento di fondo scala.
Il Reference di Arduino correttamente avvisa che non bisogna applicare al pin ARef tensioni negative o maggiori di 5 V, altrimenti è molto probabile il danneggiamento del microcontrollore!
Questa opzione vi permette di definire un range estremamente preciso, che potrebbe essere anche il canonico 0÷5 V, solo che in questo caso si usa una tensione di riferimento molto stabile e quindi anche le misure saranno più affidabili.
Esistono poi degli specifici integrati regolatori, stabilissimi, in grado di fornire delle tensioni fisse, da usare proprio in casi come questi. Applicando quindi una tensione stabile al pin ARef, questa diventa automaticamente il nuovo fondo scala dell’ADC di Arduino.
Supponendo di applicare ad ARef una tensione stabile di 2,7 V (VRiferimento), si avrà di conseguenza Risoluzione = 2,7V/1024=0,002636V, cioè ogni punto della scala 1-1023 corrisponde a 2,64 mV.
Anche in questo caso, anzi a maggior ragione, è consigliabile l’adozione di un condensatore da 100 nF, tra il pin ARef e GND.
Vediamo ora cosa succede alle letture di segnali analogici quando il loro range combacia esattamente con il riferimento dell’ADC; in altre parole supponiamo di dover misurare un segnale analogico che abbia un’escursione tra 0 V e ARef (secondo i vari parametri).
La formula che ci permette di calcolare il valore decimale per una certa tensione misurata, rispetto a quella di riferimento è:
LetturaDecimale = 1024/VRiferimento x VAnalogica
Come già spiegato, l’eventuale coincidenza tra VRiferimento e VAnalogica darebbe origine ad un over-range (1024).
Da tale formula possiamo ricavare la formula inversa, utilissima quando ci troveremo di fronte a un valore letto da Arduino, per risalire alla tensione applicata all’ingresso analogico:
VAnalogica = LetturaDecimale/1024 x VRiferimento
oppure (ricordando che Risoluzione vale VRiferimento/1024):
VAnalogica = LetturaDecimale * Risoluzione
Esempi di misurazione ADC
Vediamo ora alcuni esempi di misurazione dei segnali analogici, considerando Arduino alimentato a 5 V e i diversi parametri di ARef.
1°: Alimentazione 5 V, Riferimento DEFAULT
Ricorrendo alle formule appena viste, se applichiamo al pin analogico una tensione di 1 V avremo una lettura di: 1024/5Vx1V=204,8, ottenuta come LetturaDecimale=1024/VRiferimento x VAnalogica; il valore è sempre arrotondato all’intero più vicino, che in questo caso è 205.
Se applichiamo una tensione di 3,8 V avremo invece 1024/5 V x 3,8 V = 778.
Se Arduino legge un valore di 615 significa che sull’ingresso analogico c’è una tensione di 615/1024 x 5 V = 3,00 V (ossia VAnalogica=LetturaDecimale/1024 x VRiferimento).
Lo stesso risultato si ottiene anche con la formula alternativa 615 x 0,004883 V = 3,00 V (VAnalogica = LetturaDecimale x Risoluzione).
2°: Alimentazione 5 V, Riferimento INTERNAL
In questo caso l’alimentazione non ci interessa, in quanto il riferimento, come abbiamo visto prima, è fisso a 1,1 V; è ovvio che possiamo applicare all’ingresso analogico solo tensioni comprese tra 0 e 1,1 V.
Se applichiamo una tensione di 0,25 V avremo 1024/1,1V x 0,25 V = 233.
Se applichiamo una tensione di 0,26 V avremo invece 1024/1,1 V x 0,26 V = 242.
Notate come la differenza di soli 10 mV sposti la lettura di ben 9 punti, infatti la risoluzione è poco più di 1mV (1,1V / 1024 = 0,0011V).
Se Arduino legge un valore di 615 significa che sull’ingresso analogico in questione è presente una tensione di 615/1024 x 1,1V = 0,66 V.
Quest’ultimo esempio fa ben comprendere come uno stesso valore decimale fornito da Arduino in fase di lettura non significhi assolutamente lo stesso valore di tensione applicato al pin analogico, ma tutto è legato alla tensione di riferimento.
3°: Alimentazione 5 V, Riferimento EXTERNAL a 3,3 V
Anche in questo caso siamo svincolati dal valore dell’alimentazione di Arduino (salvo i casi della famiglia “mini”, in quanto in tal caso il fondo scala è fissato dai 3,3 V che, evidentemente, stiamo fornendo al microcontrollore tramite il pin ARef. Anche in questo caso è il riferimento che stabilisce qual è il valore massimo di tensione applicabile al pin analogico di Arduino, cioè 3,3 V.
Se applichiamo una tensione di 0,25 V avremo 1024 / 3,3 V * 0,25 V = 78.
Se applichiamo una tensione di 0,26 V avremo 1024 / 3,3 V * 0,26 V = 81.
In questo caso possiamo vedere come la risoluzione sia notevolmente diminuita in termini di precisione: infatti ora è di circa 3,3V/1024 = 0,0032 V cioè 3,2 mV; infatti solo 3 punti/lettura separano 0,25 V da 0,26 V.
Se Arduino legge un valore di 615 significa che sull’ingresso analogico c’è una tensione di 615 / 1024 * 3,3 V = 1,98 V.
Gli ultimi esempi che abbiamo proposto sono stati utili per fare un po’ di prove con le formule viste in precedenza e familiarizzare con i concetti loro correlati, ma anche per comprendere quanto sia importante il valore di riferimento dell’ADC, ai fini di una maggiore o minore precisione di lettura.
Quindi se vogliamo ottenere la massima precisione possibile dobbiamo usare una tensione di riferimento uguale o leggermente superiore al massimo valore analogico da leggere.
Naturalmente non sempre tale precisione è richiesta, magari proprio a causa di una elevata tolleranza di lettura del sensore, quindi la cosa va valutata di volta in volta a seconda dell’applicazione.
La conversione analogico/digitale
Un segnale di tipo analogico è caratterizzato da una sequenza di valori con andamento continuo, ossia è virtualmente formato da infiniti punti consecutivi; questo genere di segnale può essere letto ed analizzato direttamente da strumenti di tipo analogico che, in genere, non garantiscono grande precisione nella lettura.
Pensiamo alla misura di una tensione in continua variabile, letta da un voltmetro a lancetta; per quanto grande e stabile sia lo strumento è praticamente impossibile ricavarne un valore preciso, visto che la lettura viene effettuata confrontando la posizione della lancetta rispetto allo sfondo graduato.
Un segnale digitale è invece costituito da una sequenza di valori discreti, che possono essere letti da strumenti di misura digitali, i quali ne mostrano il valore direttamente in forma numerica. Il vantaggio di tali strumenti è che è possibile aumentare il numero di cifre (risoluzione) fino ad ottenere misurazioni estremamente precise.
I circuiti integrati digitali non sono però in grado di leggere ed interpretare segnali di tipo analogico, proprio a causa delle differenti nature del segnale analogico e di quello digitale.
Quindi un segnale analogico, per poter essere letto da un circuito digitale, necessita di una conversione (Fig. A), detta conversione analogico-digitale, che permette di trasformare una serie infinita di punti in una serie finita di valori discreti, rappresentabili numericamente.
Fig. A Conversione analogico-digitale.
Tale processo, definito PCM (Pulse Code Modulation) avviene in tre fasi successive:
• Campionamento: è la trasformazione di un segnale analogico in una sequenza di segnali impulsivi, di ampiezza uguale al valore del segnale originario, mediante letture ad istanti di tempo determinati e regolari;
• Quantizzazione: è l’assegnazione di un valore numerico (livello di quantizzazione) ad ogni valore campionato;
• Codifica: è l’associazione di un numero finito di cifre ad ogni livello di quantizzazione; di solito si ricorre alla codifica binaria.
Proviamo a farvi comprendere questa tecnica con un semplice esempio: abbiamo una tensione continuamente variabile in un range tra 0 e 5V e dobbiamo trasformarla in un segnale digitale, in modo da poterla poi rappresentare sotto forma di numeri.
Effettuiamo il campionamento con dieci letture ad intervalli di tempo regolari ed otteniamo i seguenti valori:
1,3V – 2,6V – 0,7V – 1,8V – 4,4V – 2,2V – 3,9V – 2,5V – 3,3V – 4,7V (vedere Fig. B).
Fig. B Campionamento di un segnale analogico.
Ora quantizziamo questi valori approssimandoli ad un numero finito di livelli: 1V, 2V, 3V, 4V.
In base a tale suddivisione, i valori tra 0 e 1 diventeranno tutti 1, i valori tra 1,1 e 2 diventeranno tutti 2, i valori tra 2,1 e 3 diventeranno tutti 3, i valori >3 diventeranno tutti 4.
Il risultato dell’operazione di quantizzazione sarà la trasformazione di ognuno dei dieci valori campionati in uno dei valori di livello (quello maggiore più vicino), quindi:
2V – 3V – 1V – 2V – 4V – 3V – 4V – 3V – 4V – 4V. (vedere la Fig. C).
Fig. C Quantizzazione di un segnale campionamento.
A questo punto codifichiamo tali valori, mediante la trasformazione in codice binario; sappiamo che quattro livelli di tensione o comunque quattro valori sono rappresentabili con due bit, che nel nostro caso rappresentano la risoluzione dello schema di conversione che stiamo applicando. Da ciò deriva che otteniamo: 00 = 1V – 01 = 2V – 10 = 3V – 11 = 4V.
Così i nostri dieci valori analogici iniziali diventano altrettanti valori digitali espressi nel formato binario a due cifre, che sono 01 – 10 – 00 – 01 – 11 – 10 – 11 – 10 – 11 – 11. (riferitevi alla Fig. D).
A questo punto il concetto dovrebbe risultare sufficientemente chiaro.
Fig. D Codifica digitale del segnale analogico.
Successive Approximation Register ADC
L’ADC utilizzato dai microcontrollori AVR è del tipo SAR (acronimo di Successive Approximation Register, cioè Registro ad Approssimazioni Successive). Dal nome è facile intuire che questo tipo di ADC arriva al risultato tramite una serie di approssimazioni.
La figura mostra lo schema a blocchi generico di un ADC di tipo SAR che, come si vede, è costituito da un comparatore analogico al quale viene applicata la tensione campionata dal sistema di Sample and Hold (S/H) e una tensione di riferimento generata tramite un DAC (Digital Analog Converter) che a sua volta è controllato dal registro SAR.
Il funzionamento è piuttosto semplice, si parte settando il DAC per generare una tensione pari a 1/2 ARef (è a questa unità che fa capo il relativo pin, qui chiamato VRef), mediante l’impostazione del bit più significativo del registro SAR a 1: nel caso di un ADC a 10 bit è il decimo bit che ha peso 512; se la tensione del DAC risulta minore di quella in ingresso (il valore da misurare), proveniente dall’S/H, questo bit viene lasciato a 1 in caso contrario si riporta a 0, dopo di che si porta a 1 il nono bit, peso 256, e si ripete il paragone con la stessa logica di prima, ovvero se la tensione totale in uscita dal DAC è minore di quella del S/H il bit rimane a 1 altrimenti si riporta a 0.
Si ripete il procedimento con la stessa logica per tutti i bit del DAC, nel caso dell’ATmega328P in totale sono 10, e alla fine il registro SAR contiene il valore digitale della nostra tensione analogica. Vediamo un esempio pratico ipotizzando che la tensione da misurare sia di 2,815V e che la tensione su ARef sia di 5V esatti, quindi ogni step del DAC vale:
5/1024 = 4,883 mV.
Seguono dieci passaggi:
1. Il bit 10 del SAR viene settato a 1, al DAC arriva il valore binario 0b1000000000 che vale 512 pertanto la tensione in uscita dal DAC è 4,883*512 = 2,500V, il comparatore dice che la tensione sul S/H è maggiore di quella del DAC pertanto il bit 10 del SAR resta su 1 logico;
2. Il bit 9 del SAR viene settato a 1, al DAC arriva il valore binario 0b1100000000 che vale 768, la tensione in uscita è 4,883*768 = 3,750V, il comparatore dice che la tensione sul S/H è minore di quella del DAC pertanto il bit 9 del SAR viene riportato a 0 logico.
3. Il bit 8 del SAR viene settato a 1, al DAC arriva il valore binario 0b1010000000 che vale 640, la tensione in uscita è 4,883*640 = 3,125V, il comparatore dice che la tensione sul S/H è minore di quella del DAC pertanto il bit 8 del SAR viene riportato a 0 logico.
4. Il bit 7 del SAR viene settato a 1, al DAC arriva il valore binario 0b1001000000 che vale 576, la tensione in uscita è 4,883*576 = 2,812V, il comparatore dice che la tensione sul S/H è maggiore di quella del DAC pertanto il bit 7 del SAR viene lasciato a 1 logico.
5. Il bit 6 del SAR viene settato a 1, al DAC arriva il valore binario 0b1001100000 che vale 576, la tensione in uscita è 4,883*608 = 2,968V, il comparatore dice che la tensione sul S/H è minore di quella del DAC pertanto il bit 6 del SAR viene riportato a 0 logico.
6. — Si continua in questo modo fino all’ultimo bit (1) del SAR —
Una volta arrivati al bit 0, peso 1, il valore all’interno del SAR sarà 1001000000 che equivale alla tensione di 2,812V, si trova tra 2,816V e 2,807V che è il range entro il quale è contenuto il reale valore della tensione che si sta misurando.
Il vantaggio degli ADC appartenenti a questa tipologia è che sono relativamente veloci e richiedono tanti cicli clock ADC quanti sono i bit, più uno per completare la conversione; inoltre sono semplici da implementare all’interno di un micro e possono arrivare a sample rate (ossia frequenze di campionamento) di svariati megasample al secondo.
Schema a blocchi di un ADC “SAR”
Tecniche di miglioramento delle letture ADC
La semplice lettura di un dato analogico, senza ricorrere ad una serie di accorgimenti hardware e software, tende a mostrare dati piuttosto instabili; questo, dal punto di vista hardware dipende dal mancato disaccoppiamento tra la tensione di alimentazione dell’ADC (AVCC) e quella di alimentazione generale (VCC), oltre che dall’assenza di un filtro sulla tensione di riferimento (ARef).
Purtroppo Arduino, almeno nei modelli base testati da noi, non possiede alcuno di questi elementi, e l’unico applicabile è il filtro sull’ARef. Tuttavia è bene comprenderne i meccanismi affinché essi possano essere adottati nei circuiti stand-alone senza difficoltà alcuna.
Il disaccoppiamento tra AVCC e VCC si ottiene mediante una resistenza da 22 ohm in serie al positivo di alimentazione ed un condensatore da 100 nF verso GND, che insieme formano un filtro passa-basso, tagliando buona parte del ripple ad alta frequenza normalmente presente sull’alimentazione e migliorando sia la stabilità della lettura che la precisione.
Risultati migliori si ottengono sostituendo la resistenza da 22 ohm con un’impedenza (induttanza) da 10 μH.
Il filtro sull’ARef si ottiene mediante un condensatore da 100 nF tra il pin ARef e GND.
In Fig. 2 abbiamo riportato il classico schema di un ATmega328P in modalità stand-alone con i due accorgimenti sopra descritti; ovviamente tali accorgimenti servono solo se il circuito verrà utilizzato per l’acquisizione di dati analogici, garantendo una precisione di ±1 count, altrimenti non avranno alcun significato.
Fig. 2 Configurazione hardware per un corretto utilizzo dell’ADC dell’ATmega328.
Nel prosieguo dell’articolo saranno mostrate alcune configurazioni d’uso dell’ADC; per aiutarvi a sperimentarle rapidamente, abbiamo approntato una serie di piccoli sketch correlati con le immagini di questo post.
Nelle note iniziali di ogni sketch sono riportati il numero della figura ad esso associata (ma a volte sono più di una) ed una breve descrizione della configurazione hardware.
Alcuni sensori di tipo analogico tendono a provocare valori instabili in assenza di segnale da misurare (quelli digitali, quando sono inattivi garantiscono comunque uno stato logico stabile), in questi casi conviene prevedere una resistenza con funzione di pull-down o di pull-up, cioè una resistenza (tipicamente da 10 kΩ) rispettivamente tra il pin analogico e GND o tra il pin analogico e VCC (di norma 5V).
La resistenza di pull-down si utilizza nei casi in cui occorre effettuare la lettura di tensioni con andamento positivo, per esempio quelle derivanti da sensori che forniscono un segnale con andamento proporzionale all’evento; viceversa, la resistenza di pull-up si utilizza nei casi di lettura di tensioni con andamento negativo, ovvero quando bisogna acquisire il segnale fornito da sensori che forniscono un segnale con andamento inversamente proporzionale all’evento.
Infine, ma in questo caso parliamo di protezione più che di stabilità e precisione, quando si lavora con sensori alimentati a tensioni maggiori della VCC (non ha importanza invece il valore di ARef), per prevenire possibili guasti, è buona norma usare un diodo Zener, di valore leggermente superiore alla tensione di riferimento, con il catodo sul pin di Arduino ed l’anodo a GND, con una resistenza in serie per limitare la corrente (vedere la Fig. 3).
In tal modo, quando la tensione da misurare dovesse erroneamente superare quella dello Zener, esso entrerà in conduzione verso GND, tagliando il valore in eccesso.
Naturalmente quando si interfaccia un sensore alimentato a tensione superiore a VCC il segnale viene opportunamente trattato (in genere mediante un partitore), affinché, in corrispondenza della massima tensione in uscita dal sensore, sul pin analogico arrivi una tensione al limite del range di valori ammissibile; quindi lo Zener ha una funzione protettiva solo in caso di guasto.
Il diodo Zener ovviamente deve avere una resistenza di limitazione quasi sempre rappresentata da quella interna del sensore stesso; ma in alcuni casi è necessario aggiungerla esternamente: è il caso, appunto, della Fig. 3, nella quale, oltre allo Zener è presente una resistenza di limitazione della corrente.
Naturalmente questo componente va previsto solo se esiste realmente una necessità di protezione dell’ingresso del micro.
Da notare come nella predetta Fig. 3 e nelle seguenti non abbiamo riportato l’intera circuiteria necessaria per in buon funzionamento dell’ADC; la diamo per scontata dove sia possibile usarla, ma in questo caso lo schema è basato su Arduino e non sul solo ATmega328P-PU, quindi in questi interventi siamo molto limitati.
Fig. 3 Collegamento analogico protetto.
Per migliorare la lettura dei valori analogici si può intervenire anche via software; fondamentalmente sono disponibili le due modalità descritte di seguito.
• Fare la media di un certo numero di letture effettuate in un breve lasso di tempo e poi dare un unico risultato; in questo caso, prendendo ad esempio 10 valori consecutivi: 512, 513, 512, 522, 514, 512, 518, 510, 508, 512, la media risultante sarebbe 513, quindi i quattro picchi massimi e minimi (522, 518 e 508, 510) risulteranno praticamente ignorati.
Ovviamente questa tecnica vale solo nei casi in cui si stiano misurando valori tendenzialmente stabili o che variano molto lentamente nel tempo, diversamente produrrebbe l’effetto opposto.
Per esempio, se si sta misurando la temperatura ambiente è molto improbabile che possano esserci fluttuazioni di 1-2 °C nell’arco di qualche millisecondo, quindi questa tecnica potrebbe andar bene; ma se pensiamo all’uso di sensori per la misurazione della distanza o del movimento è ovvio che, essendoci la necessità di una rilevazione in tempo reale, la media di una misurazione multipla potrebbe produrre misurazioni notevolmente falsate.
• Un altro modo per aumentare la precisione consiste nell’aumentare via software i bit di conversione dell’ADC e quindi la risoluzione, una tecnica denominata “oversampling”.
L’oversampling sfrutta sia l’errore di quantizzazione tra le misure, cioè quei mV che rappresentano la differenza in più o in meno tra il valore reale della tensione e lo step minimo del DAC, sia il rumore sovrapposto al segnale; ne deriva che, per quanto possa sembrare assurdo, una tensione perfettamente pulita (ossia segnale privo di disturbi) non permette l’uso corretto dell’oversampling.
La tecnica consiste nell’acquisire 4n sample, ove n è il numero di bit da guadagnare, sommarli e dividerli per 2n. Per esempio, l’ADC dell’ATmega328P è a 10 bit, quindi restituisce un valore massimo di
210 – 1 = 1.023; ma siccome noi vogliamo passare da una risoluzione a 10 ad una a 11 bit, acquisiamo quattro letture (41=4) e sommiamo tra loro i valori corrispondenti, dividendo poi il risultato per 2 (21=2).
Immaginiamo ora di leggere i quattro valori 1000, 1002, 1002, 1000, la cui somma è 4004, che divisa per 2 fornisce una lettura finale di 2.002; quest’ultimo valore rientra nel nuovo range a 11 bit
(211 – 1 = 2047) e la nuova risoluzione (sempre restando nel riferimento standard di 5V) ora è di 5V/2048=0,002441 V, cioè 2,44 mV.
Se invece vogliamo passare a 12 bit si acquisiscono 16 letture (42=16) e si dividono per 4 (22 = 4), in questo caso il nuovo range arriva a 212 – 1 = 4.095 e la nuova risoluzione è di 5V/4.096=0,001220 V, cioè 1,22 mV.
Naturalmente tale aumento di precisione ha un prezzo da pagare, che è la riduzione della banda passante; col passaggio da 10 a 11 bit la banda si riduce a 1/4, col passaggio da 10 a 12 bit la banda si riduce a 1/16, e così via, pertanto è decisamente sconsigliabile un incremento oltre 2 bit.
Solitamente alla tecnica dell’oversampling si ricorre quando la velocità di lettura non è prioritaria mentre serve la maggiore risoluzione possibile.
Sensori Analogici
Con questo termine si definiscono tutti quei componenti, attivi o passivi, che trasformano una grandezza fisica in una grandezza elettrica (tensione o corrente) che è facilmente misurabile.
Un sensore attivo, in genere, è un sensore alimentato che, a fronte delle variazioni della grandezza fisica da misurare (per esempio la temperatura), fornisce sul suo pin di uscita una tensione proporzionale al valore misurato; un esempio è l’integrato LM35 che, alimentato a 5 V tramite due dei suoi tre pin, fornisce sul piedino di uscita una tensione che aumenta all’aumentare della temperatura ambiente, ovvero direttamente proporzionale alla temperatura secondo un coefficiente di drift di 10 mV/°C.
Tale tipo di sensore è collegabile direttamente ad un pin analogico di Arduino, in quanto, per leggere temperature positive è alimentabile con una tensione di alimentazione uguale a quella di Arduino (vedere la Fig. 4).
Fig. 4 Schema applicativo di base del sensore.
Da notare che non serve collegare una resistenza di pull-down in quanto, come spiegato in precedenza, i sensori attivi forniscono costantemente un valore di tensione da 0 V in su, perciò sono essi che stabiliscono la tensione; il resistore di pull-down è necessario di norma per tenere a zero volt una linea quando ciò che vi è collegato si trova nella condizione di non poterlo fare (oppure nulla è collegato) come i resistori di pull-up servono per mantenere il livello alto in assenza di qualcosa che lo possa fare.
Invece un sensore passivo è un componente le cui caratteristiche sono influenzate da una data grandezza fisica da misurare, quindi non necessita di una alimentazione esterna.
Un esempio può essere un termistore NTC (Negative Temperature Coefficient) che è un resistore il cui valore resistivo diminuisce all’aumentare della temperatura; anche il suo complementare PTC (Positive Temperature Coefficient) che è un resistore che si comporta all’opposto, ovvero il cui valore resistivo aumenta all’aumentare della temperatura.
Le variazioni di resistenza generate da questi sensori, però, non possono essere direttamente interpretate dai pin analogici di Arduino, quindi necessitano di una conversione.
Il Partitore Resistivo
Nel caso dei sensori di tipo resistivo, essi devono essere inseriti in un circuito, il cosiddetto “partitore resistivo variabile” che, alimentato esternamente, è in grado di generare una tensione più o meno proporzionale alla variazione del valore resistivo del sensore; in poche parole, inserendo un sensore passivo in un idoneo circuito alimentato, lo si trasforma in un sensore attivo che, come tale, può essere letto direttamente dal pin analogico di Arduino (Fig. 5).
Fig. 5 Schema applicativo del sensore NTC.
Esistono altri sensori passivi che sono in grado di generare direttamente dei valori in tensione, in virtù delle loro specifiche proprietà fisiche, ma questa tensione ha dei valori così piccoli da risultare illeggibile da parte del pin analogico.
È il caso delle Termocoppie (ne esistono diverse tipologie, le principali delle quali sono i tipi K, J e T) che sono componenti costituiti da due elementi metallici di diversa natura (a differente struttura atomica), uniti ad un capo e separati all’altro capo, dove appunto è possibile misurare delle differenze di potenziale di circa 10 microvolt (µV) per °C; tale tensione deriva dall’effetto seebeck, ossia dallo scompenso di carica elettrica nella zona di contatto tra due metalli a diversa valenza.
In questo caso non serve un convertitore ma un amplificatore in tensione, in grado di portare il segnale almeno a 5÷10 millivolt (mV) per °C che, in questo caso, sono direttamente misurabili dall’ADC di Arduino (vedi Fig. 6).
Fig. 6 Schema applicativo di una termocoppia tipo K.
Bene, poc’anzi abbiamo definito il partitore resistivo variabile come un circuito in grado di trasformare un sensore passivo, di tipo resistivo, in sensore attivo; in questo caso il sensore è un elemento variabile del partitore e viene usato assieme ad un altro elemento di valore fisso, che fa da riferimento.
Ma esistono situazioni in cui il partitore resistivo viene costruito con due elementi fissi, allo scopo di ridurre l’ampiezza in volt di un segnale avente tensione maggiore rispetto alla tensione di alimentazione di Arduino.
Finora abbiamo “usato” Arduino in condizioni ideali, cioè applicando agli ingressi analogici solo tensioni inferiori a quella di riferimento e ci sono molte situazioni in cui questa condizione ideale è assolutamente possibile: per esempio con sensori che operano con una tensione di alimentazione di 5 V; ma cosa succede quando siamo costretti a lavorare con tensioni analogiche decisamente superiori, come ad esempio i canonici 12 V o anche 24 V di molti sensori? Qui le cose cambiano decisamente, almeno per quanto riguarda la protezione degli input/output del microcontrollore: se non prendiamo i giusti provvedimenti, alla prima lettura fatta male lo distruggiamo inesorabilmente!
Sensore a 12 V, Riferimento DEFAULT a 5V
Introduciamo questo primo esempio dicendo che applicare a un pin analogico un segnale con valore di tensione maggiore di quello di riferimento significa con ogni probabilità “bruciare” il micro; per questa ragione tale segnale va assolutamente ridotto in ampiezza. Questo è appunto il canonico caso applicativo in cui si ricorre all’utilizzo del partitore resistivo fisso (Fig. 7).
Nello specifico, conosciamo sia la tensione del segnale analogico (12 V) che quella di riferimento da dare all’A/D converter (5 V); dobbiamo quindi fare in modo da ottenere una VRidotta pari o inferiore a 5 V quando il sensore fornisce in uscita 12 V.
Allo scopo, ci basta stabilire che valore intendiamo usare come pull-down, per esempio 4,7 kΩ (4.700 Ω) che è un valore commerciale.
Con questi tre valori possiamo ricavarci il valore globale del partitore resistivo e quindi della R da applicare in serie al segnale analogico. La formula da applicare è:
RSensore = (VMaxSensore * RPulldown / VRiferimento) – RPulldown
dalla quale ricaviamo che:
RSensore = (12 V * 4700 Ω / 5 V) – 4700 Ω = 6580 Ω
Notate che nelle formule le resistenze vengono definite dal valore in ohm; ricordate anche che 1 kΩ è pari a 1.000 Ω.
La resistenza da applicare in serie al sensore deve essere di 6.580 Ω; il valore commerciale più vicino è 6.800 Ω, ma ovviamente poi bisogna ricalcolare i valori della scala di conversione, ricorrendo ad una ulteriore formula:
VRidotta = VMaxSensore / RPartitore * RPulldown
in cui RPartitore è uguale a:
R1 + R2 = 6.800 Ω + 4.700 Ω = 11.500 Ω.
Applicando tale formula si vede come la VRidotta non combaci con la VRiferimento; infatti si ha:
VRidotta = 12 V /11.500 Ω x 4700 Ω = 4,90 V
invece dei 5 V previsti.
Fig. 7 Il partitivo resistivo fisso.
Se non si vuole rinunciare ad ottenere un valore ben preciso che prescinda da quelli commerciali, al posto della RSensore fissa si può adottare un trimmer, possibilmente del tipo multigiri, che sarà usato con funzione di reostato, cioè di resistenza variabile, per ottenere il valore desiderato (Fig. 8); il valore del trimmer dovrebbe essere almeno del 50% più alto rispetto alla RSensore calcolata, nel nostro caso va benissimo un 10 kΩ (10.000 Ω).
In pratica, applicando una tensione di 12 V esatti agli estremi del partitore occorrerà ruotare la vite del trimmer fino a leggere 5 V esatti nel punto di contatto tra trimmer e resistenza di pull-down.
Questo metodo garantisce eccellente precisione, ma ha lo svantaggio di richiedere una operazione di taratura.Tornando alla resistenza di valore fisso, nella maggior parte dei casi sarà sufficiente una coppia di resistenze a valore fisso, però è buona norma usare quelle a strato metallico che garantiscono buona precisione e stabilità, tipicamente 0,5% o 1% di tolleranza, contro il 5% delle resistenze comuni.
Nel prosieguo inoltre effettueremo dei calcoli sul valore nominale delle resistenze; in realtà dovreste misurare con un buon multimetro il valore preciso delle resistenze che sceglierete di usare e sostituire nelle formule i valori nominali con quelli effettivi; bisogna considerare infatti che ogni differenza si ripercuoterà sul valore finale ottenuto, per cui potreste ottenere delle misurazioni, a livello software (cioè quando convertirete i valori analogici letti nella misura da visualizzare) abbastanza diverse rispetto a quelle reali.
Nota importante: è molto difficile che al primo calcolo si ottenga per la RSensore un valore commerciale, quindi ovviamente si è costretti a ripiegare su un valore prossimo; in questi casi occorre sempre usare il valore resistivo immediatamente superiore.
Infatti, mentre un valore di resistenza più alto fa sì che la VRidotta sia leggermente inferiore alla VRiferimento, un valore più basso porterebbe la VRidotta ad un valore maggiore della ARef, per cui i valori più alti di misura del sensore andrebbero tutti fuori scala (over-range) quindi tale condizione dev’essere evitata.
In questa situazione non parliamo invece di rischi, in quanto qualche centinaio di millivolt di extra-tensione viene tranquillamente tollerato dai pin di Arduino.
Tornando all’esempio che stiamo analizzando, in pratica quando il sensore in uscita fornirà una tensione di 12 V esatti, sul pin analogico di Arduino ne arriveranno 4,9 V, valore più che accettabile; da esso poi si può calcolare il:
FattoreRiduzione = VMaxSensore / VRidotta
cioè:
FattoreRiduzione = 12 V / 4,9 V = 2,45.
Di questo valore dovremo tener conto in quanto, naturalmente, a livello software bisognerà effettuare la riconversione da decimale alla corrispondenza in Volt.
Bene, adesso calcoliamo la risoluzione di lettura:
Risoluzione = VRiferimento / 1024
quindi:
Risoluzione = 5 V / 1024 = 0,0049 V (4,9 mV)
A livello software, per risalire alla tensione originale del sensore dovremo effettuare questo semplice calcolo:
VOutSensore = LetturaDecimale x Risoluzione x FattoreRiduzione
In pratica, se leggeremo un valore di 600, esso corrisponderà a:
VOutSensore = 600 x 0,0049 V x 2,45 = 7,20 V
Quindi, come vedete, non dovete preoccuparvi più di tanto della non perfetta corrispondenza tra i 12 V del sensore ed i 5 V del riferimento ADC, ma solo di calcolare correttamente il fattore di riduzione e la risoluzione.
Naturalmente, sempre a livello software, se il partitore non riduce perfettamente i 12 V a 5 V, quindi se il rapporto di partizione atteso non è rispettato, cambierà il fondo scala di lettura; infatti se ripetiamo la formula precedente usando il valore massimo di 1.023, cioè:
VFondoScala = 1023 x Risoluzione x Fattore riduzione
Nel nostro caso:
VFondoScala = 1023 x 0,0049 V x 2,45 = 12,28 V
Da questo scaturisce una formula alternativa per calcolare la VOutSensore:
VOutSensore = LetturaDecimale x VFondoScala / 1.023
Infatti, riprendendo l’esempio precedente:
VOutSensore = 600 x 12,28 / 1.023 = 7,20 V
Per verificare che tutto sia stato calcolato in maniera corretta proviamo a cambiare la resistenza di pull-down e rieseguiamo tutte le formule (questa volta senza spiegazioni).
Usiamo come pull-down un valore di 10 kΩ.
RSensore = (VMaxSensore * RPulldown / VRiferimento) – RPulldown
RSensore = (12 V * 10.000 Ω / 5 V) – 10.000 Ω = 14.000 Ω
Il valore commerciale più prossimo è 15 kΩ;
RPartitore = RSensore + RPulldown
quindi:
RPartitore = 15.000 Ω + 10.000 Ω = 25.000 Ω
Applicando la formula:
VRidotta = VMaxSensore / RPartitore x RPulldown
otteniamo:
VRidotta = 12 V / 25000 Ω x 10000 Ω = 4,8 V
Anche in questo caso il valore è accettabile; da esso poi si può calcolare il:
FattoreRiduzione = VMaxSensore / VRidotta
cioè:
FattoreRiduzione = 12 V / 4,8 V = 2,5
Ora calcoliamo la risoluzione di lettura:
Risoluzione = VRiferimento / 1024
quindi:
Risoluzione = 5 V / 1024 = 0,0049 V (4,9 mV)
Come già spiegato, la formula seguente ci fa risalire alla tensione originale del sensore:
VOutSensore = LetturaDecimale x Risoluzione x FattoreRiduzione
In pratica, se leggeremo un valore di 600, esso corrisponderà a:
VOutSensore = 600 x 0,0049 V x 2,5 = 7,35 V
In questo caso una lettura “600” corrisponde ad un diverso valore in tensione, rispetto al caso precedente, a motivo del differente fattore di riduzione.
Infine abbiamo:
VFondoScala = 1023 x Risoluzione x Fattore riduzione
da cui deriva:
VFondoScala = 1023 x 0,0049 V x 2,5 = 12,53 V
E quindi la formula alternativa per calcolare la
VOutSensore:
VOutSensore = LetturaDecimale x VFondoScala / 1023
Che equivale a:
VOutSensore = 600 x 12,53 / 1023 = 7,35 V
Fig. 8 Il partitivo resistivo fisso con trimmer.
Fig. 8 Il partitivo resistivo fisso con trimmer.
Sensore a 5V, Riferimento EXTERNAL a 3,3V
Questo è un caso particolare, pur disponendo di un sensore che opera a 5 V decidiamo di usare una scala a 3,3 V.
Abbiamo già spiegato che il parametro EXTERNAL si usa quando si vuole ottenere una scala particolare oppure per fornire un riferimento stabile all’ADC, mediante una tensione di riferimento precisa.
In questo esempio utilizzeremo un integrato regolatore di precisione per fornire 3,3V come riferimento all’ADC; questi 3,3V saranno anche il fondo scala dell’ADC, cioè la tensione per la quale il microcontrollore fornirà come misura il valore 1023 (Fig. 9).
Anche qui conosciamo sia la tensione del segnale analogico che quella di riferimento per l’ADC; decidiamo di usare come pull-down una resistenza da 10 kΩ (10.000 Ω). Procediamo quindi con i calcoli:
RSensore = (VMaxSensore x RPulldown/VRiferimento) – RPulldown
quindi:
RSensore = (5 V x 10.000 Ω / 3,3 V) – 10.000 Ω = 5.151 Ω
Il valore commerciale più prossimo è 5,6 kΩ, il valore globale del partitore è:
RPartitore = RSensore + RPulldown
quindi RPartitore = 5.600 Ω + 10.000 Ω = 15.600 Ω
per cui:
VRidotta = VMaxSensore / RPartitore x RPulldown
da cui deriva il valore:
VRidotta = 5 V / 15.600 Ω x 10.000 Ω = 3,21 V
quindi si può calcolare il:
FattoreRiduzione = VMaxSensore / VRidotta
cioè:
FattoreRiduzione = 5 V / 3,21 V = 1,56
Tutto ciò significa che quando il sensore fornirà una tensione in uscita di 5 V, al pin analogico del microcontrollore arriverà in realtà una tensione di 3,21 V.
Ora calcoliamo la risoluzione di lettura:
Risoluzione = VRiferimento / 1024
quindi:
Risoluzione = 3,3 / 1024 = 0,0032 V cioè 3,20 mV
A livello software, per risalire alla tensione originale del sensore, dovremo effettuare alcuni semplici calcoli; per esempio se leggeremo un valore di 600, esso corrisponderà a una tensione reale in ingresso all’ADC pari a:
VAnalogica = LetturaDecimale x Risoluzione
quindi: 600 x 0,0032 V = 1,92 V, per risalire al valore effettivo in uscita dal sensore (quindi prima del partitore), occorrerà applicare la formula:
VOutSensore = LetturaDecimale x Risoluzione x FattoreRiduzione
VOutSensore = 600 x 0,0032 V x 1,56 = 3 V
D’altra parte una semplice proporzione ci conferma quanto appena ottenuto:
VMaxSensore : VRidotta = x : VRealeADC
=cioè: 5 : 3,2 = x : 1,92 in cui x = 3 V
Infine abbiamo:
VFondoScala = 1023 x Risoluzione x Fattore riduzione
cioè:
VFondoScala = 1023 x 0,0032 V x 1,56 = 5,11 V
Arriviamo quindi alla formula alternativa per calcolare la VOutSensore:
VOutSensore = LetturaDecimale * VFondoScala / 1023
che equivale a:
VOutSensore = 600 x 5,11 / 1.023 = 3 V
Fig. 9 Schema applicativo con ARef esterno.
Sensore a 3,3 V, Riferimento INTERNo a 1,1 V
In questo caso affrontiamo una problematica simile alle precedenti, perché si tratta sempre di ridurre un segnale in ampiezza. Il sensore opera a 3,3 V e noi decidiamo di attivare il riferimento interno dell’ADC di Arduino o, meglio, del suo ATmega328P.
Stavolta decidiamo di usare un resistore di pull-down da 3,3 kΩ (Fig. 10).
Procediamo con i calcoli:
RSensore = (VMaxSensore * RPulldown / VRiferimento) – RPulldown
quindi:
RSensore = (3,3 V x 3.300 Ω / 1,1 V) – 3.300 Ω = 6.600 Ω
Il valore commerciale più prossimo a 6.600 ohm è 6,8 kΩ, almeno il primo valore immediatamente superiore. Il valore resistivo globale del partitore è:
RPartitore = RSensore + RPulldown
quindi:
RPartitore = 6.800 Ω + 3.300 Ω = 10.100 Ω
per cui:
VRidotta = VMaxSensore / RPartitore * RPulldown
da cui deriva il valore:
VRidotta = 3,3 V / 10.100Ω x 3.300Ω = 1,08V
quindi si può calcolare il:
FattoreRiduzione = VMaxSensore / VRidotta
cioè:
FattoreRiduzione = 3,3 V / 1,08 V = 3,055
Ora calcoliamo la risoluzione di lettura dell’ADC:
Risoluzione = VRiferimento / 1024
quindi:
Risoluzione = 1,1 V / 1.023 = 0,0011 V cioè 1,1 mV
A livello software, per risalire alla tensione originale del sensore dovremo effettuare questo calcolo:
VOutSensore = LetturaDecimale x Risoluzione x FattoreRiduzione
In pratica, se leggeremo un valore di 600, esso corrisponderà a:
VOutSensore = 600 x 0,0011 V x 3,06 = 2,02 V
Infine abbiamo:
VFondoScala = 1.023 x Risoluzione x Fattore riduzione
cioè:
VFondoScala = 1023 x 0,0011 V x 3,06 = 3,44 V
E quindi la formula alternativa per calcolare la VOutSensore:
VOutSensore = LetturaDecimale x VFondoScala / 1023
Che equivale a:
VOutSensore = 600 * 3,44 / 1023 = 2,02 V
Fig. 10 Schema applicativo con ARef interno.
Sensore passivo, Riferimento DEFAULT a 5 V
Anche in questo caso affrontiamo una problematica diversa dalle precedenti; ora il sensore è passivo e noi dobbiamo inserirlo in un partitore in modo da renderne il funzionamento attivo.
In questo caso il sensore farà la parte della resistenza di sensore, quindi l’unico valore da calcolare sarà quello di pull-down. Lo schema applicativo è quello mostrato nella Fig. 10.
Per il nostro esempio pensiamo ad un termistore di tipo NTC (già descritto in precedenza). Ogni tipo di NTC ha delle specifiche che sono fondamentalmente il valore in ohm in relazione alla temperatura; in genere viene espresso il valore in ohm ad una temperatura di 25°C. Gli NTC non hanno una variazione proporzionale della loro resistenza in base alla temperatura, ecco perché occorre costruire delle “scale” via software.
Per meglio comprendere questi concetti, un NTC modello TDC 310 può operare in un range di temperatura da -20°C a +120°C, con un range ohmico che va rispettivamente da 90 kΩ a 380Ω. Stabiliamo di usare un range ristretto da 0 a 50°C e prendiamo alcuni valori intermedi di temperatura con i relativi valori di resistenza:
0°C(33 kΩ), 10°C(20 kΩ), 20°C(13 kΩ), 25°C(10 kΩ), 30°C(8 kΩ), 40°C(5,5 kΩ), 50°C(3,5 kΩ)
Creando un grafico di comparazione ci si rende subito conto che, seppur sia riscontrabile una certa proporzionalità inversa tra di essi, di fatto non c’è una linearità che possa essere usata in una formula matematica. Ecco perché, scelto il range e la risoluzione di temperatura da misurare bisogna creare una tabella di conversione via software, per risalire al valore della temperatura letto dall’NTC.
Poiché disponiamo dei valori teorici di resistenza dell’NTC (RSensore), prelevabili dal suo datasheet, una volta stabilito il valore della pull-down (RPulldown), le formule viste sin qui ci permetteranno di risalire a valori che in precedenza ci erano noti e che ora sono incogniti.
Stabiliamo di usare come resistenza di pull-down una 10 kΩ e alimentiamo a 5 V il partitore costituito dall’NTC e dalla pull-down; nello specifico questa scelta è dettata dal fatto che il data-sheet di questo sensore riporta che il valore di resistenza a 25°C è appunto di 10 kΩ, quindi a questa temperatura ci aspettiamo un segnale di ampiezza pari a metà dell’alimentazione. Infatti:
RPartitore = RSensore + RPulldown
naturalmente darà un risultato diverso ad ogni temperatura in quanto RSensore è un valore variabile. In base ai valore campione di cui disponiamo avremo i seguenti valori di RPartitore alle relative temperature:
0° = 33 kΩ + 10 kΩ = 43 kΩ
10° = 20 kΩ + 10 kΩ = 30 kΩ
20° = 13 kΩ + 10 kΩ = 23 kΩ
25° = 10 kΩ + 10 kΩ = 20 kΩ
30° = 8 kΩ + 10 kΩ = 18 kΩ
40° =5,5 kΩ + 10 kΩ = 15,5 kΩ
50° =3,5 kΩ + 10 kΩ = 13,5 kΩ
Se partiamo dalla formula:
VRidotta = VMaxSensore / RPartitore x RPulldown
possiamo convertirla in:
VOutSensore = VMaxSensore / RPartitore x RPulldown
VMaxSensore è 5 V, quindi avremo questi valori di tensione teorici:
0° = 1,16 V
10° = 1,67 V
20° = 2,17 V
25° = 2,50 V
30° = 2,77 V
40° = 3,23 V
50° = 3,70 V
Come potete vedere, a 25°C avremo appunto una tensione misurabile di 2,5 V.
Poiché operiamo con riferimento a 5 V abbiamo:
Risoluzione = 5 V / 1024 = 0,0049 V = 4,9 mV
Di conseguenza possiamo ricavare i valori decimali presunti con la nuova formula:
LetturaDecimale = VOutSensore / Risoluzione
quindi:
0° = 1,16 V / 0,0049 V = 237
10° = 1,67 V / 0,0049 V = 341
20° = 2,17 V / 0,0049 V = 443
25° = 2,50 V / 0,0049 V = 510
30° = 2,77 V / 0,0049 V = 565
40° = 3,23 V / 0,0049 V = 659
50° = 3,70 V / 0,0049 V = 755
Come si può ben intuire, non è possibile ricavare un fattore di riduzione univoco, allora è chiaro il motivo per cui bisogna realizzare delle tabelle da gestire poi via software, in modo da attribuire ad ogni lettura analogica un relativo corrispondente valore in °C.
La tabella andrà realizzata sulla base della risoluzione che si vuole ottenere; in pratica servono 51 valori se ci basta una risoluzione di 1°C, 101 valori se la risoluzione aumenta a 0,5C, 501 valori per ottenere una risoluzione di 0,1°C.
Utilizzo del partitore resistivo fisso per i segnali digitali
Chiudiamo questo tutorial con un piccolo fuori tema, che tuttavia riteniamo molto utile: quanto visto finora a proposito della riduzione in ampiezza di un segnale analogico è facilmente applicabile anche ai pin digitali di Arduino che, come si sa, sono in grado, usati come ingressi, di leggere due stati logici: LOW o 0 (0V) e HIGH o 1 (5 V).
Esistono sensori di tipo digitale che generano appunto questi due livelli logici, ma a volte hanno tensioni di funzionamento maggiori rispetto ai 5 V di Arduino. In questi casi non è possibile applicare direttamente il segnale al pin di Arduino perché si danneggerebbe il microcontrollore.
Anche in questo caso è possibile risolvere il problema calcolando un partitore fisso con la formula:
RSensore = (VMaxSensore * RPulldown / VRiferimento) – RPulldown
In cui VMaxSensore è il valore di alimentazione del sensore (per esempio 12 V) e VRiferimento è la tensione di alimentazione di Arduino (5 V), che coincide con il livello logico HIGH o 1.
In genere il valore di pull-down che si usa sui pin digitali è 10 kΩ, quindi la formula diventa (mantenendo l’esempio di 12 V):
RSensore = (12 V x 10000 Ω / 5 V) – 10.000Ω = 14.000 Ω
Il valore commerciale più prossimo è 15 kΩ;
RPartitore = RSensore + RPulldown
quindi:
RPartitore = 15.000Ω + 10.000Ω = 25.000Ω
per cui:
VRidotta = VMaxSensore/RPartitore*RPulldown
da cui deriva il valore:
VRidotta = 12 V / 25.000Ω x 10.000Ω = 4,8 V
Il valore è più che accettabile come livello logico HIGH, ovvero come 1 logico.
Poiché, una volta compresi tutti i passaggi visti in queste pagine, ciò che conta sono solo le formule, abbiamo pensato di preparare la Tabella 1 che riepiloga tutte le formule usate e i relativi riferimenti.
Tenete presente che, come sempre, da una formula si possono ricavare le cosiddette formule inverse, invertendone i fattori in modo da ottenere tutti quelli desiderati; in alcuni casi le abbiamo riportate, altre potete ricavarvele facilmente da soli, all’occorrenza.
Tabella 1
Conclusioni
Bene, con questo abbiamo concluso; speriamo di avervi trasmesso tutte le nozioni utili a sfruttare al meglio l’A/D converter dei microcontrollori impiegati in Arduino.
Siamo certi che nello sviluppo dei vostri nuovi progetti basati su Arduino e sulla lettura di grandezze analogiche (tensioni, segnali di sensori, componenti ad audiofrequenza ecc.) avrete ora una marcia in più.
Buona progettazione!