Caricabatterie piombo 12V – Arduino

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.

Tabella verità 75451
Tabella verità 75451

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.

Tabella tensione/corrente
Tabella tensione/corrente

#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
}


Caricabatterie arduino

CaricaPb_TMS1638_V3.zip _ Sketch

12 Risposte a “Caricabatterie piombo 12V – Arduino”

  1. 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.

  2. Ciao, volevo realizzare il tuo caricabatterie, ma il file pubblicato non funziona, mancano dei pezzi. Potresti mandarmelo tramite email,
    Grazie.

  3. Hai ragione, la formattazione ha modificato il sorgente. l’ho modificato ed aggiunto lo sketch scaricabile (zippato). Grazie per la segnalazione.

  4. Buongiorno,
    non mi è chiara il valore di corrente che si usa per caricare la batteria.

    Grazie per l’eventuale risposta.
    Saluti
    Claudio

  5. salve ho costruito il caricabatterie, però non capisco l’uso dei pulsanti , come programmare la corrente etcc..
    potresti darmi qualche iustruzione?
    grazie

  6. 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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.