How to test battery level with Arduino?

Hello everybody! I have a little problem, how can I measure battery level with arduino? I want to measure the same battery from which Aurduino works. You can see it on the picture. If I connect this way(see on the picture) arduino do not shows me the voltage, because it use the same battery. Thank you!

You've connected GND and '+5V' to the same breadboard rail...

Also you can't measure the battery voltage this way if its also the supply, since the ADC outputs the ratio between the ADC input and the ADC reference (which defaults to the supply voltage). So you'll just measure a ratio of resistors this way.

However it is possible to set the AREF pin to an internal 1.1V reference source, analogReference(INTERNAL).

But then you'll have to make sure the resistor divider takes the battery voltage below 1.1V.

Alas the 1.1V on chip reference is not very accurate between different chips, the datasheet says its between 1.0 and 1.2V, which is +/-10%...

So what should I do? How should I connect? Which components I need? Thank you very much!

Mastino: So what should I do? How should I connect? Which components I need? Thank you very much!

look at the two blue lines/wires coming form your Arduino from the GND & v5+ pins..

you have them BOTH going to the same rail/place.. (the V++ of the battery pack)..

the GND line from Arduino needs to be moved to the GND rail/GND output of the battery pack.

First your drawing is flawed in that you show a 9vdc voltage source powering the +5vdc pin which of course would damage the board.

Now assuming you are powering an arduino board directly with batteries (which must be limited to +5.5vdc max or damage to the board is possible), is there a way to measure the battery voltage? Note that this does not apply if you are powering your board via the external power connector or the Vin pin using a battery voltage between 6-12vdc. In that case you only need to use a simple two resistor voltage divider to scale down the battery voltage to a value that stays within the normal 0-5vdc measurement range for a analog input pin.

But again if you are powering the board directly with batteries via the +5vdc pin, yes there is a way to measure the actual battery voltage on the run. It’s not simple and utilizes some tricky coding but it can be done. Here is a sketch that will perform that task and also allows any analog readings to be ‘corrected’ on the run as the battery voltage lowers while being discharged. The comments should explain how the method works.

Note: not tested under new Arduino IDE 1.0, but does run under V22.

// Function created to obtain chip's actual Vcc voltage value, using internal bandgap reference
// This demonstrates ability to read processors Vcc voltage and the ability to maintain A/D calibration with changing Vcc
// Now works for 168/328 and mega boards.
// Thanks to "Coding Badly" for direct register control for A/D mux
// 1/9/10 "retrolefty"

int battVolts;   // made global for wider avaliblity throughout a sketch if needed, example a low voltage alarm, etc

void setup(void)
    {
     Serial.begin(38400);
     Serial.print("volts X 100");
     Serial.println( "\r\n\r\n" );
     delay(100);
    }
    
void loop(void)
    {
     battVolts=getBandgap();  //Determins what actual Vcc is, (X 100), based on known bandgap voltage
     Serial.print("Battery Vcc volts =  ");
     Serial.println(battVolts);
     Serial.print("Analog pin 0 voltage = ");
     Serial.println(map(analogRead(0), 0, 1023, 0, battVolts));
     Serial.println();    
     delay(1000);
    }

int getBandgap(void) // Returns actual value of Vcc (x 100)
    {
        
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
     // For mega boards
     const long InternalReferenceVoltage = 1115L;  // Adjust this value to your boards specific internal BG voltage x1000
        // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc reference
        // MUX4 MUX3 MUX2 MUX1 MUX0  --> 11110 1.1V (VBG)         -Selects channel 30, bandgap voltage, to measure
     ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
  
#else
     // For 168/328 boards
     const long InternalReferenceVoltage = 1056L;  // Adjust this value to your boards specific internal BG voltage x1000
        // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc external reference
        // MUX3 MUX2 MUX1 MUX0  --> 1110 1.1V (VBG)         -Selects channel 14, bandgap voltage, to measure
     ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
       
#endif
     delay(50);  // Let mux settle a little to get a more stable A/D conversion
        // Start a conversion  
     ADCSRA |= _BV( ADSC );
        // Wait for it to complete
     while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
        // Scale the value
     int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L) / 10L; // calculates for straight line value 
     return results;
 
    }
1 Like

retrolefty - this is exactly what I need! Can you describe me in few words how I should connect (to which pins) arduino and battery? The code seems very difficult to me…:slight_smile: How should I configure this code to adapt it to my board(Arduino Mega 2560)?
Thank you very much!

Mastino: retrolefty - this is exactly what I need! Can you describe me in few words how I should connect (to which pins) arduino and battery?

That depends of the battery voltage you are using, type as well as voltage. The program just measures what voltage is present on the chips Vcc pin. Again, I would need to know what battery voltage you are using to tell you more.

The code seems very difficult to me..:) How should I configure this code to adapt it to my board(Arduino Mega 2560)?

The sketch is already set up to handle either 328p or mega1280 or mega2560 chips automatically. How to adapt the sketch to your on application sketch is not a simple task and I don't really know how to guide with that. What is your sketch overall objectives?

Thank you very much!

Your welcome.

Lefty

1 Like

I have 9 AA 1.2v batteries. So 10.8V from all 9 batteries. For what I need that? 1. I want send the data to my processing program. So I will see how much % of battery is available(100-90% full, 40-50% middle and 20-30%low), you know like on the mobile phone. Also I want to use the data in the code, for example if there are about 20-30%, the robot goes to docking for charge. Thank you for your attention and help!

Mastino:
I have 9 AA 1.2v batteries. So 10.8V from all 9 batteries.
For what I need that?

  1. I want send the data to my processing program. So I will see how much % of battery is available(100-90% full, 40-50% middle and 20-30%low), you know like on the mobile phone.
    Also I want to use the data in the code, for example if there are about 20-30%, the robot goes to docking for charge.
    Thank you for your attention and help!

For that you don’t need my program at all. Just wire the 10.8vdc battery voltage to either the arduino external power connector or the shield Vin pin.

Then use a two resistor voltage divider of the proper values connected to the 10.8v and wire the junctions of the resistors to a analog input pin.

Lefty

The problem is that my arduino works from the same 10.8V battery.

The problem is that my arduino works from the same 10.8V battery.

Why is that a problem? The arduino has a 5V regulator giving you a 5V voltage reference against which you can measure your varying voltage from the battery.

Mastino: The problem is that my arduino works from the same 10.8V battery.

Again that is not a problem. The +10.4 volt battery terminal would just wire to two places, 1. to the arduino Vin pin and 2. to the top of a two resistor voltage divider.

Lefty

You mean like this?:

If yes, it doesn't work. It is the same if you take a multimeter and you will try to measure the battery inside it. It don`t shows you the voltage, because the multimeter takes the power from this battery for it self. But if you will measure another battery, it will show you the voltage. I think the same is with arduino.

You are wrong it does work because the 5V reference is regulated and the battery voltage you are measuring is not.

Mastino: You mean like this?:

If yes, it doesn't work. It is the same if you take a multimeter and you will try to measure the battery inside it. It don`t shows you the voltage, because the multimeter takes the power from this battery for it self. But if you will measure another battery, it will show you the voltage. I think the same is with arduino.

I'm sorry, not a single thing you said is that statement makes any sense to me or is just not correct. Of course you can measure a battery's voltage even if it's powering another load, in fact that is preferred way. as voltage under a normal load is a more accurate representation of a battery's actual terminal voltage.

Lefty

Sorry Sorry! I am so fool.. Yes you are right! It is working well! Only one more question: Will it fast discharge the battery? I mean this divider. Many thanks for your answers!

Mastino: Sorry Sorry! I am so fool.. Yes you are right! It is working well! Only one more question: Will it fast discharge the battery? I mean this divider. Many thanks for your answers!

That depends on the resistance values you selected for the voltage divider. Just add the value of both resistors together then the formula is I (current) = voltage / resistance. That is the steady state current draw plus whatever the arduino board is drawing. The MAH rating of the battery should give you the overall current capacity over time that the battery charge has.

Lefty

Wow! Thanks Etrolefty, Master coder!

Hey there,

I have done this to do a health check on a car battery. But I am facing a problem. My circuit works perfectly, I get the same reading on my arduino as with the multimeter. But I get like 14.15 volts on a car battery that has some proper load on it (camp fridge). I was expecting the load to drop the volts down to 12.5 or something more accurate. I store bought battery monitor shows 12.2volts. Lefty mentioned earlier that load should give more accurate readings. Am I missing something?

Maybe we are missing someting. Your code and voltage divider values.

If you're using internal Aref, then the maths in your code needs adjusting, depending on the actual voltage of Aref. Every board is slightly different. You could measure it with a DMM set to 2volt, and edit the code. Leo..