Ricaricare le batterie al piombo è un’operazione che viene gestita di solito in maniera molto, molto semplice: un trsformatore, un raddrizzatore, un carico in serie (lampadina, resistenza, amperometro) ed infine la batteria. Genericamente si considera di caricare la batteria ad una tensione grossomodo costante e lasciar fare alla batteria stessa il lavoro di “controllare” la corrente di carica. Se questo metodo è semplice e poco dispendioso ha come risvolto della medaglia che la batteria verrà caricata si, ma senza dubbio non nel migliore dei modi. Per ovviare a tale inconveniente è stato progettato questo circuito che analizza di volta in volta la tensione della batteria e conseguentemente adatta la corrente di carica per raggiungere una carica ottimale. Tale circuito utilizza il metodo PWM per variare la corrente nella batterie in base alla tensione presente sui morsetti della batteria stessa. Tale metodo permette di dissipare poca potenza sull’IGBT da 20A preposto a fare da interruttore. Il duty cycle dell’onda che comanda l’IGBT è regolato da un modulo arduino mini che a sua volta controlla sia la tensione sulla batteria che la corrente che vi circola. La resistenza da 0.3 Ohm in serie alla batteria realizza una caduta di tensione utile a leggere la corrente che scorre nella batteria. Formule alla mano, alla massima corrente per il quale il circuito è progettato (ovvero 5A*1.25=6.25A) sulla resistenza vi sarà una caduta di tensione di 1.875V. A tale corrente la resistenza dissiperà 11.7W. Nel circuito sono state utilizzate 4 resistenze da 0.3 Ohm e 3w in un misto serie-parallelo per distribuire uniformemente la potenza. L’ADC di arduino è a 10 bit, ovvero con 1024 “gradini” di lettura ognuno dei quali vale 5V/1024 ovvero ogni gradino rappresenta 0,00488 V (4,88 mV), una risoluzione più che sufficiente per i nostri scopi. Per “aggiustare” la lettura e leggere il corretto valore è necessario moltiplicare il valore letto dall’ADC per una costante di 3.333 dovuta la fatto che quando scorre 1A nella reistenza ai sui capi leggeremmo 0,3V (1A*0.3 Ohm). Moltiplicando per 3.333 i valori tornano in ordine. (Ovvero 1V di lettura per 1A di corrente). Per leggere invece la tensione della batteria, che supera i 5V massimi di “capienza” dell’ADC, si è reso necessario un partitore costituito da una resistenza da 10K ed un’altra da 4.7k. Tale partitore porta la tensione da 12V a 3.836V valore gestibile dall’ADC. Anche in questo caso sarà necessaria una costante di moltiplicazione che varrà 3.127 (3.836*3.127=12). La resistenza da 4.7K è in realtà composta da una fissa da 3.9K e da un trimmer da 1K per poter regolare correttamente la lettura ovviando alla sempre presente tolleranza dei componenti. In uscita arduino pilota l’IGBT passando da un driver apposito per MOS e altri carichi, denominato SN75451.
Tale driver ha al suo interno due circuiti identici che noi utilizziamo in parallelo per aumentarne le prestazioni. Tale integrato è in pratica sintetizzato come un AND di potenza. L’iGBT finale che controlla la carica è ad alta potenza e si chiude quando sul gate è presente una tensione positiva di almeno ..V. Dal momento che viene pilotato da un AND quando in uscita su arduino si avrà un 1 l’IGBT condurrà (ovvero avremo un “1” sulla batteria) al contrario otterremo uno “0” (nessuna tesnione sulla batteria). Grazie a questo fatto la tensione (e quindi la corrente) sulla batteria sarà direttamente proporzionale al duty cycle del PWM in uscita da arduino. Il codice analizza la tensione (a vuoto) della batteria ed in base al valore rilevato procede ad impostare la corrente coerentemente con il valore di carica impostato. In ingresso al circuito servono una ventina di V circa. Completa il tutto un modulo TM1638 per la selezione e la visualizzazione.
#include "TM1638.h" #define CSV 1 // Costanti per il partitore di tensione (10k+4,9k) // current sense=0.3Ohm const float MoltiplicatoreTensione = 3.127 * 0.00488; const float MoltiplicatoreCorrente = 3.333 * 0.00488; const byte TEST_BUTTON = 0b10000000; const byte DESULF_BUTTON = 0b01000000; const int PULSE_DELAY = 3000; // mS const int DROP_DELAY = 1000; // mS const int NORMAL_DELAY = 500; // mS const int NUM_SAMPLES = 5; const byte LED_AMPERE = 7; const byte STATE_CHARGING=1; const byte STATE_CHARGED=2; const byte STATE_DROP=2; // define a display/led/buttons module on data pin 8, clock pin 9 and strobe pin 7 TM1638 module(8, 9, 7); // Variabili boolean isTest = false; int CorrenteSelezionata = 1; // Start at 4A float Corrente=1; boolean DesolfState = false; int LastPWM = 127; int State = 0; float lastVoltage1; float lastVoltage2; float lastCurrent; // define amperes led pins int I1Led = 0; int I2Led = 1; int I3Led = 2; int I4Led = 3; int I5Led = 4; // define outputs int DesolfRelay = 2; // where desolf relay work int PWMOut = 11; // Output for pwm // define analog inputs int VBattery = A1; // analog input for voltage sense int ChargeCurrent = A0; // analog input for current sense String Display; // Message for display charging type (fast, trickle, etc...) // Clear all currents leds void AzzeraBattLed() { for (int i=0; i<5; i++) { module.setLED(TM1638_COLOR_NONE, i); } } // convert a decimal float to a string needed to print it on display String Float2String(float n, int ndec) { String r = ""; int v = n; r = r + v; // whole number part r = r + '.'; // decimal point for (int i=0; i < ndec; i++) { // iterate through each decimal digit for 0..ndec n = n - v; n = n * 10; v = n; r = r + v; } return r; } // It wait for no-button press void WaitNoButtons() { while (module.getButtons() != 0) { } } // Do a tDelay*10 mS delay and return immediately if a button is pressed void myDelay(int tDelay) { for (int i=0; i < tDelay/10; i++) { delay(10); if (module.getButtons()!=0) { return; } } } // Read a defined analog input and return value multiplied with Moltiplicatore. // Also print value to serial if Msg<>"" // This routine do a median on five measure (5) to reduce reading error float LeggeAnalogico(String Msg, int Input, float Moltiplicatore, float &lastValue) { //Serial.print(">"); //Serial.println(lastValue); float dummyRead=lastValue; do { lastValue=dummyRead; dummyRead=0; for (int i=0; i < NUM_SAMPLES; i++) { dummyRead+=analogRead(Input)*Moltiplicatore; } dummyRead=dummyRead/NUM_SAMPLES; } while ((dummyRead<(lastValue-lastValue/20)) || (dummyRead>(lastValue+lastValue/20))); // if value is outside +/-20% of last lecture then the loop is repeated lastValue=dummyRead; //Serial.print("<"); //Serial.println(lastValue); if (Msg!="") { Serial.println("**********************************************"); Serial.print(Msg); Serial.println(dummyRead); Serial.print("LastPWM: "); Serial.println(LastPWM); Serial.println("**********************************************"); delay(10); } return dummyRead; } // the setup routine runs once when you press reset: void setup() { module.setupDisplay(true,4); // Activate display and set intensity to 4 pinMode(DesolfRelay, OUTPUT); pinMode(PWMOut, OUTPUT); digitalWrite(PWMOut, LOW); // Off PWM digitalWrite(DesolfRelay, LOW); // Off desulf module.clearDisplay(); module.setLED(TM1638_COLOR_RED, CorrenteSelezionata-1); // set Led for Selecte current Serial.begin(9600); State=STATE_CHARGING; #ifdef CSV Serial.println("Metodo;Stato;LastPWM;Corrente Selezionata;Corrente Impostata;Tensione a vuoto;Tensione di carica;Corrente di carica"); #endif lastVoltage1=0; lastVoltage2=0; lastCurrent=0; } // the loop routine runs over and over again forever: void loop() { float LeggeBatteria; // It contain the battery voltage float CorrenteLetta; // It contain charging current String MisuraTensione; // Value of voltage converted to string String MisuraTensioneVuoto; // Value of voltage converted to string String MisuraCorrente; // Value of voltage converted to string // PMW OFF. It allow to measure real battery voltage in idle state digitalWrite(PWMOut, LOW); // off PWM byte Buttons=module.getButtons(); // Mode Test battery trimmer regulation // if button 7 is pressed then Arduino enter in voltage measurement state // it allow to regulate trimmer to display correct voltage value if ((Buttons == TEST_BUTTON) || (isTest==true)) { LeggeBatteria=LeggeAnalogico("Test Volt: ", VBattery, MoltiplicatoreTensione, lastVoltage1); MisuraCorrente= Float2String(LeggeBatteria,1); module.setDisplayToString("Volt" + MisuraCorrente); delay(10); if (Buttons == TEST_BUTTON) { isTest=!isTest; if (isTest==false) { module.clearDisplay(); module.setDisplayToString("Waiting"); } WaitNoButtons(); } return; } // Read desolf button if (Buttons == 0b01000000) { DesolfState=!DesolfState; if (DesolfState==true) { module.setLED(TM1638_COLOR_RED, 6); digitalWrite(DesolfRelay, HIGH); } else { module.setLED(TM1638_COLOR_NONE, 6); digitalWrite(DesolfRelay, LOW); } WaitNoButtons(); } // Read current button if ((Buttons<=0b00010000) && (Buttons>=0b00000001)) { AzzeraBattLed(); switch (Buttons) { case 0b00000001: CorrenteSelezionata=1; module.setLED(TM1638_COLOR_RED, I1Led); break; case 0b00000010: CorrenteSelezionata=2; module.setLED(TM1638_COLOR_RED, I2Led); break; case 0b00000100: CorrenteSelezionata=3; module.setLED(TM1638_COLOR_RED, I3Led); break; case 0b00001000: CorrenteSelezionata=4; module.setLED(TM1638_COLOR_RED, I4Led); break; case 0b00010000: CorrenteSelezionata=5; module.setLED(TM1638_COLOR_RED, I5Led); break; } WaitNoButtons(); } // Read if battery is connected // Do a little delay to stabilize the measure if (State==STATE_CHARGING) { myDelay(NORMAL_DELAY); } else { myDelay(DROP_DELAY); } //LeggeBatteria=LeggeAnalogico("Volt: ", VBattery, MoltiplicatoreTensione); LeggeBatteria=LeggeAnalogico("", VBattery, MoltiplicatoreTensione, lastVoltage1); MisuraTensioneVuoto = Float2String(LeggeBatteria,1); // If no battery or battery to weak then no battery displayed and no PWM allowed. if (LeggeBatteria<1) { State=STATE_CHARGING; module.setDisplayToString("no batt",0); return; } // If battery voltage is lower than 7,5v and Desulf state is on // then do a desulfuration charge if (LeggeBatteria<7.5) { if (DesolfState==true) { Display="dSLF"; Corrente=1; } else { Display="WEAK"; MisuraTensione=Float2String(LeggeBatteria,1); module.setDisplayToString(Display + MisuraTensione); return; // No battery } } // If battery voltage is from 7.5 to 10.4 then current is Selected current/3.75 // always. if (State==STATE_CHARGING) { if ((LeggeBatteria>=7.5) && (LeggeBatteria<10.5)) { // Fase Fast iniziale Display="INIT"; Corrente=CorrenteSelezionata/3.75; } // If battery voltage is from 10.5 to 12.7 then current is // multiplied for 1.25 if ((LeggeBatteria>=10.5) && (LeggeBatteria<12.8)) { // Fase Fast carica Display="FAST"; Corrente=CorrenteSelezionata*1.25; } // If battery voltage is from 12.8 to 14.0 then current // selected is flowed to realize a normal charge if ((LeggeBatteria>=12.8) && (LeggeBatteria<14.1)) { // Fase carica Display="CHRG"; Corrente=CorrenteSelezionata; } // If battery voltage is from 14.1 to 14.4 then current is Selected current/3.75 // for last charge step if ((LeggeBatteria>=14.1) && (LeggeBatteria<14.4)) { State=STATE_CHARGING; // Ultima fase Display="LAST"; Corrente=CorrenteSelezionata/3.75; } } else { // If Voltage drop over 14V then repeat charging steps if (LeggeBatteria<14) { Display="DROP"; Corrente=CorrenteSelezionata/3.75; State=STATE_DROP; } } if (LeggeBatteria>=14.4) { State=STATE_CHARGED; Display="OK "; Corrente=0; } // Start pwm with last knowed pwm value analogWrite(PWMOut, LastPWM); myDelay(100); // Read current //CorrenteLetta=LeggeAnalogico("Lettura Ampere ingresso-: ", ChargeCurrent, MoltiplicatoreCorrente); // Current is regulated to reach the correct value. // if higher then decrease pwm time. Exit when reached if (Corrente!=0) { CorrenteLetta=LeggeAnalogico("", ChargeCurrent, MoltiplicatoreCorrente, lastCurrent); while (CorrenteLetta>=Corrente) { if (LastPWM>1) { LastPWM--; analogWrite(PWMOut, LastPWM); } else { break; }; delay(10); CorrenteLetta=LeggeAnalogico("", ChargeCurrent, MoltiplicatoreCorrente, lastCurrent); } // if lower then increase pwm time. Exit when reached while (CorrenteLetta<Corrente) { if (LastPWM<255) { LastPWM++; analogWrite(PWMOut, LastPWM); } else { break; }; delay(10); CorrenteLetta=LeggeAnalogico("", ChargeCurrent, MoltiplicatoreCorrente, lastCurrent); } } else { digitalWrite(PWMOut, LOW); // Off PWM } // Display step of charge and voltage (voltage previously readed when pwm disconnected) module.setDisplayToString(Display + MisuraTensioneVuoto); // lite off current information led module.setLED(TM1638_COLOR_NONE, LED_AMPERE); //CorrenteLetta=LeggeAnalogico("Lettura Ampere uscita+: ", ChargeCurrent, MoltiplicatoreCorrente); CorrenteLetta=LeggeAnalogico("", ChargeCurrent, MoltiplicatoreCorrente, lastCurrent); LeggeBatteria=LeggeAnalogico("", VBattery, MoltiplicatoreTensione, lastVoltage2); LeggeBatteria=LeggeBatteria-CorrenteLetta*0.3; // Subctract voltage fall onto 0.3 ohm resistor myDelay(PULSE_DELAY/2); if (module.getButtons() != 0) return; MisuraTensione=Float2String(LeggeBatteria,1); module.clearDisplay(); MisuraCorrente = Float2String(CorrenteLetta,1); // Display step of charge and the readed current module.setDisplayToString(Display + MisuraCorrente); // lite on current information led module.setLED(TM1638_COLOR_RED, LED_AMPERE); myDelay(PULSE_DELAY/2); #ifdef CSV Serial.print(Display + ";"); Serial.print(State); Serial.print(";"); Serial.print(LastPWM); Serial.print(";"); Serial.print(CorrenteSelezionata); Serial.print(";"); Serial.print(Corrente); Serial.print(";"); Serial.print(lastVoltage1); Serial.print(";"); Serial.print(LeggeBatteria); Serial.print(";"); Serial.println(CorrenteLetta); #else Serial.println("Metodo:" + Display); Serial.print("Stato: "); Serial.println(State); Serial.print("LastPWM: "); Serial.println(LastPWM); Serial.print("Corrente selezionata: "); Serial.println(CorrenteSelezionata); Serial.print("Batteria a vuoto: " + MisuraBatteriaVuoto); Serial.println("Volt durante ricarica:" + MisuraBatteria); Serial.println("Corrente di carica:" + MisuraCorrente); Serial.println("****************************************************"); #endif }
Molto molto interessante dovrei realizzare un sistema di ricarica batterie. 5 da 80Ah. Sfruttando 6 pannelli solari le batterie dovranno essere caricate separatamente a gruppi di. 2 2 e 1. Ogni gruppo dovra utilizzare 2 pannelli. Pensavo di prenderere la tua idea di ricarica in PWM con arduino ma non trovo lo schema.
Ho aggiunto lo schema. Grazie per la segnalazione.
Ciao, volevo realizzare il tuo caricabatterie, ma il file pubblicato non funziona, mancano dei pezzi. Potresti mandarmelo tramite email,
Grazie.
Hai ragione, la formattazione ha modificato il sorgente. l’ho modificato ed aggiunto lo sketch scaricabile (zippato). Grazie per la segnalazione.
SCUSA LA MIA IGNORANZA MA LA BATTERIA FISICAMENTE A QUALE MORSETTI DEL TUO SCHEMA ANDREBBE COLLEGATA?
Potresti lasciarmi la lista dei componenti utilizzati, alcuni nello schema non sono molto chiari per me. Grazie!!!
Cosa non ti è chiaro?
Buongiorno,
non mi è chiara il valore di corrente che si usa per caricare la batteria.
Grazie per l’eventuale risposta.
Saluti
Claudio
Solitamente si sceglie una corrente di circa 1/10 della capacità della batteria.
P1 +
P3 –
salve ho costruito il caricabatterie, però non capisco l’uso dei pulsanti , come programmare la corrente etcc..
potresti darmi qualche iustruzione?
grazie
La corrente va impostata (con i primi 5 pulsanti) ad 1/10 della capacità della batteria da caricare, i valori di corrente sono 1, 2, 3, 4, 5 A