Monday, January 9, 2012

Arduino Based Battery Discharge Monitor

Trying to figure out the capacity left in a battery based on only its voltage is difficult. The equivalent-series-resistance (ESR) of the battery makes the cell's voltage a function of the current that is being drawn from it. For this reason I like to measure and plot the discharge of a battery, I am using, with a load current that matches my circuit. With this data I can estimate the capacity left in the battery at a given voltage.

I setup an Arduino Uno to measure a 9V battery's voltage along with a sense voltage to monitor the current leaving the battery through a 10 Ohm sense resistor.
I used the current sink from a previous project and set it to 100mA. I chose 100mA, because my Protostack Arduino Clone with LCD draws roughly 92mA from its DC input and the goal is to have this board estimate the battery capacity left based the 9V battery's measured voltage.
I modified my Adruino Protoshield to have two 220K Ohm (series) and 100K Ohm (shunt) voltage dividers put in front of the Analog Inputs AN0 and AN1. This will protect these pins from voltages higher than 5V and up to 15VDC. This protoshield also still has on the DS1307 RTC and CR2032 battery backup from my Arduino RTC project. This RTC will come in handy and allow me to reference my measured voltages to a given time on the DS1307.
 A little bit of hot glue acts as a strain-relief on the AN0, AN1 and GND wires.

The software is pretty straight forward. I grab the ADC counts read by AN0 & AN1 and then convert the counts to a voltage. I then have to scale the voltage based on the 220K & 100K Ohm resistor divider. After that I grab the Date and Time from the DS1307 RTC and print everything out the comport at 9600 baud. Then I wait a fixed length of time (1 second) and repeat everything,

My full sketch can be found here.

Below is my main loop routine:

void loop()
  // read the analog in value:
  BatteryValue  = analogRead(BatteryPin);
  SenseValue     = analogRead(SensePin);

  // convert the 0-1023 ADC value to a voltage (Note: 5V reference)
  BatteryValue  = BatteryValue/1023 * 5;
  SenseValue    = SenseValue/1023 * 5;
  // Compensate the Voltage for the external Resistor divider
  // (220K series, 100K shunt) in front of the AN0-1 pins
  BatteryValue  = BatteryValue / 0.315;
  SenseValue    = SenseValue / 0.315;
  CurrentValue = (BatteryValue - SenseValue) / SenseResistor;

  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);    

  // print the results to the serial monitor:
  Serial.print("\n" );
  Serial.print(hour, DEC);
  Serial.print(minute, DEC);
  Serial.print("\t\t" );                      

  delay(60000);   // 1 min Delay

The sketch outputs all the data in a nice table format out the comport and into Hyper Terminal or your other favorite Terminal application:
This data can then be cut & pasted into Excel and plotted:
The 9V battery lasted a little better than 4.5 hours at 100mA discharge before it gave up. You can see that a constant 1V difference between the Battery Voltage and the Sense Voltage is shown. This confirms that a constant 100mA was pulled through the 10 Ohm sense resistor via the current sink

To be continued...... Next I'll be writing a sketch to display hours left on the 9V battery powering my ProtoStack Arduino Clone.

Part II here:


  1. That is a great idea, thank you for sharing all the techniques and codes.

    what is arduino

  2. Hi there,

    is it possible to attach a lcd straight away to the prototype shield and output same results as what you do in it? if it is possible, can you give some hints and tips. thanks.

    1. i mean like in the second part. where you use the clone board.

  3. Q. Why not just sense the voltage drop across the load?
    Espically because you had a varible load to get your 0.1A.
    Why the seperate 10ohm resistor? Great work by the way.