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…