Go Down

Topic: Smart battery discharger/tester (Read 5 times) previous topic - next topic

kas

Nov 20, 2009, 03:47 pm Last Edit: May 20, 2014, 02:23 pm by kas Reason: 1
Hi,

Some (most) of us are P*R**L*X renegades  ;)
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   http://en.wikipedia.org/wiki/Bipolar_junction_transistor#Regions_of_operation
Operational amplifier (comparator configuration)    http://en.wikipedia.org/wiki/Comparator
Circuit simulation using LTSPICE (a magic world)
and... learning to post on a message board

Additional readings
TIP41C datasheet:    http://www.datasheetcatalog.com/datasheets_pdf/T/I/P/4/TIP41C.shtml
LM324 datasheet:     http://www.datasheetcatalog.com/datasheets_pdf/L/M/3/2/LM324.shtml
LTSpice Homepage:  http://www.linear.com/designtools/software/
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

kas

Oops... forgot the code   ::)

Here it is
Code: [Select]
//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");  
 }
}

Alvaro

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 ?

Quote
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.
Quote
- Add some decoupling capacitor (should I ???)

No need. What for ?
Quote
- Take into account Base/Emitter current in calculation

It's too small compared to C-E current. But yes, perform a slight adjust.
Quote
- 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.
Quote
- reconnect to PC for graphical trends of voltage versus time

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
Álvaro

kas

#3
Nov 23, 2009, 05:32 pm Last Edit: Oct 28, 2014, 07:59 am by kas
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.

Quote
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??


Quote
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

Alvaro

Quote
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

kas

#5
Nov 23, 2009, 06:52 pm Last Edit: Oct 28, 2014, 07:57 am by kas
Quote
Yes, but since you also know V(R2) you can compensate.
Got it: V(bat) = V(A0) - V(A1)   ;)

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


Thanks Alvaro



kas

Code modification for Version 2 as suggested by Alvaro:

getmVolts() should be modified as follow:

Code: [Select]

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

kas

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   ;)

Additional code:
Code: [Select]
#define     CHART             1             // Trend mode


In setup():
Code: [Select]
#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():
Code: [Select]
#if defined CHART                                                 //StampPlot data for trending
   Serial.print((int)mVolt);            Serial.print(13, BYTE);
#endif

Alvaro

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

kas

#9
Dec 02, 2009, 07:46 pm Last Edit: Oct 28, 2014, 08:00 am by kas Reason: 1
Hi Alvaro

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

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


kas

#10
Dec 05, 2009, 06:51 pm Last Edit: Oct 28, 2014, 08:00 am by kas
Now, the stand alone version with integrated LCD



This a serial display, back from my P*r*ll*x time  ;)

The additional code
Code: [Select]
#define     LCDdisplay       1           // LCD display


In Setup()
Code: [Select]
#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()
Code: [Select]
#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

@+

tytower

#11
Dec 05, 2009, 10:30 pm Last Edit: Dec 05, 2009, 10:31 pm by tytower Reason: 1
Quote
P*r*ll*x

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

kas

#12
Dec 07, 2009, 07:09 pm Last Edit: Dec 07, 2009, 07:15 pm by kas Reason: 1
Quote

P*r*ll*x

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


Private joke  ;)
Some of us started learning microcontrollers with the Basic Stamp from Parallax: http://www.parallax.com/tabid/295/Default.aspx

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

bitcurrent

#13
Apr 20, 2010, 07:23 pm Last Edit: Apr 20, 2010, 09:58 pm by bitcurrent Reason: 1
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)



kas

#14
Apr 24, 2010, 12:02 pm Last Edit: Oct 28, 2014, 08:01 am by kas Reason: 1
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 ;)



Adafruit shield is V.5 as per http://www.adafruit.com/index.php?main_page=product_info&cPath=17_21&products_id=51


My advices:
First build your prototype on a breadboard http://www.adafruit.com/index.php?main_page=product_info&cPath=17&products_id=64&zenid=f74428807bfbe75ac921a42ac9b73ff6
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


Go Up