Battery Monitor and Arduino clone

Does anyone has experience in building a battery monitory for an arduino clone? I am want to be able to change a 9v battery before it is below a certain voltage. So far I have try to use 2 resistors in series and reading the voltage but it seems that the battery is discharing really fast. Anybody can guide me on how to do this? If you can point me to schematics that would be great. Thanks

You do need a resistor voltage divider to read the battery voltage but as you have found the resister’s are also discharging the battery. A better way is to install a MOSFET switch between the battery and the resister divider controlled by an output pin. The MOSFET is turned on to read the battery voltage then turned off.

I have seen this discussed several times either here and/or on the SoR forum.

Consider using 10Mohm resistors in your voltage divider. That would drop the current down to less than half a microamp, which is far lower than the self-discharge on a 9V alkaline battery. Unless I’m missing something, there’s no need for the FET.

A possible problem with a high value resistor divider is the input impedance and leakage of the ADC. These will cause an error in the ADC value. However, one may be able to evaluate what the magnitude of the error is and compensate in software to get the battery voltage.

Many of the AD converters built into micros (NXP LPC parts for instance) have a relatively low input impedance, on the order of 10-50K. So a simple high value resistor voltage divider won’t work without buffering.

I’d go with the FET switch.

But don’t waste all that power you just saved with a linear regulator of the 9V. You definitely want to use a switcher.

The ATmega328 ADC’s input impedance is 100Mohm (typical), and leakage currents even on the digital side are quite low.

A lot of the early data sheets did not publish a spec on AD input impedance. While dedicated A/Ds usually have very high input impedance, because of pin sharing with digital lines and other circuitry, this often is not often the case in mixed signal parts.

from the ATmega spec-

The ADC is optimized for analog signals with an output impedance of approximately 10 kΩ or

less. If such a source is used, the sampling time will be negligible. If a source with higher impedance

is used, the sampling time will depend on how long time the source needs to charge the

S/H capacitor, with can vary widely. The user is recommended to only use low impedance

sources with slowly varying signals, since this minimizes the required charge transfer to the S/H

capacitor.

Yes, for many applications you do have to worry about the source impedance to ensure that the SH capacitor can charge, but not in this one. If the ADC can deal with a 10k source impedance at 7.5kHz (15ks/s), increasing the source impedance to 10m suggests that you could expect to get good sample and hold at 7.5Hz (15 samples/second). That’s more than sufficient for a battery monitor.

Thanks for all your replies guys. Let me clarify a little more what is the end goal for this little project of mine. Basically I am using Minimalist Arduino from http://thetransistor.com/projects/arduino/ and the end goal is to create a sensor board (which will have different sensor, IE: Temp, Humidity, etc…) and transmit the data through xbee. So having said that I just wanted to understand how I could monitor the battery life so that I will know when I need to change the battery before the sensor boad does not transmit data anymore.

The idea is to have the battery last as long as possible (therefore putting the xbee and everything else to sleep betwen readings) and spend as less money on the final prototype.

So far yes, I am using an ATMega328P and for this test I am using Analog Pin 5 to do the reading. Would it b wiser to use Digit Pin for the reading?

I am also in need of a bettery life meter my idea was to use a 10 segment led to see exactly what percentage (0-100%) is left. I just started my post on this in the SparkFun Projects Forum and will be keeping an eye on this thread! Good progress so far keep up the good work and maybe we can figure this out. Good Luck

So I have put 2 10Mohm resistors in series (see attached diagram)

I am using

int analogInput = 1;

float vin = 0.0;

value = analogRead(analogInput);

vin = map(value,0,1023,0,900) / 100.0;

and I get a value of 1023 all the time from the analog pin 1.

The 9v alkaline battery is now discharged to 7.90v.

what am I doing wrong? I shouldn’t be getting a value of 1023 unless the battery is fully charged. Thanks.

Internal and/or external leakage to the Vdd rail.

For a sanity check disconnect the battery from the top 10M resistor and read the ADC. If it still reads 1023 than connect a 1k resistor from the ADC pin to ground. If it still reads 1023 then there is an ADC set-up and read problem in the code.

Here is the output when I don’t connect the battery from the top 10M resistor. (The battery Vin is not connected at all)

value=0

0.00 volt

value=0

0.00 volt

value=0

0.00 volt

value=0

0.00 volt

value=0

0.00 volt

value=0

0.00 volt

When I connect the battery Vin to the top 10M I get the following result:

value=0

0.00 volt

value=0

0.00 volt

value=0

0.00 volt

value=0

0.00 volt

value=0

0.00 volt

I have connected a 1K resistor from the ADC to ground.

Here is the code that I am using:

// variables for input pin and control LED

int analogInput = 1;

int LEDpin = 13;

int prev = LOW;

int refresh = 1000;

float vin = 0.0;

// variable to store the value

int value = 0;

void setup(){

// declaration of pin modes

pinMode(analogInput, INPUT);

pinMode(LEDpin, OUTPUT);

// begin sending over serial port

Serial.begin(9600);

}

void loop(){

// read the value on analog input

value = analogRead(analogInput);

Serial.print(“value=”);

Serial.println(value);

// blink the LED

if (prev == LOW) {

prev = HIGH;

} else {

prev = LOW;

}

digitalWrite(LEDpin, prev);

vin = map(value,0,1023,0,900) / 100.0;

Serial.print(vin);

Serial.println(" volt");

// sleep…

delay(refresh);

}

if I don’t put the 1K resistor from ADC to ground then I get 1023 as a value all the time.

It does sound like leakage.

Re-read the posts by viskr and tecoist. Also try two 10k or 1k resistors to see if you can get a correct battery voltage. If so then it is the ADC’s input impedance and leakage that is killing the use of the 10M resistors and you will need to use a MOSFET switch.

So, have you tried measuring the voltage on the analog-in pin with a voltmeter?

Ohm’s law says that you should certainly see zero on the ADC with a 1k resistor to ground. You have less than a microamp running through the resistor divider, so you will see less than a millivolt across the 1k resistor.

You might set your input pin low: digitalWrite(analogInput, LOW); // be sure the pullup resistor is turned off.

You might just verify that you have AVcc wired to 5V. Do you have AREF wired to 5V as well? And of course, you might verify that the voltage on AVcc really is 5V (and that Vcc is 5V).

You could try fiddling with the resistor-to-ground on the voltage divider to see if you can get something other than full scale (1023) and zero out of the ADC, e.g., try a 1M resistor to ground. If that gives you an ADC reading, you can measure the voltage on the analog input and see how it correlates with your ADC number.

Your value-to-voltage mapping is incorrect, by the way. Full scale on the ADC represents ADC reference voltage, whatever that may be, and not full scale on the battery. So if the ADC reference is 5V, 1023 would represent 5V on the input pin or 10V at the battery, not 9V.

Basically measure the voltage divider, it should be 1/2 the battery voltage. If its not then the AD input is loading down the divider too much and you’ll need to decrease the resistor values.

Is your supply 5V or 3.3? If 3.3, then those analog switches don’t like to be pulled above the supply.

If it is 3.3V, divide by 3, with 20M and 10M.

With resistances that high you’re starting to get into the realm of very high impedance circuits. By the time you get to 100M, your circuit turns from being something useful to being an antenna picking up any stray signals. Also at those levels, just touching the resistors will leave enough perspiration to affect the values.

This is the thread I used to build mine.

http://www.arduino.cc/cgi-bin/yabb2/YaB … 738420/8#8

I am using that code with a simple voltage divider. My readings are little off but work. I think I need to use different resistors since I am using a different voltage power supply.

I got mine to work with 3 resistors of 10 M in series. If you take the attachement I previously posted you just add a new 10 M resistor and that should work. I have also a resistor from the analog pin to gnd

I think if I play with the map function I can get it to what the measurement is suppose to be. Also maybe the resistor that is from the analog to gnd might not be the right value so I can still teak it that way. With the code below I am off but it is very minimal. I will try to post a picture when I am done.

Here is the code I am using

// variables for input pin and control LED

int analogInput = 1;

int LEDpin = 13;

int prev = LOW;

int refresh = 1000;

float vin = 0.0;

// variable to store the value

int value = 0;

void setup(){

// declaration of pin modes

pinMode(analogInput, INPUT);

pinMode(LEDpin, OUTPUT);

// begin sending over serial port

Serial.begin(9600);

}

void loop(){

// read the value on analog input

digitalWrite(analogInput, LOW);

value = analogRead(analogInput);

Serial.print(“value=”);

Serial.println(value);

// blink the LED

if (prev == LOW) {

prev = HIGH;

} else {

prev = LOW;

}

digitalWrite(LEDpin, prev);

vin = map(value,0,1023,0,8690)/100.0;

Serial.print(vin);

Serial.println(" volt");

// sleep…

delay(refresh);

}

Thanks that would be helpful. Even though mine works it seems to not be accurate enough to monitor battery level. I was hoping to shutdown attached systems/sensors based on battery level.