Smart battery discharger/tester

Hi,

Some (most) of us are PR**LX renegades :wink:
During this Dark Age, I built a battery discharger using a 12V lamp as resistive load. This was the good old time when an Analog Input had to be emulated through an RC circuit...
The purpose of such a device is to evaluate the actual capability of a AA (R6) battery, in term of mAh
This smart version is based on an electronic load, with fixed/adjustable discharge current.

Here it is:


Smart battery discharger/tester diagram

The NPN transistor acts as a variable resistor
Current is sensed through a shunt resistor; the corresponding voltage is fed back to the inverting input of an OpAmp configured as a comparator. The non inverting input is set at a reference voltage value through an adjustable voltage divider.
In an effort to have both input at the same level, the OpAmp will output the adequate signal which is fed to the NPN transistor base
To avoid full depletion of the battery, a relay disconnects the battery below 500mV. This sub miniature relay is directly driven by the Arduino
I used TIP41C and LM324, but any GP OpAmp and NPN transistor will fit the bill; just make sure that the max allowable collector current is over 2 Amps.
Volts and Amps are acquired through AI0 and AI1, mAh are computed by integrating Amp over time


Breaboard implementation

Caution: This device is designed to convert electric power to HEAT :o
The power dissipation can be calculated, or simulated in LTSpice
according to datasheet, the TIP41C transistor can dissipate up to 65W. Don't take the info for granted; this value assumes that collector temperature remains at 25°C which is unrealistic.
For more than a couple of Watts, install a suitable radiator on the component.
To avoid destroying the component it is advisable to limit max power within the code


LTSpice simulation X axis = potentiometer wiper relative position (0-100%)

Arduino code is straightforward. The main point is to create a fixed time loop for accurate mAh integration.

What I learnt on batteries:
Not all batteries are created equal; I get results from 662 to 2764 mAh (all AA size)
Ageing does reduce battery capacity; some batteries where discarded after test
Internal resistance is a real issue, 1500 mAmp will definitely bring voltage down, below 1 Volt.

What I learnt as a bonus:
NPN Bipolar Junction Transistor in the active region, versus saturation region Bipolar junction transistor - Wikipedia
Operational amplifier (comparator configuration) Comparator - Wikipedia
Circuit simulation using LTSPICE (a magic world)
and... learning to post on a message board

Additional readings
TIP41C datasheet: TIP41C Datasheet pdf - General Purpose Amplifier and Switching Applications - Boca Semiconductor Corporation
LM324 datasheet: LM324 Datasheet pdf - Low Power Quad Operational Amplifiers - BayLinear
LTSpice Homepage: Design Tools & Calculators | Design Center | Analog Devices
LTSpice Tutorial: http://claymore.engineer.gvsu.edu/~steriana/Videos/

Next steps

  • Add some decoupling capacitor (should I ???)
  • Take into account Base/Emitter current in calculation
  • Use a MCP3208 12 bits A/D Converter for further accuracy
  • install an LCD display and piezo buzzer for stand alone operation
  • reconnect to PC for graphical trends of voltage versus time

Thanks for reading

1 Like

Oops... forgot the code ::slight_smile:

Here it is

//Battery monitoring      V1      Basic edition
// Copyleft KAS         November 2009

#define     VMIN              700           // Battery protection      Vmin > WMIN
#define     WMAX              2000          // Transistor protection   Wmax < WMAX
#define     LOOP              2000          // loop time (ms)

#define     Vpin              0             // battery voltage pin
#define     Apin              1             // Amp reading pin
#define     RELAY             3             // relay pin

long loopTime = LOOP;
long loopUsedTime = LOOP;
long loopStart = 0;
float mVolt = 0;
float mAmp = 0;
float mW = 0;
float mAmpH = 0;
long loopCount = 0;
boolean testOn = false;

void setup()  {
  Serial.begin(19200);
  pinMode(RELAY, OUTPUT); 
  digitalWrite(RELAY,HIGH);                     // Close relay
  testOn = true;
  delay(100);
}

void loop()  {
  loopStart = millis();
  
  mVolt = getmVolts();
  mAmp = getmAmps();
  mW = (mAmp * mVolt) /1000;
  mAmpH += mAmp * loopTime / 3600 /1000;
  if(testOn)    display();
  else          while(1);                    // Loops forever
  testStop(VMIN, WMAX);

  loopCount++;
  loopUsedTime = millis()-loopStart;
  if(loopUsedTime < LOOP)         delay(LOOP - loopUsedTime);
  loopTime = millis() - loopStart;
}

int getmVolts()  {
  return int(analogRead(Vpin)*4.8828125);          // read the battery voltage
}

int getmAmps()  {
  return int(analogRead(Apin)*4.8828125/0.47);      // read the Amps
}

void display()  {
  Serial.print(loopCount/(60000/LOOP));                Serial.print(":");
  if(((loopCount%(60000/LOOP))*LOOP/1000)<10)          Serial.print("0");
  Serial.print((loopCount%(60000/LOOP))*LOOP/1000);    Serial.print("    ");
  Serial.print((int)mVolt);                            Serial.print(" mV   ");
  Serial.print((int)mAmp);                             Serial.print(" mA   ");
  Serial.print((int)mW);                               Serial.print(" mW       ");
  Serial.print((int)mAmpH);                            Serial.println(" mAh");
}

void testStop(float Vmin, float Wmax)  {
  if((mVolt < Vmin)||(mW > Wmax))
  {  digitalWrite(RELAY,LOW);                      // disconnect tested battery
     testOn = false;
     Serial.println("Stop");  
  }
}

Interesting, to say the least.

Some questions for you: your objective is to measure battery capacity (Ah). And you also want to measure linearity of this capacity. Is this right ?

Internal resistance is a real issue, 1500 mAmp will definitely bring voltage down, below 1 Volt.

Surely. This is due to how batteries work internally, chemically speaking.

  • Add some decoupling capacitor (should I ???)

No need. What for ?

  • Take into account Base/Emitter current in calculation

It's too small compared to C-E current. But yes, perform a slight adjust.

  • Use a MCP3208 12 bits A/D Converter for further accuracy

Time is more important here than instantaneous current. IMHO. So make sure your timebase is accurate. But you're measuring voltage between ground and D2? if so, you're actually (if you compensate for the resistor temperature) measuring current. If you place R2 between ground and battery (-), then you can more accurately see discharge current.

  • reconnect to PC for graphical trends of voltage versus time

I might help here :slight_smile: Send me an email or so if you're interested to test my new serial protocol http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1257971980/23#23
Álvaro

Hi Alvaro,

Thanks for the kind words; As your mention, the objective is to measure capacity (mAh) and the influence of current load (mA) on battery behaviour.

If you place R2 between ground and battery (-), then you can more accurately see discharge current.

I do compute mA based on mV between D2 and ground
If I place R2 between ground and battery (-), the battery voltage measured at D3 will be biased, won't it??

I might help here Send me an email or so if you're interested to test my new serial protocol http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1257971980/23#23

:o :o good job... may be overkill for this application.
I just need to pass one integer every other second
I am developping the project using StampPlot lite
Will report progress this week-end

If I place R2 between ground and battery (-), the battery voltage measured at D3 will be biased, won't it??

Yes, but since you also know V(R2) you can compensate. Which might be easier than doing compensation based on transistor values (they vary quite a bit depending on junction temperature.

Álvaro

Yes, but since you also know V(R2) you can compensate.

Got it: V(bat) = V(A0) - V(A1) :wink:

This is Version 2:
I have also modified D1 and D2 to A1 and A2 to reflect the (analog) type of measurement

Thanks Alvaro

Code modification for Version 2 as suggested by Alvaro:

getmVolts() should be modified as follow:

int getmVolts()  {
  return int((analogRead(Vpin)-analogRead(Apin))*4.8828125);          // read the battery voltage
}

This chart reflects the discharge process (@1C) of a 1.2V AA battery:

The diagram is obtained using Stamp Plot light from Selmaware.
This freeware can be obtained here: www.parallax.com/tabid/441/Default.aspx :wink:

Additional code:

#define     CHART             1             // Trend mode

In setup():

#if defined CHART
  delay(200);                                                       //------- Stamplot ---------------
  Serial.print("!TITL Battery tester");  Serial.print(13, BYTE);    // Set window title
  Serial.print(MESSAGE);                 Serial.print(13, BYTE);    // Set Status message
  Serial.println("!PNTS 6000");          Serial.print(13, BYTE);    // Set number of data points to collect
  Serial.println("!SPAN 500, 1500");     Serial.print(13, BYTE);    // Set maxi & mini range
  Serial.println("!AMUL 1");             Serial.print(13, BYTE);    // Set the value to multiply da
  Serial.println("!CLRM");               Serial.print(13, BYTE);    // Clear the message list
  Serial.println("!CLMM");               Serial.print(13, BYTE);    // Clear the MIN/MAX values
  Serial.println("!RSET");               Serial.print(13, BYTE);    // Reset the plot and all data
  Serial.println("!TMAX 3600");          Serial.print(13, BYTE);    // seconds maxi on x axis
#endif

in display():

#if defined CHART                                                 //StampPlot data for trending
    Serial.print((int)mVolt);            Serial.print(13, BYTE);
#endif

Amazing work. Let me congratulate you for the achievement!

What exactly are you plotting there ? battery voltage vs. time ?

I wonder if you can overlay also current (or voltage across sense resistor). I am curious if integration of this one will lead to "700mAh" they advertise.

Any chance you can provide me the data (data points+timebase) for both ?

Best,

Álvaro

Hi Alvaro

What exactly are you plotting there ? battery voltage vs. time ?

Yes, Battery voltage (mV) versus time; I am sure you recognized the typical S shape.

I wonder if you can overlay also current (or voltage across sense resistor)

Data,including time, appear in the list box at the bottom of the diagram.
Current is kept at a constant value and needs no trending.

For this test: I=700mA, mAh integration ended up at 658 mAh, total discharge time: 56' 20"

I am preparing the LCD stand alone version, I hope to be ready this week end.

Now, the stand alone version with integrated LCD

This a serial display, back from my Prll*x time :wink:

The additional code

#define     LCDdisplay       1           // LCD display

In Setup()

#if defined LCDdisplay
  pinMode(TXPin, OUTPUT);              //------LCD setup-------//
  digitalWrite(TXPin,HIGH);   
  LCD.begin(9600);                     //9600 baud is chip comm speed
  LCD.print(22, BYTE);                 // cursor off, no blink
  LCD.print(12, BYTE);                 // clear screen
  delay(5);                            //----------------------
#endif

in display()

#if defined LCDdisplay
  LCD.print(12, BYTE);                         // **LCD**  clear screen
  delay(5);                                     
  LCD.print(L1, BYTE);
  if((loopCount/(60000/LOOP))<100)             LCD.print("0");
  if((loopCount/(60000/LOOP))<10)              LCD.print("0");              
                                               LCD.print((loopCount-1)/(60000/LOOP));
  LCD.print(L1+3, BYTE);                       LCD.print(":");
  LCD.print(L1+4, BYTE);
  if(((loopCount%(60000/LOOP))*LOOP/1000)<10)  LCD.print("0");              
                                               LCD.print((loopCount%(60000/LOOP))*LOOP/1000);
  LCD.print(L1+8, BYTE);                       LCD.print("mAh");
  LCD.print(L1+12, BYTE);                      LCD.print((int)mAmpH);
  LCD.print(L2, BYTE);                         LCD.print("mV");
  LCD.print(L2+3, BYTE);                       LCD.print((int)mVolt);
  LCD.print(L2+9, BYTE);                       LCD.print("mA");
  LCD.print(L2+12, BYTE);                      LCD.print((int)mAmp);
#endif

That's all folks, hope you enjoyed reading

@+

Prll*x

Whats this ? and why the necessity to cloak it ?
Are you using this in the picture . What is its relevence?

Prll*x

Whats this ? and why the necessity to cloak it ?
Are you using this in the picture . What is its relevence?

Private joke :wink:
Some of us started learning microcontrollers with the Basic Stamp from Parallax: BASIC Stamp - Parallax

Easy language, tons of documentation,
allthough technically limited, Basic Stamp is, in my opinion, the best option for absolute beginers (Julien... ::slight_smile: )

Hello Kas,

your battery discharger is exactly the type of projects I bought my Arduino for, but I'm afraid I'm not fit enough yet to get it done by the plan and the photos, so I would very much appreciate if you could answer me some questions:
-what is the green (quite big) part on your photos? I assume it is R2? You talk about a shunt resistor in your text. Is this the part and what are the specifications that I have to search for when I would like to order it?
-I would like to build your AdaFruit Shield version. In the photo I saw that you use a different IC there. Is it LM358N? Is it used the same way as the LM324?
-Do you have some more photos of the AdaFruid Shield version? Is it Version 2 already?
-how is the jumper for different voltages wired?

Thanks in advance. I'm looking forward to measure the capacity of my rechargeable battery collection (mainly AA and AAA-types)

Hi bitcurrent

You are right, the green big thingy is R2; this is a 0.47R 8W shunt resistor (SETA RB60)
Only one OpAmp is required for this project.
LM324 is a Quad OpAmp, LM358 is a dual OpAmp, both are inexpensive and OK for the job.
I finally switched to LM358 (8 pins) to save room on the PCB

The top side looks nice

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1266140108

The other side is... a bit more cluttered :wink:

Adafruit shield is V.5 as per Adafruit Proto Shield for Arduino Kit [v.5] : ID 51 : $15.00 : Adafruit Industries, Unique & fun DIY electronics and kits

My advices:
First build your prototype on a breadboard Half Sized Premium Breadboard - 400 Tie Points : ID 64 : $4.95 : Adafruit Industries, Unique & fun DIY electronics and kits
Install only basic parts, ignore relay, buzzer and voltage divider
You don't need the heatsink if you only want to test AA or AAA batteries
Make sure everything is OK before any soldering
Develop a simple software that displays Volts and Amps on your computer.
It will be easy to add features once you have the basic design right

Oh... I finally built vesion 1 circuit, please ignore V2
Good luck,this is a very educational project

Nice one.... Something I wanted to try for a long time... Will try this out.

Hello Yves,

Thanks a lot for your clarifications, I think I should be able to rebuild it now. I will of course first try to breadboard before I build the final shield version. A (hopefully) last question about the resistor:
What's the reason for using a 8W resistor? I thought that the transistor acts as the load and the resistor should therefore stay "cool" and does not need to have 8W. Or is it because of the precision of that types of resistors? What other kind of resistor could I use here? (it is not so easy to get, so I'm looking for alternatives)

Thanks again!

Hi bitcurrent

Heat is actually shared among the two components (transistor, shunt).
You can use a 5W resistor, not less.
Heat will change resistor value and decrease accuracy
Another option is to choose a 0.1 R shunt, 1W should be OK
Don't forget to modify the code

Hi, I saw your smart arduino battery discharger today from randomly surfing and is very interested. I have a few question hopefully you can help me out with it .

The question I have is about the NPN variable resistor.

From what I understand the op-amp used as a comparator is used to limit the current draw from the battery? That if I set the Vref to 2V and initially Vp is greater than Vn in the opamp so comparator output goes to high 5V and the NPN is turned on and current flows through the shunt resistor. And if current is too high then the feedback voltage Vn is now greater than Vp and comparator output goes Low and the BJT is turned off.

I am just wondering if my observation is correct if not please shed some light on me

Hi aznweirdo

That's what it is :slight_smile:

according to Wikipedia:

When the non-inverting input (V+) is at a higher voltage than the inverting input (V-), the high gain of the op-amp causes it to output the most positive voltage it can. When the non-inverting input (V+) drops below the inverting input (V-), the op-amp outputs the most negative voltage it can. The OpAmp will output 0 or Vs (maxi) according to Vn-Vp sign.