Project LIBMS: Li-Ion Battery Monitoring System

Creative Commons LicenseLIBMS by Vaidas Sirtautas is licensed under a
Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
 Permissions beyond the scope of this license may be available
at https://sadiav.wordpress.com

Video

or you can watch in HD on Youtube.

Problem

Let’s start with a problem…

In order to have my phone as well as my BlueTooth audio headset working I had to carry two different chargers to workplace.  Moreover, I needed to find an unused socket to plug them in. And that’s really annoying…

Idea

I could see two possible solutions:

  • Buy a charger that uses batteries and provides 5V to charge my devices
  • Build one of my own

And, of course, I went with choice #2. I had some Lithium Ion batteries lying around. And this was the starting point of LIBMS.

LIBMS

It would be crazy to just power devices through some voltage regulator. LiIon cells do not like to be discharged below 3V and without some additional circuitry it was impossible to check whether they were OK to continue providing power to the devices. (Well, I could carry a multimeter and measure each of them from time to time, but that would be crazy :))

I found some IC’s that are capable of monitoring LiIon batteries, but where’s the fun in that…

I had some Atmega328 chips laying around. They have a 6 channel 10-bit ADC (there is actually only one ADC, but built-in multiplexer expands the inputs to 6). Awesome.

Batteries

I connected 3 of the batteries in series and then that block with another block of three batteries in parallel. V1..V6 show my tap points that are used to measure each cells voltage. E.g.

  • V(G2) = V2 – V1
  • V(G3) = V6 – V(G2)
  • V(G6) = V6 – V(G5)

Batteries are connected this way

Voltage regulators

At the beginning of this project I had some problems with voltage regulation. I powered the microcontroller (uC) directly from the main voltage regulator (LM338), but when a device was connected that requires a lot of current the voltage suddenly dropped and uC restarted. Not good…

I solved this problem by introducing secondary LM7805 voltage regulator that is used to power the uC and LM338 takes care of the USB ports. Using this structure provided me with a cool way for controlling the USB ports from uC.

Browsing through the LM338’s data-sheet I found an example where the regulator can be controller using a TTL signal. Perfect. Even though it does not shut down completely (there is still ~1.25V on the output), it does the job.

Sensing part

Because Atmega328 can measure up to 5V max, I had to scale down the voltages of the cells. To do that I used voltage dividers. There are 5 of them, connected to ports A0..A4. Resistors (with values specified) are R1..R10 in the schematic.

Schematic & PCB layout

*Click on the images for hi-res version.

There is a 10K pull-up resistor (not shown in schematic) connected from BC337 base to Vcc to ensure that Voltage regulator stays off while uC is starting up.

Code

This code was written using Arduino IDE (www.arduino.cc)

int analogValues [5];
int voltages[6];

unsigned char i; // Loop variable
byte LEDs = 0;
byte tempLEDs = 0;
boolean turnOn = true;
boolean updated = false;
boolean firstrun = true;
byte portVal;

byte LEDstates[] = {
0xFF, 0xDF, 0x9F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00};

void setup()
{
// Set Transistor's pin to output
pinMode(8, OUTPUT);
digitalWrite(8, HIGH);

// Set LED pins to outputs
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);

// Set analog inputs
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);
pinMode(A4, INPUT);

// Disable Pull-up resistors on analog pins
digitalWrite(A0, LOW);
digitalWrite(A1, LOW);
digitalWrite(A2, LOW);
digitalWrite(A3, LOW);
digitalWrite(A4, LOW);

for (i = 0; i < 9; i++)
{
tempLEDs = LEDstates[i];
updateLEDs();
delay(500);
}
delay(1000);
}

void updateLEDs()
{
PORTD = (PORTD & 0x1F) | (tempLEDs & 0xE0);
PORTB = (PORTB & 0xC1) | ((tempLEDs & 0x1F) << 1);
}

// Scale because of voltage divider by 2.624
void loop()
{
if (turnOn && updated)
{
digitalWrite(8, LOW);
updated = false;
}
if (!turnOn && updated)
{
// Serial.println("turn OFF");
digitalWrite(8, HIGH);
updated = false;
}

// Read status of all batteries
for (i = 0; i < 5; i++)
{
analogValues[i] = analogRead(i);
delay(10);
}

voltages[0] = analogValues[4];
voltages[1] = analogValues[3] - voltages[0];
voltages[2] = analogValues[2] - voltages[1] - voltages[0];
voltages[3] = analogValues[1];
voltages[4] = analogValues[0] - voltages[3];
voltages[5] = analogValues[2] - voltages[4] - voltages [3];

// Take care of low voltage per cell situations
//  Minimum threshold for a cell is 3.0V.
// Minimum value is 3/(5/1024) = 614.4
// Scaled because of voltage divider by 2.624,
//   so 3V = 614/2.624 = 234 units
boolean stopLoop = false;
i = 0;
while ( i < 6 && !stopLoop)
{
if (voltages[i] < 234)
{
stopLoop = true;
turnOn = false;
updated = true;
digitalWrite(8, LOW);
// Enter infinite
loop while (1) { };
}
i++;
}
//Serial.println(analogValues[2], DEC);
// Take care of LED's
if (analogValues[2] > 920) // 11.8V
tempLEDs = LEDstates[0];
else
if (analogValues[2] > 889) // 11.4V
tempLEDs = LEDstates[1];
else
if (analogValues[2] > 858) // 11.0V
tempLEDs = LEDstates[2];
else
if (analogValues[2] > 827) // 10.6V
tempLEDs = LEDstates[3];
else
if (analogValues[2] > 796) // 10.2V
tempLEDs = LEDstates[4];
else
if (analogValues[2] > 765) // 9.8V
tempLEDs = LEDstates[5];
else
if (analogValues[2] > 734) // 9.4V
tempLEDs = LEDstates[6];
else
tempLEDs = LEDstates[7];

// Something changed in total battery voltage
if (LEDs != tempLEDs)
{
LEDs = tempLEDs;
updateLEDs();

/* My old idea...

// First three LED's
tempLEDs = tempLEDs >> 5; // Right shift by 5 to get first three bits
tempLEDs = tempLEDs << 5;

portVal = PORTD;
portVal = portVal << 3; // Right shift to get rid of last three bits; portVal = portVal >> 3; // Left shift to restore first 5 bits to their positions
PORTD = portVal | tempLEDs;

// Restore temp value that changed because of all the shifting
tempLEDs = LEDs;

// Last five LED's
portVal = PORTB;
tempLEDs = tempLEDs << 3; // get rid of first three bits tempLEDs = tempLEDs >> 2; // position temp byte correctly

if (turnOn) tempLEDs = tempLEDs | 1;
PORTB = tempLEDs;

// Restore temp value that changed because of all the shifting
tempLEDs = LEDs;
*/

}

if (firstrun)
{
updated = true;
turnOn = true;
firstrun=false;
}

// Delay before next run
delay(1000);
}

 

Eagle files

Will be uploaded later

Advertisements

About Vaidas Sirtautas

http://vsshs.com

Posted on April 29, 2011, in Electronics, Projects, Uncategorized. Bookmark the permalink. 1 Comment.

  1. Lithium Ion batteries was known to be high powered and heavy duty as compared to its predecessor such as the Nickel Cadmium and the Alkaline Batteries. Well, many were born before the use digital cameras into the market. During the 1990’s the alkaline battery was the most used batteries; it is known to provide power to almost any digital or portable device. This is was the proffered choice of many during the said decade. But everything changed during the introduction of digital cameras and mobile phones especially the battery packs used in these devices.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: