SALES INQUIRIES: 1 (888) 767-9864

Building my First Arduino Controlled Battery Charger :: Student Project

This project was built by one of our long time students, Roland.  I am always impressed by the projects I see submitted, and this one is truly stellar.  He has brought a ton of talent, time and dedication to make this happen.  I am excited to see it posted here.  

This battery charger can charge 6-12 Volt Lead Acid batteries and has an LCD for display relevant charge data.

Roland was also very kind to walk through the design process, provide the code he used and supply some great pictures – please enjoy!

Requirements for the Charger and Basic Design

My solar panel system has a 24V battery-bank, consisting of 4x 6V 225Ah Trojan open Lead Acid deep-cycle batteries.

In the summertime, they get charged via a Victron MultiPlus inverter / charge-controller. In the winter, to keep the batteries “topped-up”, I needed a “powerful” sophisticated charger which can do one battery individually, or two batteries in series.

The charger needed to be able to perform all the three charge-stages required for a Lead-Acid battery; Absorption-charge, Equalization-charge and Float-charge (Check at the bottom of this post for some highly recommended reading about Lead-Acid-Battery charging)

The donor for my project was an old 6-12V “dump-charger”.

Enclosure used for Arduino Controlled Battery Charger

Since I’m far from a qualified electrical engineer, I had to search for schematics. The basis for the electronic-schematic was found on Lewis Loflins website.

A big “Thank You” to Lewis! Please visit his website to learn in-depth how the circuitry works. Lewis does an outstanding job explaining the nitty-gritty details.

Different from the Lewis design (he used solar panels as a power-source) is that a conversion to a grid-power-source was needed.

An Arduino Mini Pro ATMega 328 was chosen for the project, small and cheap to build in. The circuitry and sketch currently presented is developed after several builds and learnings derived from mistakes / practical problems.

Challenges, Experimenting, and Learning Along the Way

One of my first prototype attempts failed because I wasn’t paying attention to the internal resistance (Rds On) of the Mosfet used.

The power-Mosfet I had laying around had a Rds On of 4 Ohm. With a current of 7 – 8 Ampere, the waste heat:

P= I2*R = 8*8*4 = 256 Watt!

The Mosfet in the circuitry, the IRF4905, has a Rds On of 0.02Ω.  The waste heat is now P = 8*8*0.02 = 1.28 Watt – a substantial difference!

A major problem in building my charger turned out to be the power-supply, and everything depending on it, i.e the Arduino.

I chose to power the Arduino from the main DC power-rail (see schematic 2 of 4), which was (with no load) either around 11VDC, or 22VDC, depending which charge voltage was chosen.

Schematic 2 of 4 for the Arduino Controlled Battery Charger

The maximum voltage which can be applied to the L7805 (TO-220 package), 5V linear voltage regulator is 35Volt.

A 6V battery has, depending of the Depth-of-Discharge (DOD) an open circuit voltage of about 5.75V when fully discharged and 6.37V when fully charged.

Connecting a 6-Volt battery to the transformer causes the voltage in the main DC power-rail to drop to whatever the voltage of the battery is.

Of course, if you have a transformer as big as your home, it may be different, but we are talking normal-size, like 150 – 200VA transformers.

Besides the voltage-drop caused by the battery, the power-source is AC, meaning that 100x (@50Hz) or 120x (@60Hz) per second, it goes to zero.

The dropout voltage, the voltage needed by the L7805 to deliver a constant 5V output, is about 6.5Volt.

Anything below the drop-out voltage, and the 5Volt output drops / fluctuates accordingly.

Using big electrolyte capacitors can partially dampen the AC factor, but not much can be done to the main DC power-rail voltage drop caused by the battery.

The Arduino Mini Pro seemed to work fine with voltages below 5V, but since any analogRead depends on a stable input Voltage, or reference Voltage, all analog Voltage- and current-readings obtained via voltage dividers and a ACS712 Hall-current-sensor were all-over-the-place and, therefore, unusable.

Initially, I tried using a TL431A, 2.495V precision zener voltage reference, which has, with a 1 kΩ resistor in series, a drop out voltage of around 2.8V. This worked great for the analog charge- and battery-readings.

Unlike the ACS712 Hall-current-sensor, which needs a constant operating Voltage of 5V, the ACS711 can operate with voltages as low as 3.3V. The ACS712 chip was changed out for an ACS711.

After a few try & errors and for practical reasons, I ended up using a L78L33 (3.3V TO-92 package) voltage regulator as a power-supply for the ACS711 and, instead of the TL431A zener, as a 3.3V voltage reference.

perf board circuit of Arduino Controlled Battery Charger

The dropout voltage of the L78L33 is about 3.8V and can handle a maximum voltage supply of 30V.

Combined with electrolytic capacitors, the analog readings are now stable when charging 6 Volt batteries. Obviously, none of these problems do occur when charging batteries higher than 6.5V (the L7805 dropout voltage).

As Lewis Loflin explains in his videos, when using higher voltages on the DC power-rail, protection has to be built in to prevent exceeding the Mosfet Vgs (maximum voltage across the Gate and Source). For the IRF4905, this is 20V.

In the 12 Volt charger mode, this is done by using a zener-diode in series with the gate. However, to obtain the Gate threshold Voltage (-4V) in the 6Volt charge-mode, this zener-diode has to be removed, shorted or by-passed.

Initially, two NPN transistors were used. One transistor to connect to ground and another one to bypass the zener-diode. This worked fine until a DC rail Voltage of about 20V. At higher voltages, the IRF4905 mosfet turned on. (Perhaps this was due to current leakage through the transistor collector-base?)

The zener bypass transistor was replaced by a small TO-92 package BS170 mosfet. This solved the problem and the circuitry works now 100%. In hindsight, replacing both transistors with the BS170 mosfets may work even better and no gate-resistors are required.

Another Lesson Learned was the LCD-Display

The first display used was a reclaimed 16×2, or 1602 display without backlight. This turned out to be not very smart, as battery-chargers often get used in garages or sheds and most are not very well illuminated.

LCD display for Arduino Controlled Battery Charger

Also, LCD-displays use up a lot of I/O pins. This time, the LCD has backlight and is I2C controlled. A I2C-backpack with a PCF8574AT was connected to the 16×2 LCD. I2C uses, next to VCC and GND, only 2 data lines, SCL and SMA, normally connected to analog pins A4 & A5 of the Arduino.

If the Arduino Mini Pro is chosen, and if you want to use I2C, attention has to be paid that the board has (the provision for) the analog pins A4 and A5.

As you can see on this picture, this Arduino Mini Pro has two additional holes, just below the analog pins A2 and A3. These two holes are A4 and A5. Not all Mini Pro’s have this feature, so be aware.

Arduino pro mini used with Arduino Controlled Battery Charger

Also, be aware that the Arduino Mini Pro doesn’t have an Aref pin (at least, I haven’t seen one), for connecting to the external reference voltage.

Pin 20 of the ATMEGA 328 chip is the Aref pin. On my board, pin 20 is connected to a SMD capacitor. This capacitor, obviously on the pin 20 side, offers a nice “big” opportunity to solder a small wire to. I fed that wire, for strain relief, through a few unused pinholes on the top-end of the board.

When switching a coil (the transformer) On/Off, inductive voltage spikes do occur.

In one of my earlier attempts, with different resistor values for the voltage dividers and no protection in place, I fried the analog I/O pins of my Arduino board 🙁

With the current divider resistor values and a 30V zener diode included, the I/O pins should be safe.

To reduce the transformer inrush current, a NTC Thermistor (5D-15) was added.

For additional safety, the transformer is equipped with a fuse and a normally closed (NC) thermo-switch, 85 degC (185F).

The transformer can get hot, especially while charging 12 Volt batteries. Make sure you choose a transformer which is up for the job; 150VA or higher.

When the transformer is powered by 120V, a bigger fuse is required. I added a little cooling fan, using an LM35 temperature sensor, and it’s steered with Arduino PWM to keep things cool in 12Volt charging mode.

The fan is optional, and as such indicated, in the IDE Sketch. If not required, “comment” the indicated sections.

Building the Circuit on a Perforation Board

The Arduino Mini Pro was mounted on a 5 x 7 cm perforation-board.

I used SIL female headers on the perf-board for mounting the Arduino. This enabled me to remove the Arduino while working on the board.

As it turned out, using the SIL headers, a nice space below the Arduino was created for a large 4700µF 6.3V capacitor to smooth out / store energy in the 5V supply.

Since the 5V is supplied by the L7805, which can deliver 1.5A, ample additional 5V- and GND-pins were added to the board.

The main DC power-rail, soldered on the bottom of the board, consisted of solid 1.5mm2 (≈ 16AWG) copper-wire.

To avoid contact with the metal-enclosure, the perf-board was mounted on 4 standoffs. The KBPC5010 rectify-bridge and the IRF4905 Mosfet were for cooling purposes. Both were mounted against the metal-enclosure. Cooling-paste was used for optimum heat transfer.

Open Enclosure view of this Arduino Controlled Battery Charger

To reset the Arduino, a momentary pushbutton was added in the back of the enclosure. The Reset-button will, when pressed, connect the RST-pin to GND.

The enclosure front was custom made out of a 2mm plastic sheet and spray-painted.

The metal enclosure itself was sanded and spray-painted.

Writing the Arduino Code

This is my first “major” self-written Arduino sketch.  (You can download the sketch below).

Most of the programming language was learned at Programming Electronics Academy, so a big “Thank You” to Michael for all his energy and efforts that he has put in his very well laid out website and very well explained lessons.

I’m sure, looking back in a few years time, that the sketch could have been written much more sophisticated and efficient, but…it’s what it is and it works fine 😉

/* This programme is written for charging Trojan T-225Ah 6/12Volt open Lead Acid batteries (LAB),
 *  but it can easily be adapted for another LAB's and/or charge values.
 *  Before I give an explanation, intended as a guide, about charging LAB's; an important note:
 *  ***** Do NOT leave a LAB in a discharged condition or discharge it too low ******
 *  This will drastically shorten its life, if not completely destroy it! Always charge
 *  a LAB after usage, a.s.a.p.! There are different types of LAB's, each with its own characteristics.
 *  There are open LAB's and closed LAB's, also called VRLA (valve-regulated-lead-acid), such as gell-
 *  and AGM-batteries. Batteries are build for different purposes; deep-cycle, car, marine, etc, etc. Each
 *  have their own characteristics and charge patterns. If you want to know more about LAB's, a highly
 *  recommended read would be: http://www.victronenergy.dk/upload/documents/Book-Energy-Unlimited-EN.pdf
 *  Each LAB knows 3x charge-stages; Float-, Absorption- and an Equalisation-charge. Normally an
 *  absorption-charge is sufficient to recharge the battery and to keep it in a good shape. After
 *  the absorption-charge, a float-charge can be applied to keep the battery constantly "topped-up".
 *  An Equalisation-charge is only required either; every few months or when the specific-gravity of
 *  the acid in a individual cell differs more than 0.02 sg compared to the other cells, from
 *  the same battery. Via a switch, the charger can be set for 6V or 12V. Another mode-switch selects 
 *  absorption-charge (Trojan 6V T-225: 7.40V, 12V: 14.8V) or equalization charge (Trojan: 7.75V / 15.5V).
 *  In either case, this sketch will keep the voltage at the absorption voltage / float level,
 *  or at the equalization voltage level; whichever charge-mode has been selected.
 *  In the absorption-mode, when the current reaches 2% of the battery capacity,
 *  the battery is considered to be full; in this case 2% of 225Ah = 4.5Amps @ 7.40V.
 *  When in absorption charge, this sketch switches to float-charge as soon as the "battery full
 *  current" is reached. Be aware that this isn't the case in equalization mode!!
 *  The duration of an Equalisation-charge should be no longer until the acid specific gravity of all cells
 *  have an equal, or nearly equal readings. An Equalisation charge is very hard on the battery
 *  and should only be performed when necessary, as short as possible and manually / observed.
 *  In no way the charger & battery should be left unattended during an equalisation charge.
 *  Each type of LAB has its own manufacture recommended charge-voltages. Check yours first!!
 *  Since charging of a LAB is a chemical process, it needs time to occur. The charge-current
 *  for a LAB is therefor max. 10% of the battery capacity. For a 225Ah LAB, this is no more
 *  than 22.5 Amps (lower is fine too). Of course, the charge-source self, the Mosfet and the cables,
 *  all have to be suitably rated for these high currents.
 *  During charging, a close eye needs to be kept on the temperatures of all components involved;
 *  the Mosfet, the battery, the cables, panels / transformer etc.
 *  The same schematic pricipals were used as from lewis Loflin (http://www.bristolwatch.com/solar1.htm).
 *  If you like an excellent thorough explanation of how the schematic works, please visit his website.
 *  An Arduino (in this case a Arduino mini pro) steers, via a NPN transistor, a "P-channel" Mosfet.
 *  The In/Out voltage is read via a resistor voltage divider and the current is measured via
 *  a 25Amp ASC711 Hall Sensor.
 *  Combined with LED-indicators, a 16x2 LCD is added for read-out, checks & messages.
 *  The Arduino is powered via a 5V L7805, 1.5 Amp voltage regulator. The regulator is connected to
 *  the incoming voltage on the charge-side.
 *  When, instead of Solar-panels, a transformer is used, a circuitry protection against induction
 *  Voltage-spikes has to be included.
 *  When the charger is connected the the battery and switched on, best is to press the reset-button. 
 *  This will ensure that the Arduino has the latest correct Voltage readings. Failure to do so, 
 *  may cause that the Arduino has incorrect readings in its memory, taken while starting up / connecting up.
 *  For in the 12Volt charging mode, a cooling fan with an LM35 temperature sensor can be included. 
 *  To include, all the code in between the "optional cooling fan" dotted lines have to be Uncommented. 
 *  This example code is in the public domain.
 *
  modified 24 November 2015
  by RvD.
*/


#include<Wire.h>// include I2C wiring LCD display
#include<LiquidCrystal_I2C.h>       // include display I2C, connect SDA to A4, SCL to A5 
LiquidCrystal_I2C LCD(0x3F, 16, 2); // tells Adruino the LCD I2C address and display size. The chip ACF8574-AT
                                    // has I2C address 0x3F, the chip ACF8574-T has I2C address 0x27
# define chargeReading A0           // Analog pin for reading charger voltage
# define batteryReading A1          // analog pin for reading battery voltage
# define ampReading A2              // analog pin for reading output-voltage from the current-sensor
# define transistorPin 13           // output pin via a 2.2kΩ resistor to NPN-transistor basis for Mosfet control.
# define modeSwitchPin 2            // selector Switch for absorption or equalization charge
# define zenerByPassPin 11          // to write transistor High to Bypass zener in 6V mode
# define absorptionLed 3            // pin to steer absorption indicator Led
# define equalizationLed 4          // pin to steer equalization indicator Led
# define twelveVLed 5               // pin to steer twelve-volt indicator Led
# define sixVLed 6                  // pin to steer six-volt indicator Led
//--------------------------Begin of optional cooling fan-------------------
# define tempCPin A3                // Pin for LM35 temperature sensor input
# define temperatureLed 8           // warning Led in case the temperature exceeds max-temperature
# define fanPWMTransistor 9         // pin, via 2.2kΩ resistor, to base of fan PWM switching transistor
//--------------------------End of optional cooling fan-------------------
int batteryVoltage = 0;             // initialize and define batteryVoltage
int chargeVoltage = 0;              // initialize and define chargeVoltage
int ampVoltage = 0;                 // initialize and define voltage from ACS711 current-sensor
int floatVoltage6V = 260;           // float voltage 6.60V => ADC reading over 1k/6.8k divider
int absorptionVoltage6V = 292;      // absorption voltage 7.40V => ADC reading over a 1k/6.8k divider
int equalizeVoltage6V = 306;        // equalization voltage 7.75V => ADC reading over a 1k/6.8k divider
int lowCutOffVoltage6V = 217 ;      // Below 5.5V something is wrong with the clamps or worse, the battery
float conversionFactor6V = 0.02534; // Conversion factor in the 6V range to get from the analog value to Voltage
int sixOrTwelvePoint = 475;         // six-or-twelve volt charge cross-over point set at around 11.5V
int floatVoltage12V = 522;          // float voltage 13.2V => ADC reading over 1k/6.8k divider
int absorptionVoltage12V = 586;     // absorption voltage 14.8V => ADC reading over a 1k/6.8k divider
int equalizeVoltage12V = 614;       // equalization voltage 15.5V => ADC reading over a 1k/6.8k divider
int lowCutOffVoltage12V = 455;      // Battery Voltage below 11.5 V, something is wrong with the clamps or the battery
float conversionFactor12V = 0.02525;// Conversion factor in the 12V range to get from the analog value to Voltage
float battFullCurrent = 4.0;        // Current (in Amps) at which the batt is considered full during absoption and
                                    // switches over to float charge.
float battFullCurrentAnalog;        // number used after conversion from battFullCurrent to analog number.
int currentZero = 514;              // ADC number given by the ACS711 current-sensor with no current flowing
int gridFrequency = 50;             // Grid Frequency, change if required.
float periodTime;                   // time in milltseconds of 1 full grid-cycle; 50Hz = 20ms, 60Hz = 16.66ms
float averageAmpVoltage = 0;        // Since the Current is AC, averages are taken
float averageChargeReading;         // Since the charge Voltage is AC, averages are taken
float currentADCRatio = 16.735;     // current-sensor ADC reading calibrated for 1 ampere.
float ampere;                       // declare a variable
int switchPosition;                 // declare a variable for absorption or equalize position
//-------------------------Begin of optional cooling fan--------------------
int tempC;                          // temperature read from the temperature sensor
int fanSpeed;                       // the PWM duty cycle for the fan speed
int tempMin = 70;                   // minimum temerature in degC at which the fan has to start cooling at minimum speed
int tempMax = 85;                   // the maximum temperature in degC at which the fan has to run full speed
long previousMillis = 0;
long interval = 1000;               // setting the blaink rate in milli-seconds
//--------------------------End of optional cooling fan--------------------


void setup() {

  Serial.begin(9600);                // Setup the serial monitor, very handy for trouble shooting
  analogReference(EXTERNAL);         // Instead of using the default 5V supply, a TL431 with 2.5 voltage reference is used
  pinMode(chargeReading, INPUT);     // setup pinMode for input from voltage divider charger side
  pinMode(batteryReading, INPUT);    // setup pinMode for input from voltage divider battery side
  pinMode(ampReading, INPUT);        // setup pinMode for input from current-sensor
  pinMode(zenerByPassPin, OUTPUT);   // setup pinMode for output to bypass transistor zener.
  digitalWrite(zenerByPassPin, LOW); // set the base of the zener bypass transistor LOW = OFF.
  pinMode(transistorPin, OUTPUT);    // Mosfet steering is done via the transistor base. Putting the transistor base
                                     // HIGH, pulls the Mosfet Gate to ground = LOW => Mosfet "ON"
  digitalWrite(transistorPin, LOW);  // set the base of the switching Transistor LOW => OFF
  pinMode (modeSwitchPin, INPUT);    // Switch (STDP) for selecting absorption or equalize-charge
  digitalWrite(modeSwitchPin, LOW);  // write mode-switch low for absorptiob charge
  pinMode(sixVLed, OUTPUT);          // set six-volt LedPin mode as output
  digitalWrite(sixVLed, LOW);        // set low = 6V indicator led off
  pinMode(twelveVLed, OUTPUT);       // set twelve-volt LedPin as output
  digitalWrite(twelveVLed, LOW);     // set low = q2V indicator led off
  pinMode(absorptionLed, OUTPUT);    // set absorption indicator ledpin as output
  digitalWrite(absorptionLed, LOW);  // set pin Low
  pinMode(equalizationLed, OUTPUT);  // set equalization indicator ledpin as output
  digitalWrite(equalizationLed, LOW);// set pin Low
//---------------------------Begin of optional cooling fan-----------------
  pinMode (tempCPin, INPUT);         // set pin to receive LM35 temperature sensor output
  pinMode (fanPWMTransistor, OUTPUT);// set the pin to steer the base of the fan steering transistor
  digitalWrite(fanPWMTransistor,LOW);// set pin low = transistor off
  pinMode (temperatureLed, OUTPUT);  // set the pin for the high temperature warning led
  digitalWrite(temperatureLed,LOW);  // set pin low = temperature Led off
//---------------------------End of optional cooling fan-------------------
  LCD.init();                        // initialise LCD
  LCD.backlight();                   // Turn-on backlight, which is oof in default
  LCD.setCursor(0, 0);               // set the cursor at the top-left-hand corner
  periodTime = 1000 / gridFrequency; // in milliseconds
  battFullCurrentAnalog = (battFullCurrent * currentADCRatio); // converting user amp input to ADC reading

}

void loop() {
  
  // Determine whether the charger is set for 6V or 12V charge
  // Because the Charge-Transformer is AC, more Voltage readings are taken and then averaged out
  int j = 1; // set, or reset, counter
  averageChargeReading = 0; //reset averageAmpVoltage
  while (j <= 2 * periodTime) {
    averageChargeReading += analogRead(chargeReading);
    j++;
    delay(1);
  }
  chargeVoltage = (averageChargeReading / (2 * periodTime)); // calculating the average charge Voltage

  if (chargeVoltage <= sixOrTwelvePoint) { // if lower than sixOrTwelvePoint, do the 6V charge, else 12V charge
    
// ------------------------- Initialization of 6 Volt charge-----------------------------
    
    digitalWrite(sixVLed, HIGH);     // Led indicating the program is in 6V charge mode
    digitalWrite(twelveVLed, LOW);   // as a precaution and to remove previous settings
    switchPosition = digitalRead(modeSwitchPin); // check the mode switch selection; absorption or equalize

    if (switchPosition == HIGH && chargeVoltage <= sixOrTwelvePoint) { // mode switch HIGH means 6V equalisation has been selected

//---------------------------Begin of 6V Equalisation loop------------------------------
      
      digitalWrite(equalizationLed, HIGH);      // set equalization indicator Led
      digitalWrite(absorptionLed, LOW);         // set absorption indicator Led
      
      batteryVoltage = analogRead(batteryReading); // Read battery Voltage

      // Because the Charge-Transformer is AC, more Voltage readings are taken and then averaged out
      int j = 1; // set, or reset, counter
      averageChargeReading = 0; //reset averageAmpVoltage
      while (j <= 2 * periodTime) {
        averageChargeReading += analogRead(chargeReading);
        j++;
        delay(1);
      }

      chargeVoltage = (averageChargeReading / (2 * periodTime)); // calculating the average charge Voltage

      Serial.println(chargeVoltage);

      if ((chargeVoltage < equalizeVoltage6V) && (batteryVoltage > lowCutOffVoltage6V)) { // check charge voltage
        LCD.home();
        LCD.print("Charge Volt Low ");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      } // end of if statement

      if ((chargeVoltage <= equalizeVoltage6V) && (batteryVoltage <= lowCutOffVoltage6V)) { // check both Voltages
        LCD.home();
        LCD.print("IN & OUT too Low");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      } // end of if statement

      if ((chargeVoltage > equalizeVoltage6V) && (batteryVoltage <= lowCutOffVoltage6V)) {
        /* check battery voltage.
              If below the set threshold "lowCutOffVoltage", the charger will not start to charge.
           *  Either the clamps are not good connected or the battery has been drained so far, that it most likely has been damaged.
           *  In that case, the threshold voltage can be set lower, but now the battery has to be supervised during the charge process.
           *  Even if the battery (partially) recovers, damage has been done and has shorten its lifetime / capacity */

        LCD.home();
        LCD.print("Batt Volt LOW!");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      }

      if ((chargeVoltage > batteryVoltage) && (chargeVoltage <= sixOrTwelvePoint) && (batteryVoltage <= equalizeVoltage6V) && (chargeVoltage > equalizeVoltage6V) && (batteryVoltage > lowCutOffVoltage6V)) {
        // if all these 5 conditions are true, start charging.
        // if one of the conditions is not true, no charging will occur. This also means that when the battery clamps are not connected,
        // no voltage is supplied to them and therefor no risk of shorting them.

        LCD.home();
        LCD.print("Equal ");
        LCD.print("Batt=");
        LCD.print(batteryVoltage * conversionFactor6V);
        LCD.print ("V");

        int chargeON = (equalizeVoltage6V - batteryVoltage) * 100; // determine the Mosfet ON time
        chargeON = abs(chargeON);   // make it alway a positive number

        digitalWrite(zenerByPassPin, HIGH); // set zener bypass Mosfet high, to exclude Mosfet Vgs protection zener
        digitalWrite (transistorPin, HIGH); // transistor turns Mosfet gate LOW = ON
        delay (0.5 * chargeON); // to get the charge current started and stabelize

        // Because the chargeCurrent is an AC current, more readings are taken and then averaged out
        int j = 1; // set, or reset, counter
        averageAmpVoltage = 0; //reset averageAmpVoltage
        while (j <= 2 * periodTime) {
          averageAmpVoltage += analogRead(ampReading);
          j++;
          delay(1);
        }
        
        averageAmpVoltage = averageAmpVoltage / (2 * periodTime);
        ampVoltage = currentZero - averageAmpVoltage;
        ampVoltage = abs(ampVoltage); // make ampVoltage always a positive voltage
        ampere = ampVoltage / currentADCRatio; // convert ampVoltage to amperes
        LCD.setCursor(0, 1); // reset cursor
        LCD.print("Current:"); // print to LCD
        LCD.print(ampere); // print to LCD
        LCD.print(" Amp"); // print to LCD

        delay(0.5 * chargeON);
        digitalWrite(transistorPin, LOW); // transistor turns off, Mosfet gate goes HIGH => OFF
        digitalWrite(zenerByPassPin, LOW); // set zener bypass Mosfet LOW, to include Mosfet Vgs protection zener

      } // end of if statement
      
      switchPosition = digitalRead(modeSwitchPin); //check swithMode for changes
      chargeVoltage = analogRead(chargeReading);   // check the chargeVoltage again for 6-12V chargeMode
      delay(10);                                   // to allow anolagReading to settle
      
    } // end of if statement

//----------------------------End of 6V Equalize loop-----------------------------


//--------------------------- Begin of 6V Absorption loop-------------------------

    else {

      digitalWrite(equalizationLed, LOW);      // set equalization indicator Led
      digitalWrite(absorptionLed, HIGH);       // set absorption indicator Led
      
      // Because the Charge-Transformer is AC, more Voltage readings are required and then averaged out
        int j = 1; // set, or reset, counter
        averageChargeReading = 0; //reset average Voltage on the AC charge side
        while (j <= 2 * periodTime) { // take readings for 2 periods
        averageChargeReading += analogRead(chargeReading); // compound readings
        j++; // add to counter
        delay(1);
      } // delay 1ms

      chargeVoltage = (averageChargeReading / (2 * periodTime));
      batteryVoltage = analogRead(batteryReading);
      ampVoltage = abs(currentZero - analogRead(ampReading));

      if ((chargeVoltage < absorptionVoltage6V) && (batteryVoltage > lowCutOffVoltage6V)) { // check the charge voltage
        LCD.home();
        LCD.print("Charge Volt LOW ");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      } // end of if statement

      if ((chargeVoltage <= absorptionVoltage6V) && (batteryVoltage <= lowCutOffVoltage6V)) {// check charge and batt
        LCD.home();
        LCD.print("IN & OUT too LOW");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      } // end of if-statement

      if ((chargeVoltage > absorptionVoltage6V) && (batteryVoltage <= lowCutOffVoltage6V)) {
        /* check battery voltage,
              if below the set threshold "lowCutOffVoltage", the charger will not charge.
           *  Either the clamps are not good connected or the battery has been drained so far, that it most likely has been damaged.
           *  In that case, the threshold voltage can be set lower, but now the battery has to be supervised during the charge process.
           *  Even if the battery (partially) recovers, damage has been done and has shorten its lifetime / capacity */

        LCD.home();
        LCD.print("Batt Volt LOW!   ");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      }

      if ((chargeVoltage > batteryVoltage) && (chargeVoltage <= sixOrTwelvePoint) && (batteryVoltage <= absorptionVoltage6V) && (chargeVoltage > absorptionVoltage6V) && (batteryVoltage > lowCutOffVoltage6V)) {
        // if all these 5 conditions are true, start charging.
        // if one of the conditions is not true, no charging will occur. This also means that when the battery clamps are not connected, no voltage is supplied
        // to them and therefor no risk of shorting.

          LCD.home();
          if (absorptionVoltage12V == floatVoltage12V) {
            LCD.print("Float ");
          }
          
          else { 
            LCD.print("AbsP  ");
          }
          
          LCD.print("Batt=");
          LCD.print(batteryVoltage * conversionFactor6V);
          LCD.print ("V");
          

        int chargeON = (absorptionVoltage6V - batteryVoltage) * 100; // determine the Mosfet ON time
        chargeON = abs(chargeON); // make it alway a positive number

        digitalWrite(zenerByPassPin, HIGH); // set zener bypass Mosfet high, to exclude Mosfet Vgs protection zener
        digitalWrite (transistorPin, HIGH); // transistor turns Mosfet gate LOW = ON
        delay (0.5 * chargeON); // time to give charge current to start and stabelize

        // Because the chargeCurrent is an AC current, more readings are taken and then averaged out

        int j = 1; // set, or reset, counter
        averageAmpVoltage = 0; //reset averageAmpVoltage
        while (j <= 2 * periodTime) {
          averageAmpVoltage += analogRead(ampReading);
          j++;
          delay(1);
        }
        
        averageAmpVoltage = averageAmpVoltage / (2 * periodTime);
        ampVoltage = currentZero - averageAmpVoltage;
        ampVoltage = abs(ampVoltage); // make ampVoltage always a positive voltage
        ampere = ampVoltage / currentADCRatio; // convert ampVoltage to amperes
        LCD.setCursor(0, 1); // reset cursor
        LCD.print("Current:"); // print to LCD
        LCD.print(ampere); // print to LCD
        LCD.print(" Amp"); // print to LCD
        Serial.println(ampere);

        delay(0.5 * chargeON);
        digitalWrite(transistorPin, LOW); // transistor turns off, Mosfet gate goes HIGH => OFF
        digitalWrite(zenerByPassPin, LOW); // set zener bypass Mosfet LOW, to include Mosfet Vgs protection zener

      } // end of if-statement

      if (ampVoltage <= battFullCurrentAnalog && batteryVoltage >= absorptionVoltage6V && chargeVoltage >= floatVoltage6V) {
        // if raw ampreading <= battery full current and battery Voltage >= floatVoltage

        absorptionVoltage6V = floatVoltage6V; // change absorption Voltage to float Voltage.
        batteryVoltage = analogRead (batteryReading);
        LCD.clear();
        LCD.home();
        LCD.print("Float charge");
        LCD.setCursor(0, 1);
        LCD.print("Batt: ");
        LCD.print(batteryVoltage * conversionFactor6V);
        LCD.print("V");
        delay(200);
      }
      
      switchPosition = digitalRead(modeSwitchPin); //check swithMode for changes
      chargeVoltage = analogRead(chargeReading);   // check the chargeVoltage again for 6-12V chargeMode
      delay(10);                                   // to allow anolagReading to settle 
      
    } // end of else statement
//---------------------------------End of 6V Absoption loop-------------------------------
  } // end of 6V charging mode


  else { // -----------------------Initialization of 12V charging ----------------------------

    digitalWrite(zenerByPassPin, LOW); // set zener bypass Mosfet low, to include Mosfet Vgs protection zener
    digitalWrite(sixVLed, LOW);     // as a precaution and to remove previous settings.
    digitalWrite(twelveVLed, HIGH); // Led indicating the program is in 6V charge mode

//---------------------------------Begin optional cooling fan ----------------------------

      tempC = (analogRead(tempCPin)* 0.48828125);// read temperature sensor and convert to Celcius
       
       if(tempC < tempMin) {                     // if temp is lower than minimum temp
           fanSpeed = 0;                         // set value of variable.
           digitalWrite(fanPWMTransistor, LOW);  // write base of fan transistor LOW => Fan = OFF.  
       } 
       if(tempC >= tempMin) {                                 // if temperature is higher than minimum temp, start cooling
           fanSpeed = map(tempC, tempMin, tempMax, 60, 255); // convert temperature reading to PWM output range, a starting
                                                             // duty cycle of 60 to overcome initial fan starting friction
           fanSpeed = constrain (fanSpeed, 60, 255);         // constrain fanSpeed within PWM range
           analogWrite(fanPWMTransistor, fanSpeed);          // PWM to the fan.
       } 
       
       if(tempC > tempMax) {                            // if temp is higher than tempMaxa, start the temperature waring Led
        unsigned long currentMillis = millis();         // Read current milliseconds clock
        if(currentMillis - previousMillis > interval){  // compare
          previousMillis = currentMillis;
          if(temperatureLed == LOW){                    // if temperature Led is Low, set High.
            digitalWrite(temperatureLed, HIGH);
          }
          else {                                        // if temperature Led is High, set Low.
            digitalWrite(temperatureLed, LOW);
          }
        }
       }
//---------------------------------End of optional cooling fan --------------------------

    switchPosition = digitalRead(modeSwitchPin); // check the mode switch selection; absorption or equalize

    if (switchPosition == HIGH && chargeVoltage > sixOrTwelvePoint) { // mode switch HIGH means 12V equalisation has been selected

//---------------------------------Begin of 12V Equalisation loop---------------------
      
      digitalWrite(equalizationLed, HIGH);      // set equalization indicator Led
      digitalWrite(absorptionLed, LOW);         // set absorption indicator Led
      
      batteryVoltage = analogRead(batteryReading); // Read battery Voltage

      // Because the Charge-Transformer is AC, more Voltage readings are taken and then averaged out
      int j = 1; // set, or reset, counter
      averageChargeReading = 0; //reset averageAmpVoltage
      while (j <= 2 * periodTime) {
        averageChargeReading += analogRead(chargeReading);
        j++;
        delay(1);
      }

      chargeVoltage = (averageChargeReading / (2 * periodTime)); // calculating the average charge Voltage

      if ((chargeVoltage < equalizeVoltage12V) && (batteryVoltage > lowCutOffVoltage12V)) { // check charge voltage
        LCD.home();
        LCD.print("Charge Volt Low ");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      } // end of if statement

      if ((chargeVoltage <= equalizeVoltage12V) && (batteryVoltage <= lowCutOffVoltage12V)) { // check both Voltages
        LCD.home();
        LCD.print("IN & OUT too Low");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      } // end of if statement

      if ((chargeVoltage > equalizeVoltage12V) && (batteryVoltage <= lowCutOffVoltage12V)) {
        /* check battery voltage.
              If below the set threshold "lowCutOffVoltage", the charger will not start to charge.
           *  Either the clamps are not good connected or the battery has been drained so far, that it most likely has been damaged.
           *  In that case, the threshold voltage can be set lower, but now the battery has to be supervised during the charge process.
           *  Even if the battery (partially) recovers, damage has been done and has shorten its lifetime / capacity */

        LCD.home();
        LCD.print("Batt Volt LOW!  ");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      }

      if ((chargeVoltage > batteryVoltage) && (batteryVoltage <= equalizeVoltage12V) && (chargeVoltage > equalizeVoltage12V) && (batteryVoltage > lowCutOffVoltage12V)) {
        // if all these 4 conditions are true, start charging.
        // if one of the conditions is not true, no charging will occur. This also means that when the battery clamps are not connected,
        // no voltage is supplied to them and therefor no risk of shorting them.

        LCD.home();
        LCD.print("Equal ");
        LCD.print("Batt=");
        LCD.print(batteryVoltage * conversionFactor12V);
        LCD.print ("V");

        int chargeON = (equalizeVoltage12V - batteryVoltage) * 100; // determine the Mosfet ON time
        chargeON = abs(chargeON);   // make it alway a positive number

        digitalWrite (transistorPin, HIGH); // transistor turns Mosfet gate LOW = ON
        delay (0.5 * chargeON); // to get the charge current started and stabelize

        // Because the chargeCurrent is an AC current, more readings are taken and then averaged out
        int j = 1; // set, or reset, counter
        averageAmpVoltage = 0; //reset averageAmpVoltage
        while (j <= 2 * periodTime) {
          averageAmpVoltage += analogRead(ampReading);
          j++;
          delay(1);
        }
        
        averageAmpVoltage = averageAmpVoltage / (2 * periodTime);
        ampVoltage = currentZero - averageAmpVoltage;
        ampVoltage = abs(ampVoltage); // make ampVoltage always a positive voltage
        ampere = ampVoltage / currentADCRatio; // convert ampVoltage to amperes
        LCD.setCursor(0, 1); // reset cursor
        LCD.print("Current:"); // print to LCD
        LCD.print(ampere); // print to LCD
        LCD.print(" Amp"); // print to LCD

        delay(0.5 * chargeON);
        digitalWrite(transistorPin, LOW); // transistor turns off, Mosfet gate goes HIGH => OFF
      } // end of if statement
      
      switchPosition = digitalRead(modeSwitchPin); //check swithMode for changes
      chargeVoltage = analogRead(chargeReading);   // check the chargeVoltage again for 6-12V chargeMode
      delay(10); // to allow anolagReading to settle
    } // end of if statement

//-----------------------------End of 12V Equalize loop-----------------------


//-----------------------------Begin of 12V Absorption loop----------------------

    else {

      digitalWrite(equalizationLed, LOW);      // set equalization indicator Led
      digitalWrite(absorptionLed, HIGH);       // set absorption indicator Led

      // Because the Charge-Transformer is AC, more Voltage readings are required and then averaged out
      int j = 1; // set, or reset, counter
      averageChargeReading = 0; //reset average Voltage on the AC charge side
      while (j <= 2 * periodTime) { // take readings for 2 periods
        averageChargeReading += analogRead(chargeReading); // compound readings
        j++; // add to counter
        delay(1);
      } // delay 1ms

      chargeVoltage = (averageChargeReading / (2 * periodTime));
      batteryVoltage = analogRead(batteryReading);
      ampVoltage = abs(currentZero - analogRead(ampReading));

      if ((chargeVoltage < absorptionVoltage12V) && (batteryVoltage > lowCutOffVoltage12V)) { // check the charge voltage
        LCD.home();
        LCD.print("Charge Volt LOW ");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      } // end of if statement

      if ((chargeVoltage <= absorptionVoltage12V) && (batteryVoltage <= lowCutOffVoltage12V)) {// check charge and batt
        LCD.home();
        LCD.print("IN & OUT too LOW");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      }

      if ((chargeVoltage > absorptionVoltage12V) && (batteryVoltage <= lowCutOffVoltage12V)) {
        /* check battery voltage,
              if below the set threshold "lowCutOffVoltage", the charger will not charge.
           *  Either the clamps are not good connected or the battery has been drained so far, that it most likely has been damaged.
           *  In that case, the threshold voltage can be set lower, but now the battery has to be supervised during the charge process.
           *  Even if the battery (partially) recovers, damage has been done and has shorten its lifetime / capacity */

        LCD.home();
        LCD.print("Batt Volt LOW!  ");
        LCD.setCursor(0, 1);
        LCD.print("                ");
      }

      if ((chargeVoltage > batteryVoltage) && (batteryVoltage <= absorptionVoltage12V) && (chargeVoltage > absorptionVoltage12V) && (batteryVoltage > lowCutOffVoltage12V)) {
        // if all these 4 conditions are true, start charging.
        // if one of the conditions is not true, no charging will occur. This also means that when the battery clamps are not connected, no voltage is supplied
        // to them and therefor no risk of shorting them.

          LCD.home();
          if (absorptionVoltage12V == floatVoltage12V) {
            LCD.print("Float ");
          }
          else { LCD.print("AbsP  ");}
          LCD.print("Batt=");
          LCD.print(batteryVoltage * conversionFactor12V);
          LCD.print ("V");
        
        int chargeON = (absorptionVoltage12V - batteryVoltage) * 100; // determine the Mosfet ON time
        chargeON = abs(chargeON); // make it alway a positive number

        digitalWrite (transistorPin, HIGH); // transistor turns Mosfet gate LOW = ON
        delay (0.5 * chargeON); // time to give charge current to start and stabelize

        // Because the chargeCurrent is an AC current, more readings are taken and then averaged out

        int j = 1; // set, or reset, counter
        averageAmpVoltage = 0; //reset averageAmpVoltage
        while (j <= 2 * periodTime) {
          averageAmpVoltage += analogRead(ampReading);
          j++;
          delay(1);
        }
        averageAmpVoltage = averageAmpVoltage / (2 * periodTime);
        ampVoltage =abs (currentZero - averageAmpVoltage);
        ampere = ampVoltage / currentADCRatio; // convert ampVoltage to amperes
        LCD.setCursor(0, 1); // reset cursor
        LCD.print("Current:"); // print to LCD
        LCD.print(ampere); // print to LCD
        LCD.print(" Amp"); // print to LCD

        delay(0.5 * chargeON);
        digitalWrite(transistorPin, LOW); // transistor turns off, Mosfet gate goes HIGH => OFF

      } // end of if-statement


      if (ampVoltage <= battFullCurrentAnalog && batteryVoltage >= absorptionVoltage12V && chargeVoltage >= floatVoltage12V) {
        // if raw ampreading <= battery full current and battery Voltage >= floatVoltage

        absorptionVoltage12V = floatVoltage12V; // change absorption Voltage to float Voltage.
        
        LCD.home();
        LCD.print("Float charge    ");
        LCD.setCursor(0, 1);
        LCD.print("Batt: ");
        LCD.print(batteryVoltage * conversionFactor12V);
        LCD.print("V    ");
        delay(20);

      }
      switchPosition = digitalRead(modeSwitchPin); // check swithMode for changes
      chargeVoltage = analogRead(chargeReading);   // check the chargeVoltage again for 6-12V chargeMode
      delay(10);                                   // to allow anolagReading to settle
    } // end of else statement
//-----------------------------------End of 12V Absoption loop------------------------
  } // end of else statement.

}// end of void-loop

The position of the external toggle switches determines whether 6Volt, 12Volt, absorption- or equalization-charge is selected.

The sketch feeds-back the selected switch position via indicator LED’s. Because the LED’s are an Arduino feedback of the choice made, it may take a little delay before the appropriate LED comes on.

The sketch recognizes, via the charge Voltage divider, which charge voltage is chosen.

If 12Volt is selected, but a 6Volt battery is connected, the LCD will show “Batt Volt Low” message.

If 6Volt is selected, but a 12Volt battery is connected, the LCD will show “Charge Volt Low” message.

As long as the charge-clamps are not connected to the battery, the LCD will show “Batt Volt Low” and the clamps remain “dead.” No change or shorting them. Only when the charge and battery voltages match will the charger start charging.

This also means that when attempting to charge a completely dead battery, which has a remaining voltage below a “healthy”-battery threshold, the charger may refuse to charge.

In such case, the charge thresholds can be altered in the sketch, but most likely the battery is already severely damaged.

Again, I like to refer to the comprehensive Victrons booklet “Energy-Unlimited” for battery Depth of Discharge and consequences.

When “Absorption” charge is selected (6V or 12V), the charger will bring the voltage level up to the voltage required for an absorption charge. It remains there until the current has dropped below a level at which the battery is considered full (See Victron ” Energy-Unlimited”). Hereafter, the charger will switch to Float-charge.

When Equalization mode is selected, the charger will bring the voltage level up to the voltage required for equalization charge.

It will remain there until the “operator” (you) decides enough equalization is done (see Victron ” Energy-Unlimited”).

Therefore, the Equalization charge needs constant attention and monitoring. During equalization charge, the batteries produce explosive hydrogen gases. This means no open-fire and ensure the charging is performed in a well-vented area.

Top view of Arduino Controlled Battery Charger

Each type of battery has its own characteristics and manufacture recommended charge-voltages. Check the properties of your batteries and change them in the IDE sketch.

Once you understand how batteries work and follow correct charging procedures, it will prolong the battery life considerably.

Batteries look robust on the outside, but for a long life, you have to treat them with velvet gloves.

Work safe on the mains. Preferably you should use an isolation transformer in combination with a Variac.

Any suggestions / improvements are very welcome – please leave your comments!

RvD.

Further Reading:

A highly recommended read about Lead-Acid-Battery charging: http://www.victronenergy.dk/upload/documents/Book-Energy-Unlimited-EN.pdf

Lewis Loflins Website: http://www.bristolwatch.com/solar1.htm 

Downloads:

Click here to download a zip file of the schematics and Arduino code for this project.

15 Comments

  1. Avatar Jim Greever on January 3, 2016 at 11:31 pm

    This is an excellent project!
    I’m very pleased that you clearly documented everything you did.
    Thank you for sharing.

    • Avatar MICHAEL JAMES on January 4, 2016 at 2:00 pm

      I thought the same thing – the documentation is fantastic! There more more pictures too that I didn’t post, but the quality is fantastic.

  2. Avatar Jack Singler on February 16, 2016 at 6:53 pm

    I’m just a little confused as to how you hooked up A0, A1, A2 pins in your circuit? I understand they’re used for analog readings but how are they hooked up in the circuit? Thanks many if you can enlighten us,

    • Avatar Jack Singler on February 16, 2016 at 7:10 pm

      Also, how did you know to use those certain resistor values and how did you get the ADC conversion values? Much appreciated

    • Avatar MICHAEL JAMES on February 17, 2016 at 12:13 pm

      This is from Roland….

      Hello Jack; I’ll take it that you downloaded the zip-file with all the schematics? If you take in the sketch for example #define chargeReading Aø, which means that analog pin ø dedicated to chargeReading. In this case it reads to output of the voltage divider on the charge side. If you look in the schematic, there is “pointer” saying “chargeReading” and facing outwards, meaning an output. That’s the one going to the Aø pin. Maybe I could have given each output / Input in the schematic a fixed Arduino pin, but I wanted to give the builder the liberty to choose their own Arduino pins.

      The schematic shows “chargeReading”, an output going out to the Arduino board. You can see in the sketch “chargeReading” goes to Aø.

      Another example; A little lower in the schematic you see “zenerBypassPin”, which is a pointer as an input to the schematic, so for the an Arduino it’s an output. Look in the sketch and “zenerBypassPin” is 11. If you look in the void setup(), you see that the pinMode (zenerBypassPin, OUTPUT);

      Pointers facing towards the schematic is an input from the Arduinoboard, pointers facing outwards from the schematic are outputs, so inputs for the Arduino board.

      As for the voltage dividers; assume the highest anticipated voltage on the Main DC power rail is 25V and in this case the maximum voltage on your Arduino analog input pin should not be higher then the voltage reference of 3.3V. I took a 1kΩ resistor, with 3.3V you get 3.3mA. To calculate the other resistor: (25-3.3) / 0.0033 = 6.57 kΩ. This one doesn’t exist, so I took the next higher = 6.8kΩ.

      As for the ADC conversions values; I’ll take it that you are talking about the current? With a known current flowing through the Hall-sensor, you read the ADC reading via the serial-monitor. You take several different current readings, so you get different ADC readings. This you can plot and should be a reasonable linear line. From the angle of the line, you can calculate the conversion factor, or by just looking at the numbers…… all mathematics 🙂

      Hope this helps……..

      • Avatar Jack Singler on February 21, 2016 at 6:48 pm

        Wow thanks for the answer, that clears it up !

  3. Avatar Helio on February 25, 2016 at 10:11 pm

    Hi, very well documented project, thanks for sharing. I was looking through the code and I wasn’t clear about one if statement

    if (ampVoltage = absorptionVoltage12V && chargeVoltage >= floatVoltage12V)

    When will this condition, i.e. batteryVoltage >= absorptionVoltage12V, ever be met? Even if the battery is at full charge won’t its Voltage be at a little bit above 12V?

    • Avatar MICHAEL JAMES on March 11, 2016 at 1:39 pm

      This is from Roland:

      Yes that condition will be met when.

      Condition 1) ampVoltage is the Voltage from the current-sensor, battFullCurrentAnalog is the converted number of thebattFullCurrent. So the condition is; if the real current flowing is lower, or equal, than the set battFullCurrent, then the battery if considered to be full

      Condition 2) batteryVoltage >= absorptionVoltage12V. Please note that absorptionVoltage12V is just a name to indicate that we are in the 12V mode, and has nothing to do with exactly 12Volt. The absorption voltage for my batteries is 14.8Volt, as you can read in the initialization of the parameters. So what the condition says; if the battery voltage is bigger than the set absorption Voltage, then the battery is considered full.

      Condition 3) chargeVoltage >= floatVoltage12V. This nearly always the case when is everything works fine. It is just that when switching over to the float-charge, the charge-voltage has to be bigger than the float-voltage……..Duh…..

      So when all three conditions are met, the absorptionVoltage12V will be set equal to the floatVoltage12V and the charger will go in float-mode. Again, both “12V” have nothing to do with the actual absorption- or float-voltages

  4. Avatar Jack Singler on March 3, 2016 at 8:00 pm

    Hi Roland I have another question,

    how did you for instance figure out “int lowCutOffVoltage12V = 455” how is this equivalent to 11.5V? Or I guess the more relevant question is how did you figure out the “float conversionFactor12V = 0.02525”. I get that 455*0.02525 = 11.5V but I don’t understand how you came up with that conversion factor?

    And I’m still confused as to how you figured out “float currentADCRatio = 16.735” :/ I understand “int currentZero = 514” is just the serial print output of when no current is flowing but i don’t understand the 16.735 value?

    I appreciate you taking the time to answer this if you can.

    • Avatar MICHAEL JAMES on March 11, 2016 at 1:38 pm

      This is from Roland:

      What I have done is to set with a bench power supply a specific voltage and the main DC rail; say 11.5V. You can read out from the serial monitor what number you get from the voltage divider(s), which was 455. So 11.5V = 455. Assuming all is a linear line (which it was not), then 11.5 / 455 = 0.02525

      What I noticed is when in the 6V range these conversion factors were not exactly the same as 12V and above. To get the voltage readout as accurate as possible, I took two conversion factors, one for 6V range and one for the 12V range. Don’t ask me why there is a deviation…….

      As for the current readout and conversion factors; I did the same. I took the bench power supply, a multi-meter and a big resistor. The resistors happen to be two old electrical grill out of an oven (25 Ohm) and some 6 Ohm 50Watt resistors. By putting them in series or parallel, you can create all sorts of resistance. Obviously you feed this current through the hall-sensor and take read-outs on your serial monitor. When you increase the voltage, the current increases and you calibrate the number on the serial monitor with the amps showing on your multi-meter. So you calibrate against your multi-meter; assuming your multi-meter is accurate (enough). The resistors are getting hot, so you don’t have much time to hang around at different settings. My bench power supply couldn’t go higher then 3 Amps, but since the hall sensor is linear, higher currents are therefor extrapolated. Also, higher currents are just more for an indication. Whether the battery charges with 6, 7,8 or 10 Amps….. not so exiting. All you are really interested in is the current when the battery is considered to be full, or battFullCurrent. Batteries are more sensitive to voltage than to current, so accurate voltage readouts are more important.

      I can’t repeat the conversion factors I got, as that would mean that I have to make a complete setup up as described above and take the charger apart. Hope I guided you in the direction and as long as you keep tinkering, I hope you get the conversion factors 😉

      Regards: Roland.

  5. Avatar Daniele Senatore on June 6, 2016 at 5:08 pm

    Hello!
    First of all, thank you for sharing this wonderful project.
    I have a question about the transformer: where do you have found a transformer with that outputs? I think it have to be with 18V and 9V outputs, but I didn’t find it. Can you help me?
    Thank you in advance.
    Daniele

  6. Avatar Reyad Haddad on September 30, 2016 at 4:30 am

    Very Nice Project. From what I read this can charge batteries at 5A. How can I increase that to 10A or Even 15?

  7. Avatar Debasis Chakraborty on August 4, 2017 at 1:53 am

    How can be modify the battery charger to support 24V 30-40 Ampere Charging or 72 V 40 Ampere charging. Please if you could change and send me the schematics, it will be quite helpful.

  8. Avatar Mark Oude Elberink on August 2, 2019 at 6:22 am

    Hi,
    Could I run this project on 40V as input?
    I think the only problem would be the power supply of the Arduino, but this could be solved with a lm2596…

    Another question is if i could use other MOSFETS like the IRFZ48N ( 55V max. 64Amps and threshold about 5V ) and if i would need a MOSFET driver for that…

    It would be quite helpful if you could tell me if that would work and if not then some other suggestions…

    Thanks in advance

  9. Avatar Sanchit Jain on September 19, 2019 at 12:59 am

    Hey, great project indeed. But I had a query. I need to create a circuit that charges a lithium ion battery from solar panel and also from mains. And if the battery is fully charged and I connect my appliance to a DC power source, I want my appliance to run on it.

    In my case the appliance is an Arduino UNO controlled car. Hope you enlighten us.

Leave a Comment