Arduino Battery Capacity Tester Memory Leak
Arduino Battery Capacity Tester Memory Leak
com/blog/2009/11/08/arduino-battery-capacity/
The Atmel ATMega328 microcontroller has 6 analog inputs with 10-bit A-to-D converters and a external AREF that allows you to define what voltage 0x3FF
represents. In other words, it’ll give you ~1.4mV precision measuring 0-1.5V when given a 1.5V analog reference. Plenty accurate for a battery capacity
measurement.
The principle is fairly simple. Apply a known load to a battery, record the voltage periodically while the battery discharges, stop recording at some point, and
integrate to arrive at the area under the curve in order to derive the amp-hours delivered from the battery.
Enough theory, let’s see how it works. The UI starts with a helpful message:
Insert Battery
While the battery discharges, the UI prints the voltage, real-time capacity measured thus far, and the duration that the measurement has been taking place.
Battery In
Arduino battery capacity tester « Memory Leak http://www.foobert.com/blog/2009/11/08/arduino-battery-capacity/
When the cut-off voltage of 0.9V has been reached, the “usable” capacity is saved at the top. The real-time data continues so the capacity below 0.9V is
measured. For the NiMH batteries I’ve tested, the capacity below 0.9V is minimal (~100mAH).
After the cut-off is reached, an LED starts blinking to attract attention that the test is effectively over.
Done
Arduino battery capacity tester « Memory Leak http://www.foobert.com/blog/2009/11/08/arduino-battery-capacity/
Here’s the code (click to download as text rather than the questionable HTML translated version pasted below):
/*
Battery Characterization Tool
This uses the analog in to measure the voltage of a battery under a known load and
integrates the area under the curve to arrive at the useful capacity of the
batterin in mAH.
*/
#include <LiquidCrystal.h>
// Set some constants -- these will need to be adjusted for your setup
//
// Connect a ~10KΩ (Rr) resistor from 3.3V supply pin to the AREF pin,
// creating a voltage divder with the internal 32KΩ resistor on AREF.
// aRefVoltage = supply_voltage * 32K / Rr
// Alternatively, measure the actual AREF voltage applied with a good DMM:
// my measured aRefVoltage = 2.62;
const float aRefVoltage = 2.62;
// Connect a load resistor (Rl) to the battery. ~2.2Ω restistor gives ~500mA drain which
// is about right for a battery rated at 2500mAH. Note, this should be a >=1W resistor!
// Dont trust your DMM to meausre such a low resistance accurately. I measured the current
// and back-calculated the resistance. Best just to trust rated resistance.
// my resistance = 2.2;
//
// The integrator works by accumulating the sampled voltage values from the start until
// hitting a pre-determined low-voltage threshold. Since they are sampled at a
// known period, the number of samples taken cancels out and the accumulation of all samples
// simply needs to be scalled by a factor
Arduino battery capacity tester « Memory Leak http://www.foobert.com/blog/2009/11/08/arduino-battery-capacity/
//
// Let's make some definitions to show the derivation of how this is so:
// I = current
// V = load voltage
// Rl = load resistance
// samples = number of voltage samples made
// sensor = value read out of analog A->D
// rate = number of samples taken per second
//
// ave(V)
// capacity = ∫I ~= ave(I) * time = ----------- * time
// Rl
//
// Where:
// ∑(V) ∑(sensor) * aRefVoltage/1024
// ave(V) = ------- = ---------------------------------
// samples samples
//
// time = samples/rate
//
// Thus:
// ∑(sensor) * aRefVoltage samples
// capacity = ----------------------------- * ----------
// samples * 1024 * Rl rate
//
// ∑(sensor) * aRefVoltage
// capacity = ------------------------------ = ∑(sensor) * quanta
// 1024 * Rl * rate
//
//
// aRefVoltage
// quanta = --------------------
// 1024 * Rl * rate
//
// rate in this sketch is 1 Hz (1/sec).
// Thus, the units of quanta are: volt*seconds/(Ω*samples) = amp*seconds per sample
//
// What we really want are mA*Hours, so, scale by 1hr/3600seconds and 1000mA/A, or simply 1/3.6
//
// So, finally:
// quanta = aRefVoltage/(Rl*1024*3.6) in units of mA*hours per sample
int sensorPin = 0; // select the analog input pin for the voltage measurement
int ledPin = 13; // select the pin for the LED
int fetGatePin = 8; // select the pin for the LED
int sensorValue = 0; // unscaled sensor output
float voltage = 0; // measured voltage
double mAH = 0; // Calculated current
long accumulator = 0; // sum of all unscalled sensor values sampled
int epoch = 0; // seconds since battery was inserted
int lowVolts = 0; // debounce the low voltage threshold
boolean done = false;// Voltage has dropped below threshold
boolean batteryIn = false;// Battery present
// initialize the the LCD library with the numbers of the interface pins
// LCD Pins -- RS, EN, D4, D5, D6, D7
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
// declare the ledPin and fetGatePin as an OUTPUT:
pinMode(ledPin, OUTPUT);
pinMode(fetGatePin, OUTPUT);
void loop() {
Arduino battery capacity tester « Memory Leak http://www.foobert.com/blog/2009/11/08/arduino-battery-capacity/
sensorValue = analogRead(sensorPin);
voltage = sensorValue*aRefVoltage/1024.0;
// print voltage
lcd.setCursor(0, 1);
lcd.print(voltage);
if (!done) {
accumulator += sensorValue;
// print mAH
mAH = accumulator*quanta;
if (mAH < 10) { lcd.setCursor(8, 1); } // adjust to make it perdy
else if (mAH < 100) { lcd.setCursor(7, 1); }
else if (mAH < 1000) { lcd.setCursor(6, 1); }
else { lcd.setCursor(5, 1); }
lcd.print(int(mAH));
if (!done) {
epoch++;
} // batteryIn -- main routine
if (done) {
// When done, flash the LED to get attention
digitalWrite(ledPin, HIGH);
delay(500);
Arduino battery capacity tester « Memory Leak http://www.foobert.com/blog/2009/11/08/arduino-battery-capacity/
digitalWrite(ledPin, LOW);
delay(499);
} else {
// Since the processing takes some time prior to the delay, we'll assume 1mS
// This could stand to be improved with an interrupt routine that is kicked off
// before all the processing starts for each loop
delay(999);
}
/* DEBUG
Serial.print("\nsensor = " );
Serial.print(sensorValue);
Serial.print("\t lowvolrs = " );
Serial.print(lowVolts);
*/
}
extremesanity
January 24, 2010 at 5:02 am · Reply
Thanks for the info!
MichaelDallas
March 21, 2010 at 3:06 pm · Reply
I am wondering about your code. It seems to have errors such as the #include not listing any files. The compiler gives me a few more errors
as well. Is this your actual code?
MichaelDallas
March 21, 2010 at 3:20 pm · Reply
Okay. The two things that you need to change to make the code run is to change “#include” to “#include ” and to change “else if (batteryIn
&& done && (sensorValue < = 20)) {" to "else if (batteryIn && done && (sensorValue <= 20)) {" (i.e. change "< =" to "<=" by removing the
space.)
Thanks for posting this project.
MichaelDallas
March 21, 2010 at 3:22 pm · Reply
After the #include you need to list the LiquidCrystal.h file. This site won’t print the code for some reason.
john
March 21, 2010 at 3:46 pm · Reply
Thanks Michael — Didn’t even notice that the cut-paste of code was partially interpreted as HTML.
Fixed.
In any case, the “Here’s the code” has always been a link to the text — much better than cutting/pasting from the browser
MichaelDallas
March 23, 2010 at 8:23 pm · Reply
I’ve constructed a version of this. I noticed your comments about not trusting the VOM on the low R (ohm) readings and to measure the
current and calculate backwards. You may want to reconsider. I assume you said this because you had problems making the calibration
numbers balance (V/I=R). My calculation seemed to indicate an additional .7R to .8R in the system (in addition to the 2.1R resistors). I finally decided to
measure the VOM which was measuring current with another VOM for any R that the (first) VOM might be adding. Sure enough, the VOM measuring
current added .7R to .8R. While .7R doesn’t mean much in a high impedence system, it makes a big difference when added to 2R of the load resistors.
Thanks again for posting your example. I had independently thought of building this gadget. Your code saved me a ton of time.
Hector Albornoz
July 23, 2010 at 5:55 am · Reply
Thank you for this exciting project.
I have to test the batteries of 16V or 12V.
I could indicate how you made the connections or a Schematic of tester?
Scott Vitale
December 22, 2010 at 4:03 am · Reply
Hi John:
I was looking over your code/project. You put a lot of thought into the features … and its a good application for an ARDUINO.
I’m currently working on a project that is similar to yours but is acting as a chart recorder. I am testing Li-Ion charge/discharge characteristics for another
project. I had thought about using a simple resistor load but in using that method, the actual load current diminishes as the cell voltage decreases. In my
humble opinion, sinking constant current increases the accuracy of your measurments and is a “more correct” way to determine discharge ratings of a
battery.
In my application, I used a constant current sink. I chose a TL431 “Adjustable Precision Shunt Regulator”. On page 29 of the Texas Instruments data
sheet, there is a schematic for a “Precision Constant Current Sink”. You can power the TL431 from the ARDUINO 5V supply rail and attach the collector
of the sink transistor to your battery. Since the TL431′s “REF” pin has a constant 2.495V (+/-%), it could also be used as your A/D reference instead of
the resistor divider you used. The “Standard Grade” part has a +/- 2% tolerance, while the “B Grade” part sports +/- 0.5% tolerance.
Thanks for posting your work.
Best regards,
Scott
Andy
December 1, 2011 at 8:26 am · Reply
Hi Scott;
I too am interesting in creating a constant-current discharger/logger. Would the TL431-based constant current sink work with 1.2v nmh batteries?
Arduino battery capacity tester « Memory Leak http://www.foobert.com/blog/2009/11/08/arduino-battery-capacity/
Would using a MosFet in place of the BJT shown on the TI page work better?
John
December 22, 2010 at 9:07 am · Reply
@Scott: It’s good point, especially for LION where the discharge profile has the voltage steadily declining throughout the discharge cycle.
NiMH has a fairly stable voltage profile that falls off a “cliff” quite rapidly upon depletion. Thus, I suspect you’d see minimal difference in the
measured capacity for the two methods.
Constant power discharge would probably be the best method for applications that use nonlinear voltage regulation.
Andy
November 26, 2011 at 8:44 am · Reply
Thanks for posting this.
Did I miss the link to the parts list and schematic?
john
November 26, 2011 at 1:51 pm · Reply
Updated!
The usage of the FET to stop discharging probably isn’t entirely obvious to everyone. Thanks for motivating me to actually draw it out.
Andy
November 26, 2011 at 5:44 pm · Reply
john
November 26, 2011 at 7:18 pm · Reply
I didn’t exactly engineer it and just pieced it together to get the discharge current (drain-source ON resistance) I was looking for. I had
a hand-full of unspecified low-current transistors sitting around and I just put them all in parallel to minimize the resistance.
Really, most any N-channel FET that’s solidly saturated when Vgs>=4 V should work with a continuous current rating of >500mA. You’ll want to
account for the resistance of the FET and adjust accordingly to get an accurate measurement.
Perhaps this one would work fine for you.
Another way to do it is to use a relay, but that’s more costly. Alternatively, you could use nothing and just be ready to pull the battery out when it
hits the low-voltage threshold.
Andy
November 27, 2011 at 3:50 pm · Reply
Thanks for the info. I do hobby electronics (passives, transistors, op-amps, etc.) , but I’m not really up on MosFets. I want to take your idea
(and thank you for posting it) and modify it to make the load constant-current by measuring the voltage drop across the resistor and varying
the gate voltage to keep the current constant, regardless of the voltage. And of course, shut off when the voltage on the battery gets to the safe
minimum.
Saw a circuit using an Op-Amp to drive the gate and keep the current constant, but not sure if I need the op-amp since I can use 2 of the A/D inputs to
measure the voltage drop directly and calculate the current draw. I’d use one of the PWM outputs and a cap to send a voltage to the gate.
Any suggestions on how I would go about choosing a suitable MosFet?
poperbu
April 20, 2012 at 10:14 am · Reply
Hi, I’ve “built” it and it works perfect with low voltage batteries, but I need to test batteries from 9 to 12v, and it shows me always 2.62 volts.
Could you help me please?
john
April 20, 2012 at 2:40 pm · Reply
The design is only intended for 1.5 volt batteries (nominal). There are a couple of ways you could adapt it for 12V batteries. The
biggest problem is that I doubt the analog input nor AREF input are suitable for usage above 5 volts. I could be wrong on that, so,
check the Atmel spec.
The simplest method to work around this is to use a voltage divider such that the measurement voltage is within the usable range of the analog
input. You would then have to scale the formula based on the percentage drop the measurement is taking compared to that of the actual voltage
of the battery. You’ll lose some amount of precision, but, it will probably prove to still be acceptably accurate.
Zuazua
July 10, 2012 at 11:55 am · Reply
Hello:
I do not know much about electronics and circuitry and stuff, but I would like to make this tester. I have an Arduino and I just follow the
Arduino battery capacity tester « Memory Leak http://www.foobert.com/blog/2009/11/08/arduino-battery-capacity/
instructions that people supply for these projects. I can solder and all that stuff and I have the LCD display, just like the one in the picture here. The only
thing that I think I need is how to connect the Arduino to the display. Could you please show a diagram or a description of how to connect it please?
Thank you
john
July 14, 2012 at 12:38 pm · Reply
Perhaps this will help: http://arduino.cc/en/Tutorial/LiquidCrystal
Note that the pin-out I used is probably different than the tutorial.
Safy Saeed
July 19, 2012 at 5:42 am · Reply
I am also building a similar project, can you tell me how would i be able to log the data measured over time in a txt file? I need to do this in a
remote location so serial connection is not an option, can you tell me how would i be able to log the data in a removable memory device
which can be put in computer later to plot graph of the discharge curve ?
cole
October 21, 2012 at 12:03 pm · Reply
i built this on a breadboard, but i didn’t have a 2.2 ohm resistor so i put 4 10 ohm ones in parallel to get 2.5 ohms, and i didn’t have a 0.1W
10k ohm resistor so i used 1/8W one. but when i turned it on, it gives me 2.62 volts constantly even with no battery inside. i am just
measuring an AA battery and i built everything else perfectly. please help soon I need this for a school project.
john
October 21, 2012 at 2:19 pm · Reply
That’s not much info to go on for debugging. Nothing you’ve described sounds like any problem. The first place I would look is to test
the the analog input to make sure it’s working correctly. Make a voltage divider to get a known voltage (measure it with a volt meter),
then disconnect the analog input wire, and apply the known voltage to the analog input pin you are using. The voltage displayed by the program
should match the value you measured. If it doesn’t, you’ll need to figure out why.
If analog input test works, then there is some problem with your battery measurement circuit and where it connects to the analog input.
Hope that’s helpful. Good luck!
cole
October 21, 2012 at 3:48 pm · Reply
thanks, my analog input was fine but it turned out that my AREF resistor wasn’t connected properly, now it works like a charm!
Wildan
May 2, 2013 at 10:41 am · Reply
From that circuit diagram of Arduino, it can be used for tester Lead Acid Battery capacity? or just used for AA batteries? Sorry for my
English. I’m newbie..
john
May 2, 2013 at 3:36 pm · Reply
As I mentioned in the comments above, the analog input is only good for a max of 5 volts. Most lead-acid batteries are greater than
5v, so, you’ll have to scale the analog-input to some voltage between 0-5 volts and adjust the formula for that scaling factor.
Also, the higher voltage will require a different discharge circuit to handle greater power dissipation.
Ankit
August 31, 2013 at 7:27 am · Reply
hi,i’m doing a project named as LEAD ACID BATTERY HEALTH TESTER so please guide me through the project as it is similar to the one
which you have made.
thanking you!!
john
August 31, 2013 at 7:30 am · Reply
Try this: http://lmgtfy.com/?q=lead+acid+battery+health+check
Michael Illingby
December 24, 2013 at 11:40 pm · Reply
Just wondering if you have thought about modifying this into a 4 or 8 simultaneous battery version?
I have about a hundred AA batteries, and doing this one at a time would be painful.
would love a upscaled version of this.
Also, would you be able to engineer a charging circuit into this? That way, you could charge, then test, then charge then test again, and see if cycling
improves performance.
Arduino battery capacity tester « Memory Leak http://www.foobert.com/blog/2009/11/08/arduino-battery-capacity/
Also an arduino newbie btw, but love the idea you have come up with here.
john
December 25, 2013 at 6:25 pm · Reply
The arduino has 8 analog inputs (IIRC), so, in theory, you should be able to scale this up quite simply. It’d be a good exercise to learn
about the arduino for someone just starting out
Steve
February 10, 2014 at 1:52 pm · Reply
There are several descrepancies between the code on this page and the downloaded text file. Whole chunks of code appear in one, but not
the other, and vice-versa. For example, the downloaded file will not work because there is no provision for turning the FET on!
Also, you explain how you arrive at “quanta” but then you calculate it differently – it is even different between the two pages – without explanation of how
or why.
I have managed to reconcile the two pages of code, but I cannot fathom how you arrived at the figures for “quanta”. I would love to build this project but I
have a different reference voltage (1.62V) and different load resistor (1 Ohm) and using your formula, the “quanta” figure is obviously not correct.
I have added PWM drive for the FET to give a constant current load which could improve accuracy – provided the “quanta” figure can be corrected.
Otherwise this is a nice project.
john
February 11, 2014 at 11:01 pm · Reply
Steve
February 12, 2014 at 6:33 am · Reply
Ro
March 1, 2014 at 6:00 am · Reply
I plan to make this circuit to measure the capacity of three series AA battery. So, I have a total of 4.5V. It does not exceed 5V of Arduino
safety input. Is this circuit and code compatible with it? Or do I need another AREF value? Please help. Any suggestion would be very
helpful to me.
john
March 1, 2014 at 1:50 pm · Reply
You’ll need to use an AREF that’s larger than the max voltage the 3 series batteries. On a 5V aurdino, you get 5V reference with the
AREF pin left open (floating).
Adjust the “quanta” calculation as needed for your AREF and Rl (load resistance), and you should be good to go.
Irvin
March 11, 2014 at 5:25 am · Reply
Hi john, may I ask something, I’m using the Arduino Uno R3 board, after I paste your code into my software my lcd doesn’t show anything. Is
it the datasheet different?
john
March 11, 2014 at 9:49 am · Reply
I’d suggest double checking the LCD connections match those that I used in the sketch.
Irvin
March 11, 2014 at 9:27 pm · Reply
Sir, sry for bothering u, I not really understand this sentences, can explain details a little bit more? =C
Arduino battery capacity tester « Memory Leak http://www.foobert.com/blog/2009/11/08/arduino-battery-capacity/
“Connect a load resistor (Rl) to the battery. ~2.2Ω restistor gives ~500mA drain which
is about right for a battery rated at 2500mAH. Note, this should be a >=1W resistor!”
Jonn
March 17, 2014 at 7:03 am · Reply
Hi John, Im doing a project similarly like battery capacity tester, But im using the Li-ion battery which is 4V, and resulting the lcd display
2.62volts and capacity has no value too. I saw yours comment on the others guy to change the AREF value. But If i use 4v battery and i
using 16 ohm for Rl is it able to work? Please guide me master =C, Thanks you
john
March 18, 2014 at 12:46 am · Reply
Yes, 4v Li-ion will work with some minor changes. Remove the resistor connected to AREF so you have the default 5v analog
reference voltage. Calculate the value of quanta accordingly for the new AREF value and different Rl value.
Jonn
March 18, 2014 at 2:25 am · Reply
Thanks for yours reply, just 1 more question , then the resistor which is R1 in the FET no need to change it if im using 4v? sorry
for my poor english .. Thganks for the help !!
john
March 18, 2014 at 7:42 am · Reply
R1 can be whatever value you like that results in an appropriate discharge current for your battery. Just remember, the
quanta calculation uses the ‘effective load resistance’ on the battery: R1 + ‘resistance of the FET while on’.