Misurare una batteria con Arduino e il partitore di tensione

Ciao a tutti!

Il post tratta di un argomento piuttosto semplice che però può tornare utile in vari progetti,
soprattutto se alimentati a batteria.
Infatti una funzione molto utile è monitorizzare lo stato della batteria per avvisarci in qualche modo del fatto che la batteria sta per terminare.



Come tutti ben saprete ogni ingresso analogico di Arduino può leggere un valore di tensione che va da 0 a 5 Volt, valore che poi viene convertito in digitale in un numero che va da 0 a 1023.
Sarà sufficiente una semplice proporzione con la funzione map per ricavare la tensione della batteria.




Quindi leggere con Arduino il valore di tensione di una batteria da 1.5 Volt è molto semplice in quanto la batteria potrà essere collegata direttamente ad un pin analogico.
Ma come facciamo a monitorare una batteria con una tensione maggiore di 5 Volt?


La risposta è anche qui semplice, è sufficiente realizzare un partitore di tensione.


Da Wikipedia:
"Un partitore di tensione è una tipologia di circuito costituito da due o più componenti passivi collegati in serie ai capi dei quali se viene applicata una tensione, essa si ripartirà sulle stesse componenti in base al loro valore."






Se le 2 resistenze hanno lo stesso valore, la tensione si ripartirà allo stesso modo su entrambe le resistenze, ad esempio:





Verifichiamo quanto detto sopra con questa formula:


Vout = Vin * R2 / (R1 + R2)


nell'esempio:

Vin = 9v
R1 = 10k
R2 = 10k

quindi:

9 * 10'000 / 20'000 = 4.5v  (valore di tensione accettabile dalle porte analog in di Arduino)

.
Da questa formula posso utilizzare anche la seguente formula inversa, necessaria ad esempio se volessi ottenere 4v da una batteria da 12v dovrei calcolare:


R2 = Vout / Vin * (R1 + R1)


Decidendo un valore di R1 + R2 = 20 kohm (valore che permette un passaggio di corrente ne troppo piccolo ne troppo grande) posso calcolare:

R2 = 4 / 12 * (20'000) = 6666.6 Ohm (approssimabile al valore commerciale 6.8 kOhm)

Quindi R1 = 20'000 - 6666.6 = 13333.4 Ohm (approssimabile a 12 kOhm)


Per ricalcolare ora quanta tensione cadrà con le resistenze che ho scelto:


V1 = I * R1

V2 = I * R2


dove:


I = Vin / (R1 + R2)


= 12 / 18'800

= 0.000638 Ampere (0.638 mA)


Quindi V1 = 0.000638 * 12000 = 7,656 V

e V2 = 0.000638 * 6800 = 4.338 V



Individuati i valori di resistenza da utilizzare vediamo finalmente come collegare il nostro circuito ad Arduino:




e questo è lo sketch da caricare:


  1. int PinBatt = A0;  
  2. int ValPinBatt;
  3. float Vpin_perc;
  4. float Vbatt;  
  5. float calc_res;
  6. float R1 = 10000; //modificare questi valori con i valori realmente utilizzati.
  7. float R2 = 10000;
  8. void setup()
  9. {
  10.   Serial.begin(9600);
  11.   pinMode (PinBatt, INPUT);
  12.   calc_res = (R1 + R2) / R2;
  13. }
  14. void loop()
  15. {
  16.   ValPinBatt = analogRead(PinBatt);
  17.   Vpin_perc = map (ValPinBatt, 0, 1023, 0, 500);
  18.   //leggerò 1023 quando ho 5 volt sul pin, quindi scalo 0-1023 in 0-500.
  19.   Vbatt = Vpin_perc * calc_res / 100 ;  
  20.   //ora divido tutto per 100 perchè sopra ho scalato da 0 a 500 anzichè da 0 a 5V
  21.   Serial.print("Tensione batteria:");
  22.   Serial.println(Vbatt);                
  23. }


Modificate i valori di R1 e R2 con quelli realmente utilizzati, poi aprite il Serial monitor per leggere la tensione della batteria.
Ricordate che una tensione maggiore di 5v potrebbe danneggiare il vostro Arduino, se avete dubbi misuratela prima con un voltmetro.

Se qualcosa non è chiaro lasciate pure un commento qui sotto,
Ciao!

Seguimi sulle mie pagine per rimanere sempre aggiornato sui nuovi post!

31 commenti:

  1. Innanzitutto grazie per le utilissime informazioni. Questo è il mio setup: Arduino uno con partitore di tensione 15kΩ e 6,8kΩ, per ottenere un Vin di massimo a 14.4V e un Vout di 4,5V, e un Vin di 11,8 con Vout di 3,7V. Ho impostato i valori di R1 e R2 e inizialmente il valore di Vin della batteria non corrisponde con il seriale. Ho percui cambiato nella mappatura il valore con cui scalare 0-1023 da 500 a 490 e adesso è perfetto.
    Avrei qualche domanda:
    1) perché cambiando il valore da 500 a 490 il risultato cambia?
    2) Vorrei poter attivare due pin a due determinati valori di voltaggio della batteria, che sono 11,8- high e 12,8 va in low. I pin dovrebbero comandare un semplice relay da 5v. Ho provato diversi metodi, ma non riesco a fa funzionare correttamente l'uscita dei pin.
    Se qualcuno può aiutarmi mi farebbe un enorme favore.

    RispondiElimina
    Risposte
    1. Ciao, grazie per il complimento!
      Per la prima domanda effettivamente Arduino si perde un decimo di volt, si dovrebbe riuscire a risolvere utilizzando il pin "Aref", oppure mappando a 490 come hai fatto tu. Il risultato cambia perché il "map" funziona come una semplice equazione, quando hai 1023 (diciamo 5v) il valore viene scalato a 500, se hai 4v il valore sarà circa 800. Ma se al posto di 500 metti 250 allora i valori di uscita verranno tutti dimezzati.
      Per la seconda domanda é sufficiente fare un if, se V é maggiore di 11.8 e minore di 12.8, porta alto il pin, se V é maggiore di 12.8 portalo basso.
      Ciao!

      Elimina
    2. Grazie mille per la spiegazione. Ho creato un if ottenuto da una media di 10 rilevazioni sulla tensione (in realtà sul pin analogico), ho aggiunto un delay che controlli che la tensione sia stabile prima di attivare il relay. Funziona tutto perfettamente. Non so se sia un codice ottimizzato ma funziona..
      Media A0 ottenuta tramite buffer.

      if (digitalRead(Relay))
      {
      if (Media_A0 < 594) // se media è minore di 594 che corrispondono a 11,8v.
      {
      if (millis() - delayTime > 10000) // per almeno 10 secondi
      digitalWrite(Relay, LOW); // stacca relay
      }
      else // altrimenti se tensione sopra soglia
      delayTime = millis(); // insegue contatore millis()
      }
      else
      {
      if (Media_A0 > 644) // se media è maggiore di 644 che corrispondono a 12,8v.
      {
      if (millis() - delayTime > 10000) // per almeno 10 secondi
      digitalWrite(Relay, HIGH); // attacca relay
      }
      else // se tensione sotto soglia
      delayTime = millis(); // insegue contatore millis()
      }

      Elimina
    3. Grazie mille a te per aver condiviso il tuo codice, sicuramente potrà tornare utile a molti.
      Ciao!

      Elimina
    4. Ciao ho un problema in cui mi sono bloccato. vorrei far suonare un buzzer in due momenti precisi. Il primo suono dovrebbe avvenire quando sul pin analogico c'è meno di 540 ( dovrebbe fare 3 suoni veloci di 500ms distanziati da 1000ms) e il secondo dovrebbe suonare quando sul pin analogico c'è meno di 490 (dovrebbe fare 5 suoni lenti da 800ms distanziati da 1200ms)
      Il buzzer l'ho impostato cosi:
      Tone(buzzer, 2000, 500);
      Il problema è che se anche riesco a farlo suonare ad un determinato momento di lettura del pin analogico non riesco a fargli fare 3 suoni. Sicuramente devo creare un if else per farlo suonare ad un determinata lettura dell'analogico, e lavorare con millis() per fargli fare i 3 suoni e poi farlo fermare, ma anche partendo da uno sketch nuovo simulando il pin analogico con un potenziometro, non riesco a fargli fare 3 suoni distinti, e se per caso ci riesco attraverso i millis() non riesco a farlo fermare dopo i 3 suoni e continua all'infinito, anche usando la funzione noTone()
      Qualche idea??

      Elimina
  2. Ciao e grazie! Sto cercando di usare questo progetto con arduino mega 2560 solo che mi riporta dei valori più alti, sai dirmi per caso se l'analogRead di arduino uno è diverso da arduino mega 2560? grazie in anticipo

    RispondiElimina
    Risposte
    1. Ciao, prova a misurare con un tester la tensione sul pin Analogico, e guarda se corrisponde. Ciao!

      Elimina
    2. Ciao, è passato molto tempo da quando ho usato il tuo bellissimo progetto e alla fine ho risolto con delle soglie calcolate in precedenza. ora però banalmente non riesco a calcolare il voltaggio di una power bank da 5v collegata direttamente al pin A6 di arduino nano. Sai dirmi come mappare i valori?
      grazie

      Elimina
    3. Ciao, ti consiglio di fare un partitore con 2 resistenze da 10k come nella prima figura, in questo modo puoi misurare i tuoi 5 volt.

      Elimina
  3. Scrivo solo per ringraziarti delle guide, gira che ti rigira capito sempre quì a farmi un'idea chiara. Buon lavoro

    RispondiElimina
  4. Ciao Daniele,
    È già la seconda volta che "capito" sul tuo sito alla ricerca di informazioni...
    Intanto grazie per condividere in modo chiaro e dettagliato...
    Se posso vorrei chiederti aiuto per monitorare un pacco 3s formato da delle 18650...
    Se gentilmente puoi implementare quanto già scritto sopra con degli schemi e relativo codice...
    Spero di non averti chiesto troppo...
    Grazie mille Roberto

    RispondiElimina
    Risposte
    1. Ciao Roberto, una batteria al litio ha una tensione nominale di 3.7v, un pacco da 3 celle é quindi da 11.1 (3.7 x 3). Quindi sei fortunato perché rientri nel secondo esempio (R2 da 6.8k e R1 da 12k) sostituisci poi i valori nello sketch come spiegato nel tutorial. Ciao!

      Elimina
  5. Ciao Daniele,
    grazie mille per la veloce risposta...
    la mia intenzione sarebbe quella di "controllare" le 3 singole celle, dato che ho letto che può succedere (magari sono casi limite ma meglio essere cauti) che una cella si "sbilanci" e che si danneggi o peggio ancora...

    cosa ne pensi è una soluzione troppo "drastica"?
    grazie ancora
    Roberto

    RispondiElimina
  6. Ciao e complimenti per i tuoi progetti. Io vorrei alimentare arduino con una batteria 9V, ma mi servirebbe poi controllare la carica della batteria. Come è possibile utilizzare il esempio?
    Grazie per una tua eventuale risposta.

    RispondiElimina
    Risposte
    1. Ciao, grazie per i complimenti.
      Semplicemente alimenta Arduino collegando la batteria al jack di alimentazione, e poi la misuri come mostrato nell'esempio

      Elimina
  7. Ciao! Leggendo il tuo articolo mi è venuto un dubbio.. Io uso arduino alimentato direttamente da un pacco batterie sul pin 5V; posso testare la carica di un’altra batteria su un’altro pin? O rischio di rovinare la scheda?
    Ciao e grazie!

    RispondiElimina
    Risposte
    1. Ciao, nessun problema, ricordati solo di collegare il gnd della batteria insieme a quello di Arduino e di scegliere il valore corretto delle resistenze

      Elimina
  8. Questo commento è stato eliminato dall'autore.

    RispondiElimina
  9. Ciao, causa passaggio a linea telefonica digitale sto cercando di costruire un combinatore gsm con Arduino da interfacciare alla mia centrale di allarme.La centrale sembra comunicare un evento di allarme al combinatore togliendo la tensione su una linea a 12V. Dovrei dunque individuare quando i 12V vengono a mancare per inviare l' sms utilizzando un pin di arduino.Ritieni sia possibile farlo utilizzando il partitore di tensione con due resistenze o rischio di bruciare tutto? se si quale valore di resistenze mi consigli di usare ? grazie

    RispondiElimina
  10. Ciao, ho provato il tuo sketch per analizzare un pacco batterie, io però prelevo il segnale da un partitore fatto da tre resistenze da 10K in modo che ValPinBatt sia 1/3 Vbatt, ho provato ma non mi sono capito, cosa devo cambiare per avere i dati esatti. Grazie

    RispondiElimina
    Risposte
    1. Ciao, devi cambiare R1 e R2 all'inizio dello sketch, io ho messo 10000(10k) entrambe, tu metterai 20000 e 10000

      Elimina

    2. Ciao e grazie della risposta, ho provato ma ho il risultato di 13,41v quando in realtà sono 12,61v cosa modifico

      Elimina
  11. Questo commento è stato eliminato dall'autore.

    RispondiElimina
  12. Salve, prima di tutto grazie per i tuoi post, molto chiari e dettagliati. Pongo il mio problema premettendo che sono 0 in elettronica! Spiego il mio problema, dovrei controllare la tensione di un pacco batterie al litio 14s30p fatto in casa (con le 18650), tra ieri ed oggi sono riuscito utilizzando arduino mega a controllare la tensione di due celle singole non collegate in serie tra loro e son riuscito ad inviare i valori della tensione al server mosquitto del mio hub homeassistant, pensavo di aver risolto il problema invece facendo due conti mi son reso conto che non posso collegare tutte e 14 le serie singolarmente in quanto arduino dispone si di 16 pin analogici ma di un'unica GND in comune! La soluzione sarebbe quella di utilizzare 13 partitori di tensione per la 2°.... fino alla 14° serie ed un unico collegamento GND al negativo del pacco batterie, in questo modo con un po di formule potrei rilevare la tensione di ogni singola serie, pero avrei un po di difficolta nel scegliere le resistenze corrette ed ho paura che otterrei dei margini di errore troppo elevati. Mi chiedo se esiste un'altro metodo ad esempio utilizzando dei diodi e collegando sia positivo che negativo di ogni serie rispettivamente sui pin A0...A13 e GND?

    RispondiElimina
    Risposte
    1. Ciao Luca, quella dei partitori mi sembra l'unica soluzione con pochi componenti, altrimenti potresti montare degli optoisolatori tra le celle in modo da poterti poi riferire in uscita ad un unico gnd, ma anche in questo caso la linearità dei fotoaccoppiatori ti farà perdere di precisione.

      Elimina
  13. Ciao Daniele, ho bisogno del tuo supporto :)

    Sto utilizzando una wemos d1 mini lite, il cui pin analogico a0, ammette una tensione massima di 3.2v. Devo monitorare una batteria al litio da 3.7 nominale, la cui tensione a carica massima è di 4.27v ( utilizziamo il valore 4,22v che quello che ho al momento nella batteria )

    Utilizzo due resistenze da 100k e applicando la formula mi aspetto che che la tensione che arrivi al pin sia di 2,11v. Faccio le misurazioni in un circuito senza il microcontrollore ed effettivamente la misura sulla seconda resistenza mi da 2,09v ( direi che ci siamo ); poi faccio le misurazione collegando il pin a0 con il punto in cui si uniscono le due resitenza e ed il gnd e mi da 1,815v e già questo non me lo spiego. In cascata anche il codice utilizzato mi restituisce una tensione non corretta


    int r1 = 100000;
    int r2 = 100000;
    float calc_res = (r1 + r2) / r2;
    int valPinBatt = analogRead(pinBatteria);
    float tensione_scalata = map(valPinBatt, 0, 1023, 0, 320);
    float Vbatt = tensione_scalata * calc_res / 100;
    Serial.print("Lettura = ");
    Serial.print(valPinBatt);
    Serial.println();
    Serial.print("Tensione scalata = ");
    Serial.print(tensione_scalata);
    Serial.println();
    Serial.print("Batteria = ");
    Serial.print(Vbatt);
    Serial.println(" V");

    Mi puoi dare una mano ?

    RispondiElimina
    Risposte
    1. Ciao, 100k (200k in totale) è un valore piuttosto alto di resistenza.
      Significa che la corrente che transita è molto bassa. Anche dal pin del wemos transita una corrente molto bassa che nel tuo caso può influenzare la misurazione.
      Ti consiglio di mettere 2 resistenze da 10k ad esempio

      Elimina
  14. Complimenti per la spiegazione, da neofita ho provato ed è funzionato al primo colpo, vorrei chiederti se fosse possibile controllare la tensione di 3 batterie con 1 solo Arduino uno, grazie ancora

    RispondiElimina
    Risposte
    1. Ciao, grazie per i complimenti!
      Si dato che Arduino Uno ha 6 ingressi analogici (A0-A5), puoi replicare il tutto per misurare 6 batterie indipendenti

      Elimina
  15. Si ho capito come abbassare tensinone per entrata pin analogico e portare 5 v su Arduino ma poi per leggere la tensinone reale quale è sketch da scrivere e soprattutto come correggere

    RispondiElimina

Lascia un commento qui sotto, ti risponderò il prima possibile!

Altri Post