Ed ora un’altro interessante progettino.
Dopo aver visto vari progetti in rete, soprattutto basati sui microcontroller PIC, ho deciso di realizzare un caricabatterie per batterie NiMh gestito da un’Attiny85.
Per quale motivo, penserà qualcuno, serve un microcontrollore per gestire la carica di una batteria. La risposta è molto semplice… La maggior parte dei caricabatterie economici che ci sono in commercio, regolano la carica basandosi su un timer, cioè se devo caricare una batteria da 2500mAh, forniscono una corrente di carica ad esempio di 250mAh, continuando la carica per ad esempio 14 ore (una parte dell’energia se ne va a quel paese, 10 ore non sarebbero sufficienti).
Questo modo di caricare le batterie al Nichel (Mh o Cd), non è tanto funzionale. In primo luogo è un processo lento, e poi non garantisce la corretta carica precisa al 100% delle celle, oltre a presentare rischi di sovrraccarica.
I caricabatterie di tipo “smart” in commercio invece, caricano le batterie correttamente, ma oltre ad essere abbastanza costosi, hanno solitamente correnti di carica non elevatissime, con tempi quindi non sempre sopportabili.
Da qui, oltre che la curiosità e la voglia di creare qualcosa di mio, nasce questo progetto…
Ma andiamo con ordine, e cominciamo con il il video che mostra il progetto finito ed in funzione:
Cerchiamo ora di capire un’attimo il funzionamento.
Innanzitutto le batterie al Nichel necessitano di una corrente costante per essere caricate correttamente. In questo caso si è utilizzato un generatore di corrente costante basato su transistor, derivato da quello che abbiamo visto in un post precedente, e fin qui niente di particolare, ma come facciamo a capire quando la batteria è carica?
Dobbiamo leggere continuamente la tensione della batteria sotto carica, e quando questa presenterà dopo un picco massimo di tensione, una discesa repentina di circa 20mv, la batteria potrà considerarsi carica. Tale fenomeno (chiamato Negative Delta V) è legato alla chimica di questa tipologia di batteria, e permette di stabilire con precisione il momento corretto per terminare la carica.
Vediamo quindi lo schema del circuito:
Lo schema è abbastanza semplice. Il transistor dalington Q1 (TIP127), tramite il LED1 (che deve essere assolutamente ROSSO) e la resistenza R3 da 0,3Ω, crea una corrente costante che scorre in direzione della batteria a 6 celle (7.2V), mentre il diodo Schottky 1N5822 da 3A, serve per proteggere tutto il circuito nel caso che venga a mancare la tensione di ingresso con la batteria connessa. Il partitore di tensione R4-R5, serve per portare alla porta 7 dell’Attiny (A1) il voltaggio della batteria diminuito a circa 1/3, in maniera tale che possa funzionare con tensioni sino a 15V (l’ingresso analogico dell’Attiny non può superare i 5V). Il transistor Q2, pilotato dalla porta 5 dell’Attiny (D0), serve come interrutore per attivare o disattivare il LED1 e il transistor Q1.
E’ fondamentale che il LED sia ROSSO, e questo non per una questione di estetica, ma perchè la potenza uscita è data dal rapporto tra la tensione del LED (nei led rossi è di circa 1,8-2,2V) e la resistenza R3. Usando un LED verde, la tensione di riferimento si alza, e di conseguenza anche la corrente si alza (e non di poco).
Il circuito così fornito, può erogare circa 1,5-2,5A, dovete eventualmente fare un po’ di prove con vari tipi di LED rosso, oppure variare la resistenza, che deve essere da 2W. Nel caso non abbiate a disposizione o non riusciate a trovare resistenze di valori così bassi, potete utilizzare 3 o 4 resistenze da 1Ω in parallelo.
Altra cosa da tenere in conto, è la potenza dissipata dal TIP127, che può arrivare anche a 20Watt (dipende dalla corrente e dalla differenza di tensione tra l’ingresso e la batteria), quindi va montato un dissipatore adeguato. Nel mio caso ho usato il case di alluminio che risulta essere sufficiente.
Ultimo appunto è il voltaggio di ingresso, che non deve essere troppo alto altrimenti si rischia di far bruciare il transistor, ma non deve essere nemmeno troppo basso, perchè altrimenti il dropout indotto dai vari componenti fa scendere troppo la corrente di carica. Consiglio all’incirca una differenza di circa 5V tra la tensione di ingresso ed il valore nominale della batteria. Ad esempio con 6 celle, il voltaggio consigliato è di 12,2V (va bene anche 12). Ovviamente si possono caricare anche meno celle, regolando opportunamente la tensione in ingresso. Per una cella, dovremmo alimentare il tutto con una tensione di circa 1,2+5 = 6,2V (va bene anche 6 o 7).
Vediamo ora il circuito stampato:
Da notare le due chicche che non erano visibili nello schema. Il connettore ICSP (quindi la possibilità di aggiornare il firmware sull’Attiny (via programmatore ad esempio UsbTinyISP), e il connettore debug, da collegare ad un convertitore TTL per potere leggere il voltaggio della batteria durante la carica.
Il connettore J1 invece è un jumper che deve essere sempre chiuso, tranne quando aggiorniamo il firmware dell’Attiny85.
A proposito di firmware… Il codice sorgente del firmware è il seguente:
/* NiMh Charger 0.9 con AtTiny85 @ 1Mhz by Luca Soltoggio 10/03/2012 - 20/04/2012 Usa il -dT per determinare la fine carica. Funziona con batteerie NiMh e NiCd. I valori di default sono per pacchi da 6 celle e 2500mAh Necessita di qualche aggiustamento hardware/software per parametri differenti. Vedi https://arduinoelettronica.wordpress.com/ */ const int inputPin = A1; const int outputPin = 0; const int numReadings = 30; // numero di letture analogiche prima di fare il check della batteria const int multi = 1614; // coefficiente di moltiplica per ottenere il voltaggio corretto dall'analogread long interval = 1000; // intevallo del pulse charge - non modificare long interval2 = 250; // intervalle pulse off - modificabile. Utlizzare 100 per 2-4Ah, 500 per 1-2Ah long interval2b=interval2; long previousMillis,currentMillis,currentMillis2,trickleMillis = 0; unsigned int readingtemp; unsigned int total = 0; unsigned int average,medium,maxmedium = 0; boolean executed,endcharge,trickle=false; // variabili di controllo unsigned int myarray [7]; // arrray che memorizza le ultime 7 letture int index,i = 0; void setup() { Serial.begin(9600); pinMode(0,OUTPUT); // Alcune letture per un controllo iniziale for (i=0;i<10;i++) { readingtemp = analogRead(inputPin); total=total+readingtemp; } average = (((float)total / 1023.0) * (float)multi) / 10.0 + 0.5; if (average<=70) endcharge=true; // Se la batteria non è presente, termina la carica Serial.println(average); total=0; average=0; } void pusharray() { // push dell'array for (i=0;i<=5;++i) { myarray[i]=myarray[i+1]; } myarray[6]=average; } void voltread() { readingtemp = analogRead(inputPin); // legge l'input analogico total= total + readingtemp; index++; // se è stato raggiunto "numReadings" calcola la media if (index==numReadings) { index=0; average = (((float)total / 1023.0) * (float)multi) / numReadings + 0.5; if (average<=70) endcharge=true; // termina la carica se la batteria viene scollegata total=0; pusharray(); // inserisce la nuova media nell'array // calcola la media delle ultime 7 letture medium=(float)(myarray[6]+myarray[5]+myarray[4]+myarray[3]+myarray[2]+myarray[1]+myarray[0])/7.0+0.5; if (medium>maxmedium) maxmedium=medium; // salva il valore della media più alta in "maxmedium" Serial.print(medium); Serial.print(","); Serial.print(maxmedium); Serial.print(","); Serial.println(myarray[6]); // se la batteria è carica (la media dei voltaggi è scesa di 0.02v), ma non nei primi 11 minuti if ( ((medium+1) < maxmedium) && ((millis()/60000)>=11) ) { if (!trickle) trickleMillis=millis(); // parte il timer per la "trickle charge" finale trickle=true; // parte la "trickle charge" finale // se la batteria si è caricata nei primi 15 minuti, non utilizzare la "trickle charge" finale // (probabilmente la batteria era già carica) if ((millis()/60000)<=15) endcharge=true; } } } void loop() { currentMillis = millis(); // esegui ogni "interval" millis if(currentMillis - previousMillis > interval) { voltread(); // chiama la funzione di lettura e controllo digitalWrite(outputPin,LOW); // ferma temporaneamente la carica previousMillis = currentMillis; executed=false; // variabile per controlloare se è già stata riattivata la carica // nei primi 10 minuti e negli utlimi 15 minuti effettua una "trickle charge" // (modifica il tempo di OFF) if ( ( (trickle) && (((millis()-trickleMillis)/60000)<15) ) || ((millis()/60000)<10) ) { interval2=(interval-(interval-interval2b)/5); // dopo la carica iniziale ripristina il valore corretto di interval2 } else if ((millis()/60000)>=10) interval2=interval2b; // alla fine dell'ultima "trickle charge" termina la carica if ( (trickle) && (((millis()-trickleMillis)/60000)>=15) ) endcharge=true; } currentMillis2 = millis(); // esegui "interval2" millis dopo aver fermato la carica if ((currentMillis2 - previousMillis > interval2) && (!executed)) { executed=true; if (!endcharge) { digitalWrite(outputPin,HIGH); // se la batteria non è carica, riabilita la carica } } }
Il codice è abbastanza semplice ed autoesplicativo.
Per la versione con i commenti in inglese – For commented English version, take a loke at:
http://fritzing.org/projects/smart-nimh-battery-power-charger-with-attiny85/
Concludo con qualche foto del progetto finito:
Trovi il mio progetto anche su Fritzing:
http://fritzing.org/projects/smart-nimh-battery-power-charger-with-attiny85/
Alla prossima!