Computing stuff tied to the physical world

What if we want to know the battery state?

In Hardware on May 15, 2013 at 00:01

Welcome to the weekly What-If series, also available via the Café wiki.

One useful task for wireless sensor nodes, is to be able to determine the state of the battery: is it full? is it nearly depleted? how much life is there left in them?

With a boost converter such as the AA Power Board, things are fairly easy because the battery voltage is below the supply voltage – just hook it up to an analog input pin, and use the built-in ADC with a call such as:

word millivolts = map(analogRead(0), 0, 1023, 0, 3300);

This assumes that the ATmega is running on a stable 3.3V supply, which acts as reference for the ADC.

If that isn’t the case, i.e. if the ATmega is running directly off 2 AA batteries or a coin cell, then the ADC cannot use the supply voltage as reference. Reading out VCC through the ADC will always return 1023, i.e. the maximum value, since its reference is also VCC – so this can not tell us anything about the absolute voltage level.

There’s a trick around this, as described in a previous post: measure a known voltage with the ADC and then deduce the reference voltage from it. As it so happens, the ATmega has a 1.1V “bandgap” voltage which is accurate enough for this purpose.

The third scenario is that we’re running off a voltage higher than 3.3V, and that the ATmega is powered by it through a voltage regulator, providing a stable 3.3V. So now, the ADC has a stable reference voltage, but we end up with a new problem: the voltage we want to measure is higher than 3.3V!

Let’s say we have a rechargeable 6V lead-acid battery and we want to get a warning before it runs down completely (which is very bad for battery life). So let’s assume we want to measure the voltage and trigger on that voltage dropping to 5.4V.

We can’t just hook up the battery voltage to an analog input pin, but we could use a voltage divider made up of two equal resistors. I used two 10 kΩ resistors and mounted them on a 6-pin header – very convenient for use with a JeeNode:


Now, only half the battery voltage will be present on the analog input pin (because both resistor values are the same in this example). So the battery voltage calculation now becomes a variant of the previous formula:

word millivolts = map(analogRead(0), 0, 1023, 0, 3300) * 2;

But there is a drawback with this approach: it draws some current, and it draws it all the time. In the case of 2x 10 kΩ resistors on a 6V battery, the current draw is (Ohm’s law kicking in!): 6 V / 20,000 Ω = 0.0003 A = 0.3 mA. On a lead-acid battery, that’s probably no problem at all, but on smaller batteries and when you’re trying to conserve as much energy as possible, 0.3 mA is huge!

Can we raise the resistor values and lower the current consumption of this voltage divider that way? Yes, but not indefinitely – more on that tomorrow…

  1. The resistor are connected like:

    Vcc – R1 – ADC – R2 – Gnd

    the leakage is from Vcc through R1 plus R2 to ground.

    If you now make it as follows:

    Vcc – R1 – ADC – R2 – Port

    Then if the Port is set to output, low, it is almost at Gnd level, thus the divided voltage can be measured.

    If we do not want to measure, we set the Port to input, and thus should have almost no leakage.

    This has some loss in accuracy, but the “grounded” Port should be very close to real ground….

    • This has a flaw, alas: when the pin is left floating, the centre tap of the resistor divider still has a path to VCC through an internal ESD protection diode, so that pin will be pulled to VCC + 0.6V – IOW this reduces but does not entirely eliminate the leakage current.

  2. OK, So now we’ve got the voltage what can we do with it?

    It would be good to send a packet when the battery is nearly flat, so how would you calculate that threshold?

    For example running off 3 AA batteries we should have 3×1.5v (for alkaline) – 4.5v total. Is it the case that anything less than 3.3v should trigger? I have a feeling there are a lot of variables.

  3. It’s less about the absolute battery voltage (which needs correcting for temperature BTW) and more about the shape of the discharge curve. Two shapes are interesting:

    * The rapid fall off from the “plateau” portion of the discharge curve near charge end point
    * The increasing voltage drop off during or immediately after a ‘heavy’ load on the battery – this is a good estimator of the rise in the battery internal resistance that occurs close to exhaustion

    Either or a combination of these IMHO give a reliable predictor of end of useful charge. Of course, for some rechargeable chemistries, the discharge should stop much earlier to prevent cell life reduction from over deep discharge.

    Cells in series pose extra problems – even from the same manufacturing batch and with the same charge history, one cell will hit exhaustion before the others. Current then is driven “backwards” through that cell; generally a bad idea. Even “leakproof” dry cells are liable to start exuding icky stuff at this point. The rough solution is not to discharge beyond (n-1) x Vfresh but that is pessimistic and leaves some accessible charge undrained.

  4. So are there any more generic/simple rules we can follow here.

    Most of the wireless weather stations have some form of battery indicator and they can’t possible know what type of batteries are in use, but they still manage to warn of low battery conditions.

Comments are closed.