Lithium Cell Protection in Arduino Projects

by yoh-there in Circuits > Arduino

3414 Views, 36 Favorites, 0 Comments

Lithium Cell Protection in Arduino Projects

191820424841_1_0_1.jpg
s-l1600.jpg
191736127467_1_2_1.jpg

If you happen to make Arduino based projects that are powered by a single LiPo cell (or any battery type), it pays off to try to minimise power. Slowing down the loop using not the regular delay function but sleep () from the LowPower.h library is the way to go. You also have to remove the power LED and the voltage regulator. Then using an Arduino board without USB interface, such as a bare ATtiny85 or an Arduino pro mini saves even more.

I have done this in the Star Finder project so you can see a practical implementation there: most of the time the Arduino is in a deep sleep using only a few micro-Amps and it will run for about a year on one charge.

LiPo cells though are easily destroyed by a deep discharge. As these long running devices can be easily forgotten, it is a good idea to check the battery state and warn the user it should be charged. I combined two ideas for this. One is the ability of the Arduino microcontroller to measure it's own Vcc voltage level, and the other is using a buzzer the same way a smoke detector does.

The credits for the battery voltage measurement code go entirely to Ivo Pullens.

Let's get started!

Add a Piezo Buzzer

262294293131_1_1_1.jpg

Add a buzzer to your project. Any buzzer that still runs on 3 volt DC is fine, but I would recommend piezo type buzzers for their irritating loudness. I found small ones on eBay for less than EUR 0.50 a piece. Make sure you buy the "active" type, as they contain the required oscillator.

Note that all active type buzzers have polarity. Wire the negative pin to ground of your project, and the positive pin to a free data pin of your Arduino. In this example I used pin D7.

No other hardware is used. No external voltage divider, no usage of an analog pin.

On to the software.

The Software

Add the following function and it's companion defines to your sketch. The function measures the battery voltage and will return TRUE as long as the battery voltage is above 3.2 volt.

#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define ADMUX_VCCWRT1V1 (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1))
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
#define ADMUX_VCCWRT1V1 (_BV(MUX5) | _BV(MUX0))
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
#define ADMUX_VCCWRT1V1 (_BV(MUX3) | _BV(MUX2))
#else
#define ADMUX_VCCWRT1V1 (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1))
#endif

boolean battery_check ()
{
	// set reference to VCC and the measurement to the internal 1.1V reference
	if (ADMUX != ADMUX_VCCWRT1V1)
	{
		ADMUX = ADMUX_VCCWRT1V1;
		delayMicroseconds(350);			// wait for Vref to settle
	}
	ADCSRA |= _BV(ADSC);				// start conversion
	while (bit_is_set(ADCSRA, ADSC)) {};		// wait for it to finish
	return (ADC < 351);				// false when Vcc < 3.2 V
}

Next, change your loop () to check for the battery voltage. If it is too low, beep the buzzer. Other than a smoke detector, it is probably also a good idea to stop doing what it needs to, so the warnings can be issued as long as possible.

loop ()
{
   if (battery_check ())
   {
      // do what needs to be done here
   }
   else
   {
      digitalWrite (7, HIGH);		// sound beeper
      delay (200);
      digitalWrite (7, LOW);
   }
   sleep ();				// power down processor, i.e. for 30 seconds
}

And that's it. Of course it is not mandatory to add a buzzer, you can also simply shut down as many functions as possible to avoid further battery draining for as long as possible, but your project simply not working would be the only indication that the battery is low.

I reused most of this project in the Li-Ion discharger instructable.