Rilevare batteria scarica con un microcontrollore PIC senza usare IO
In riferimento ad un articolo precedente, in cui illustravo un modo per leggere la tensione di batteria (ma anche una tensione analogica qualsiasi) utilizzando il modulo FVR come riferimento, qualche giorno fa mi scrive Gianfranco Moretti, lettore di Settorezero, illustrandomi un sistema, da lui usato con successo, per segnalare all’utente quando la batteria è scarica in uno strumento portatile il cui cuore è costituito da un microcontrollore PIC. Gianfranco compie questa operazione senza collegare alla batteria nessun I/O. Detta così sembra una cosa assurda per chi non conosce il trucchetto: anche io li per li, sono onesto, facevo fatica a comprendere dal momento che il sistema prevede di leggere internamente la tensione fissa fornita dal modulo FVR.
Indice dei contenuti
Una questione di riferimenti
L’FVR, lo sappiamo, fornisce una tensione fissa di base a 1024mV, ma è possibile impostare un guadagno di 2x o di 4x per ottenere tensioni di 2048 e 4096mV rispettivamente: questo è vero finchè la tensione di alimentazione si mantiene al di sopra del valore impostato per l’FVR (se alimento il PIC a 3.3V è chiaro che se imposto l’FVR per darmi 4.096V, non me li potrà mai fornire). Il nocciolo è proprio questo: la tensione dell’FVR è fissa, lo dice il nome stesso del modulo (Fixed Voltage Reference) e, specialmente se impostata a 1024mV, non varierà proprio mai perchè non è possibile alimentare il PIC al di sotto di 1.024V (il PIC usato nel mio esempio arriva a 2.6V circa): quindi a cosa serve leggere la tensione dell’FVR?
L’attenzione difatti, va focalizzata su un altro aspetto: il riferimento positivo del modulo ADC. Quando utilizziamo il modulo ADC con VDD (tensione di alimentazione del PIC), la lettura di un valore analogico è rapportata a tale valore: ecco perchè nell’articolo precedente consigliavo di non usare mai VDD come riferimento se dobbiamo fare letture precise e stabili.
Facciamo un esempio: ho un PIC con un modulo ADC che ha una risoluzione di 10bit. Tale modulo mi fornirà un’uscita numerica intera con valori da 0 a 1023. Utilizzando VDD come riferimento positivo (e GND come riferimento negativo), il modulo ADC non farà altro che restituirmi in proporzione un numero da 0 a 1023 per un range di tensioni lette da 0 a VDD volts.
Supponiamo quindi di alimentare il PIC a 5V: il modulo ADC a 10bit avrà una risoluzione pari a:
Con “step” ho indicato il valore numerico intero restituito dal modulo ADC. A volte Microchip fa riferimento a questo valore come “count”. Insomma chiamatelo come preferite: è giusto per non fare confusione col significato dei numeri mostrati.
Il valore numerico intero che otterremo in uscita dal modulo ADC dopo la lettura di un ingresso analogico, moltiplicato 4.8875, fornirà il valore in mV della tensione applicata a quell’ingresso (con una certa approssimazione). Supponiamo ora di applicare una tensione di 1024mV all’ingresso di sampling: il modulo ADC, che ricordiamo ha 5V come riferimento positivo, ci restituirà un valore numerico intero pari a:
Supponiamo ora di abbassare la VDD, ovvero la tensione di alimentazione del PIC che è utilizzata anche come riferimento positivo dell’ADC, e di portarla ad esempio a 3V: il riferimento superiore è cambiato, per cui dobbiamo aspettarci che cambi anche la risoluzione:
Vediamo che ora la risoluzione è più alta (ogni step corrisponde ad un valore più piccolo). Adesso, però, la tensione di 1024mV che stavamo leggendo prima, dato che è confrontata con un range differente, non ci fornirà più in uscita dal modulo ADC un valore di 210, bensì:
Cosa accade? Stiamo, si, leggendo un valore che rimane fisso, ma lo stiamo confrontando all’interno di un range che cambia. Arrivati a questo punto il trucchetto comincia ad essere chiaro: leggiamo una tensione che rimane sempre costante, che è appunto quella fornita dall’FVR, ma variando il riferimento del modulo ADC, impostato alla tensione di alimentazione, varia la risoluzione di lettura del modulo e di conseguenza il valore digitale restituito. Vedete che man mano che la tensione di riferimento del modulo (VDD) si abbassa, la risoluzione aumenta e di conseguenza la lettura fornita dal modulo ADC di un valore che rimane fisso, aumenta.
A questo punto nel nostro codice eseguiremo i seguenti passi:
- Alimentiamo il PIC in maniera diretta con la batteria che vogliamo monitorare (ad esempio una cella LiPO)
- Settiamo il modulo ADC per utilizzare VDD come riferimento positivo e VSS (GND) come riferimento negativo
- Settiamo il modulo FVR per generare 1024mV (quindi nessun guadagno)
- Impostiamo il canale da far leggere al modulo ADC sul buffer 1 dell’FVR
L’FVR ha difatti due uscite separate chiamate buffer1 e buffer2, il buffer2 si trova sul percorso che va al modulo comparatore.
App Note
Questo modo di procedere, in realtà, è già noto da anni. Un’ Application Note della Microchip, la 1072 (che risale al 2007!) illustra proprio come misurare la VDD utilizzando un riferimento fisso interno: venne scritta quando il modulo FVR non esisteva ancora e alcuni PIC avevano la capacità di generare una tensione interna, chiamata VP6, di 0.6V che aveva anch’essa la possibilità di essere letta dal modulo ADC.
Errori
I valori numerici che possiamo calcolare teoricamente possono essere ben distanti da quello che troveremo sperimentalmente: questo perchè il modulo FVR non è precisissimo e in più stiamo facendo tante approssimazioni sui decimali e il valore restituito dal modulo è quantizzato. Quindi il sistema migliore, prima di impostare una soglia sulla quale segnalare batteria scarica, è quello di misurare.
Facciamo quindi due conti. Il valore numerico fornito dal modulo ADC sulla lettura dei 1024mV forniti dal modulo FVR vale, per quanto detto sopra:
Per cui la formula inversa, per poter ricavare il valore di VDD in mV dal valore restituito dal modulo ADC è:
Ho fatto quindi delle misurazioni con il codice di esempio allegato a questo articolo e messo tutto nella tabella che segue. Con un alimentatore variabile stabilizzato ho alimentato il PIC in un range di tensioni da 5.1V a 2.56V (sotto questo valore il PIC si spegne). Il valore di tensione applicato l’ho misurato con un tester (che non è cinese ma non è nemmeno un Fluke e avrà quindi i suoi errori) e riportato nella prima colonna. Nella seconda colonna ho riportato il valore che mi aspetto venga restituito dall’ADC secondo la [1]. Nella terza colonna ho riportato il valore reale restituito dal modulo ADC e che ho riportato sulla UART per poterlo leggere. Nella quarta colonna è riportato il valore di VDD teorico calcolato con la [2] a partire dal valore restituito dall’ADC. L’ultima colonna rappresenta l’errore relativo percentuale sulla tensione misurata ((teorico-reale)/teorico):
VDD (V) | ADC teorico | ADC misurato | Tensione ricavata da ADC misurato | Errore relativo % |
---|---|---|---|---|
5,1 | 206 | 212 | 4,9 | -3,1% |
5,0 | 210 | 216 | 4,8 | -3,0% |
4,9 | 214 | 221 | 4,7 | -3,3% |
4,8 | 218 | 226 | 4,6 | -3,5% |
4,7 | 223 | 229 | 4,6 | -2,6% |
4,6 | 228 | 236 | 4,4 | -3,5% |
4,5 | 233 | 241 | 4,3 | -3,4% |
4,4 | 238 | 246 | 4,3 | -3,2% |
4,3 | 244 | 253 | 4,1 | -3,8% |
4,2 | 250 | 259 | 4,0 | -3,7% |
4,1 | 256 | 262 | 4,0 | -2,4% |
4,0 | 262 | 269 | 3,9 | -2,6% |
3,9 | 269 | 275 | 3,8 | -2,3% |
3,8 | 276 | 284 | 3,7 | -2,9% |
3,7 | 283 | 292 | 3,6 | -3,0% |
3,6 | 291 | 304 | 3,4 | -4,4% |
3,5 | 300 | 312 | 3,4 | -4,1% |
3,4 | 308 | 321 | 3,3 | -4,1% |
3,3 | 318 | 332 | 3,2 | -4,5% |
3,2 | 328 | 340 | 3,1 | -3,8% |
3,1 | 338 | 350 | 3,0 | -3,5% |
3,0 | 350 | 365 | 2,9 | -4,4% |
2,9 | 362 | 378 | 2,8 | -4,5% |
2,8 | 374 | 390 | 2,7 | -4,1% |
2,7 | 388 | 405 | 2,6 | -4,3% |
2,6 | 403 | 422 | 2,5 | -4,6% |
2,56 | 410 | 427 | 2,5 | -4,2% |
Vedete che gli errori sono abbastanza alti, ma una volta impostata una soglia è facile rilevare quando la batteria è scarica: è il momento in cui il modulo ACD fornisce un valore superiore a quello impostato (ricordo che man mano che la VDD scende, il valore letto aumenta).
Limitazioni
Il sistema è efficace ma ha chiaramente la limitazione di dover alimentare il PIC direttamente con la batteria da utilizzare senza frapporre regolatori di nessuna sorta, altrimenti la tensione di alimentazione è costante e il sistema non serve più a nulla. Con batterie fino a 5V è un buon sistema. Con una singola cella LiPO abbiamo un massimo di 4.2V ma anche questo può costituire una limitazione nel momento in cui dobbiamo, ad esempio, interfacciarci con dispositivi funzionanti a 3.3V. Insomma dovremo prevedere di utilizzare sullo stesso circuito dispositivi funzionanti alla stessa tensione in modo che la linea di alimentazione, man mano che si abbassa, influisca su tutti e quindi i livelli logici delle comunicazioni siano uguali per tutti. Se non ci sono dispositivi con cui comunicare, il problema non c’è o è decisamente minore. Non abbiamo nemmeno il problema di non poter leggere, ad esempio altri valori analogici: quando serve possiamo difatti cambiare il riferimento positivo del modulo ADC per portarlo su FVR (variando anche il guadagno se vogliamo), fare la nostra misurazione tenendo conto che il riferimento non è più VDD e quando abbiamo finito possiamo riportare tutto com’era.
Downloads
Il codice di esempio, disponibile su Github, l’ho realizzato su una scheda PIC16F15376 Curiosity Nano (già illustrata in un precedente articolo), utilizzando MPLAB Code Configurator. In particolare ho eseguito i settaggi per far funzionare modulo ADC e FVR come descritto in precedenza. Il Clock è settato a 8MHz e nella configurazione c’è il settaggio, relativo esclusivamente a questo modello di scheda, per far funzionare il PIC a 5V: condizione essenziale se volete testare il funzionamento di questo trucco è quello di alimentare il PIC dall’esterno, per cui, come specificato nel manuale della scheda in oggetto, dovete portare il pin VOFF a GND e quindi applicare la tensione esterna su VTG come ho anche puntualizzato al paragrafo Powering from external sul repo Github dove carico questi esempi.
Nel main ci sono solo un paio di funzioni per leggere l’ADC, che sono le funzioni fornite dal Code Configurator. Il valore rilevato viene inviato sulla seriale (disponibile come porta COM sull’USB della scheda) dal momento che ho utilizzato RD0 configurato come TX della UART2. RD0 è collegato alla ricezione CDC e ho ridirezionato STDIO sulla UART, come spiegato nell’articolo sulla curiosity nano in oggetto.
Nel codice ho impostato come valore di soglia 375, che in teoria corrispondono ad una tensione di alimentazione di 2.8V: quando il valore misurato è superiore a 375, viene acceso il led incluso sulla scheda.
Ringrazio ancora Gianfranco per la chiacchierata tecnica su questo argomento.
- Sorgente per MPLABX su Github
- AN1072 Microchip - Measuring VDD Using the 0.6V Reference (126 download)