SparkFun Forums 

Where electronics enthusiasts find answers.

For the discussion of Arduino related topics.
By cbabilotte
#113376
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
By waltr
#113380
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.
By tecoist
#113394
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.
By waltr
#113403
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.
User avatar
By viskr
#113412
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.
User avatar
By viskr
#113428
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.
By tecoist
#113433
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.
By cbabilotte
#113434
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?
By DarkStar
#113524
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
By cbabilotte
#113831
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.
You do not have the required permissions to view the files attached to this post.
By waltr
#113842
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.
By cbabilotte
#113852
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.
By waltr
#113857
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.
By tecoist
#113859
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.