Arduino Battery Voltage Indicator

169,726

423

126

About: Just an ordinary person who loves #thinking and #tinkering

When we are using a battery powered Arduino such as RC robots or Temperature Controller, we might want to check the battery voltage if it needs to be charged or replaced. It happens to me with my RC Panzer. Sometimes when my kids are about to run it, it moves very slow, low battery. Then they are disappointed and need to wait for charging time. I would rather had noticed this battery condition on the last run but I am too lazy to check it with multimeter.

Arduino Uno needs 5 volts power to run, then we need at least 7.4 volts to 9 volts battery. Since Arduino pins support only 5 volts maximum, then we need a Voltage Divider. It is simply made up of two resistors in series. To divide the voltage to half, we need two resistor with the same value. 1K to 20K resistors can be used, but the larger the resistance the lower the power consumed by the Voltage Divider. I am not that good in calculating such thing but that is what I summarize from sources I read. You can correct me if I am wrong and any better explanation to this is most welcome on the comment section.

Step 1: Bill of Materials

  • Arduino Uno or compatible.
  • Male pins (we need four pins only).
  • Two same value resistors (here I use 12K).
  • Two pin female connector. Photo shows three pin because that is what I have. Here I use power switch connector to motherboard instead :)
  • A battery (I use 7.4V lipo battery).
  • 16x2 LCD with I2C adapter. Later on you can switch this to a red LED to indicate low battery at your desired voltage level.
  • A mini breadboard is optional for testing phase.

Step 2: Arduino Sketch

Well, I would like to upload this sketch to Arduino first before connecting it to a battery for testing. Uploading this will show you nothing before you connect all the parts needed for this project, but sooner or later you will still need to upload this sketch. I am not sure what will happen if you have power from usb and also from Vin at the same time. I guess it will be okay, Arduino designers must have think of this possibility and prevent this power conflict. But I will never try it on purpose and risking my Arduino to get burnt :P

In this instructable, I am not explaining about "how to get your LCD display works", but I will leave some links here (which I use) to get your LCD works through I2C connection:

// Print battery voltage
// to 16x2 LCD via I2C
// with Voltage Divider (2x 10K resistor)
/*
  Resistors are aligned in series.
  One end goes to Battery - and also to Arduino GND
  The other goes to Battery + and also to Arduino Vin
  The middle (connection between two resistors) goes to Arduino A0
*/

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

#define I2C_ADDR    0x27 //Add your address here.  Find it from I2C Scanner
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7
#define led_pin 13
LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

void setup()
{
  lcd.begin (16,2); //My LCD was 16x2
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home (); // go home
  
  pinMode(led_pin, OUTPUT);
  digitalWrite(led_pin, LOW);
}

void loop()
{
  printVolts();
}
 
 void printVolts()
{
  int sensorValue = analogRead(A0); //read the A0 pin value
  float voltage = sensorValue * (5.00 / 1023.00) * 2; //convert the value to a true voltage.
  lcd.setCursor(0,0);
  lcd.print("voltage = ");
  lcd.print(voltage); //print the voltage to LCD
  lcd.print(" V");
  if (voltage < 6.50) //set the voltage considered low battery here
  {
    digitalWrite(led_pin, HIGH);
  }
}

Step 3: Circuit

The wire connections are simple as you can see on the images above.

Using 16x2 LCD and its I2C adapter:

  • Adapter GND to Arduino GND.
  • Adapter VCC to Arduino 5V.
  • Adapter SDA to Arduino A4 (or the pin next to AREF on Digital Pins side).
  • Adapter SCL to Arduino A5 (or the pin next to SDA, two pins from AREF on Digital Pins side).
  • Align two 10K resistors in series on breadboard.
  • Connect the middle of the resistors-in-series to Arduino A0.
  • Connect one end to Arduino GND and also to Battery - (negative).
  • Connect the other end to Arduino Vin and also to Battery + (positive). I think you should connect this one after you load the Arduino Sketch as I tell you my reason before.

Using a LED instead of LCD:

  • Connect LED anode (small piece inside) to Arduino D13.
  • Connect LED cathode (large piece inside) to GND (next to D13).
  • Align two 10K resistors in series on breadboard.
  • Connect the middle of the resistors-in-series to Arduino A0.
  • Connect one end to Arduino GND and also to Battery - (negative).
  • Connect the other end to Arduino Vin and also to Battery + (positive).

When you plug the battery to Arduino Vin, it should work right away showing the voltage of your battery on your 16x2 LCD because Arduino is powered by that battery. If it is not working, please re-check your connection or the battery you use might be lower than 5 volts needed by Arduino to power up. Please try another battery or check it with your voltmeter.

On my test with multimeter, the voltage shown on the LCD is slightly lower then the multimeter display. We are loosing around 0.05V to 0.15V on breadboard and Arduino circuits. But that is not a big problem for me (I don't know what about you), as long as I know whether my battery has enough power to run my robot. That's all.

Step 4: From Mini to Micro

Well, I don't want that "mini" breadboard goes along on my Panzer, then I make it "micro".

  • The first resistor : One end soldered to pin 1 from the left. The other end to pin 4 from the left.
  • The second resistor : One end soldered to pin 2 from the left. The other end to pin 4 from the left.
  • Soldered the connector inner pins to pin 1 and pin 2 from the left.
  • Put the black connector jacket on.
  • Pull out pin 3 from the left.

Well, now we have add-on to Arduino pin : GND, Vin, A0.

Step 5: Re-Connect and Run

Now re-connect the LCD and Battery, we have simpler connection without breadboard.

  • Adapter GND to Arduino GND.
  • Adapter VCC to Arduino 5V.
  • Adapter SDA to Arduino A4 (or the pin next to AREF on Digital Pins side).
  • Adapter SCL to Arduino A5 (or the pin next to SDA, two pins from AREF on Digital Pins side).
  • Battery - (negative) to Arduino GND (on our add-on pins).
  • Battery + (positive) to Arduino Vin (on our add-on pins).

On my test I lost 0.1V and pretty stable. Actually we lost only 0.05V on Arduino circuit. 7.79V is shown on my multimeter. Voltage Divider reduced it to half, that is 3.89V entering the A0 pin. The Arduino reads 3.84V. Then we double it to show the exact voltage back, that is 7.68V.

We can fix this in the sketch, but we need more data population to see the stable voltage lost. One more question is : "Is it my multimeter that is not accurate? Because I bought a cheap one."

Again, I don't mind that little difference as long as I know my battery is fit enough to run my RC toys :)

3 People Made This Project!

Recommendations

  • 1 Hour Challenge

    1 Hour Challenge
  • Classroom Science Contest

    Classroom Science Contest
  • Pets Challenge

    Pets Challenge

126 Discussions

0
None
DarylL22

6 weeks ago

Hi. if i am using a 3.7V LiPo battery , i will not need a voltage divider right? then may i know where should i connect the A0 pin?

2 replies
0
None
chienlineDarylL22

Reply 6 weeks ago

Your Battery positive lead (the one you are having the voltage measured) goes to A0 pin :)

0
None
DarylL22chienline

Reply 6 weeks ago

Hi, thanks for your prompt reply.So basically, i am using A5 instead of A0 and when i connect the battery positive lead directly to A5 and negative lead of battery to GND of Arduino UNO the LED on the arduino UNO board is not lighting up, i suspecting that the power supply is not huge enough or am i wrong ? please correct if i mentioned anything wrongly. P.S. I have attached a image of my coding for reading the battery voltage, please help me check thanks :)

battery voltage coding.JPG
0
None
poli.karlo

Question 7 weeks ago

I was wondering if this is possible with a 24v batterys. I have a electric scooter so i want to see the charge % ??

1 answer
0
None
chienlinepoli.karlo

Answer 6 weeks ago

Yes, why not?
24V battery can be fully charged up to 28V or more. Fully charged your battery and measure the voltage with a multimeter. If it is below 30V then you can use 6 resistors with same value for the voltage divider. If it is over 30V then pick 7.
Just a little change in the code (sketch), find the line :

float voltage = sensorValue * (5.00 / 1023.00) * 2;

and change it to :
float voltage = sensorValue * (5.00 / 1023.00) * 6;

Change the multiplication to * 6 or * 7 according to the number of resistors you use on your voltage divider. We divide the voltage with resistors, then we multiply it back on the sketch, simply like that ^_^

0
None
BriceA4

Question 3 months ago on Step 2

Hi! I'd like to know how you came up with that relation : (5.00/10.23)*2 when you calculate the battery level/voltage ?

1 answer
0
None
chienlineBriceA4

Answer 3 months ago

The maximum voltage on Arduino analog pin is 5V. That pin has 10-bit reading = 2^10 = 1024. It means that the analog pin reads value between 0 - 1023.
Let's say our battery has 8.2 volts left in it. 8.2V is beyond maximum of Arduino pin voltage which is 5V and it will fry that pin if plugged directly. So we need a pair of resistors as voltage divider which divides the battery voltage to 8.2 / 2 = 4.1V.
That 4.1V is read by Arduino pin as : 4.1 / 5 * 1023 = 839 (rounded).

Now we try to calculate back that sensor reading value to voltage :
839 * (5.00/1023)* 2 = 8.20136852394 (according to my 12 digits calculator)
The number 5.00 (five point zero zero) will round the value to two decimal digits.

If we have 10V battery, the pin reads 5V (after voltage divider), the digital number read by Arduino pin is 1023 (max). If we stick to the 10-bit (1024) in the formula, we will get :
1023 * (5.00/1024)*2 = 9.99V, and we will never get the 10V. That is why it is 1023 in the formula ^_^

0
None
chienlineSreeA7

Answer 4 months ago

Yes it is. There was about 0.1 volt difference compared to (my) multimeter but it had stable result on several tests. Then I could simply reduce 0.1V in the code, but I left it as is. If you want higher accuracy, collect test data to count average voltage lost in the measurement and adjust the calculation in the code (like simply reduce the result with 0.1V) to get the same result with your multimeter.

0
None
Pedro 1

Question 5 months ago

Very interesting project, bonus for a nice and clean circuit! I was wandering, is it possible to make it so i can record the voltage as the time passes? Making it so i can get data for the voltage decai over time for specific uses.

*Sorry for the bad english :P

1 answer
0
None
chienlinePedro 1

Answer 5 months ago

Thank you.
Recording the time and voltage can be done in the sketch, but you need to add SD card module (check it here). The internal rom has limited space and also limited write cycles. You can learn about that in Arduino official web.

1
None
Jacques-Olivier

7 months ago

Thanks for the idea, not what I was looking for, but should be very usefull anyway.

Just an idea to fix the precision problem : you should use your multimeter to test both resistances values. No matter if the meter is precise or cheap model, while it gives you the same values when you test twice the same thing.

But resistances have a tolerance as well, and your idea of dividing by 2 only works if they have the exact same value... If you test the real resistances values, you could find the division factor is not 2 but somewhere between 1.98 and 2.02, and then update your sketch. Or if you have many resistances just choose two with values that are very close, no matter the value itself...

Thanks again for sharing your idea !

1 reply
0
None
chienlineJacques-Olivier

Reply 7 months ago

Ah.. you are right about the resistors. Those were 2% tolerance resistors anyway.
Thanks for pointing this out.

0
None
beic

Question 11 months ago

Hi, I really love your tutorial, but have a question.

I have a 100k and 10k voltage divider and I wish to monitor vehicle batteries like 12v and 24v, so my question is: how can I measure that in % as you proposed in one comment bellow:

Let us say my RC needs at least 6V to run its Arduino and motors and every modules in it. I am using a 7.4V battery that is fully charged to 8.4V. Do some math here :
8.4 - 6 = 2.4 (this is 100%)
2.4 / 100 = 0.024 (this is 1%)
then we can set in the code :
BatteryLife = 100 - ((8.4 - voltage ) / 2.4 * 100)
Now you got your BatteryLife in percentage before your device stop working.


Thank you for your answer! ;)

6 answers
1
None
chienlinebeic

Answer 11 months ago

So you are going to measure your car's battery voltage. I won't say this device doesn't work but I will explain further regarding car's battery. Let's pick a normal family car or SUV which is rated 12V. It is fully charged at around 12.7V. When the engine is running you will get 13.7V - 14.7V, that is the output of the car's alternator.

When your battery dies? When it reaches 11.9V, but this is not telling you about time to replace your battery. You may still charge it with external charger to working voltages, or you may not, there are a lot of possibilities regarding to car's battery such as abnormal discharging.

The range of working voltage of a car battery is 11.9V to 12.7V, so you can calculate it like this :

100% = 12.7 - 11.9 = 0.8V
1% = 0.8 / 100 = 0.008V
Battery percentage = (ReadVoltage - 11.9) / 0.008

Assuming ReadVoltage = 12.4V

Battery percentage = (12.4 - 11.9) / 0.008 = 62.5%

Again, this is not telling you whether you can start your engine or not. Starting up a car needs a lot of amp, not voltage. Checking on the voltage regularly can give you a rough condition of your car's battery and help you in diagnosing a battery problem like if something in the car is discharging your battery when the engine is off.

In certain case you can jump start your car and let it run for 20 mins to charge the battery and if the battery is still good (it can store charges) then no replacement is needed. Someone may have leave the key in ACC and every electronic in the car is discharging the battery. That happens to old car. New family car will warn you with "beeps" when your your key is plugged, the engine is off and the driver's door is open (meaning the driver is leaving the car without the key).

0
None
beicchienline

Reply 11 months ago

Thank you for the great explanation! ;)

The batteries are not connected to the charger nor will be on vehicle's alternator, it will remain as stand alone power source. Do you know how can I implement periodic check in millis() (read every 10s) to get a rough estimate left over time in minutes until the battery dies?

Kind regards

1
None
chienlinebeic

Reply 11 months ago

If it is a standalone power source, then you should measure the voltage when it is fully charged and also when it dies (your project stop working/not working properly). The formula remain the same :

OnePercent = (FullyCharged - BatteryDies) / 100;
BatteryPercentage = (ReadVoltage - BatteryDies) / OnePercent;

The sketch above reads the battery voltage continuously. If you want to read every 10 seconds, the simplest way is adding delay(10000); in loop section rather than complicated but more accurate timer implementation.

You know about millis() then I assume you know how to write simple Arduino sketch just like me ^_^ then I can simply explain the algorithm I guess, because it needs testing phase to write working sketch and I think I don't have that time by now :D

For rough estimate remaining time you can add another parameter storing how long it spends 1 percent of the battery.

int TimeForOnePercent = 0;
float PrevPercentage = 0;

Put this variable out of any procedure or function. Make it global. Then add this to printVolts() function after float voltage = ... :

if (PrevPercentage == 0){ // first time reading.
PrevPercentage = Battery Percentage;
}
else if (PrevPercentage == BatteryPercentage){
// battery has not dropped, add another 10 seconds to record.
TimeForOnePercent += 10;
}
else if (PrevPercentage - BatteryPercentage == 1.00){
// battery drops 1%, time to count the estimate remaining time.
TimeForOnePercent += 10; // 10 secs has passed, we still need to add this.

// EstimateRemainingTime is in second, you can convert it to hour and minute
EstimateRemainingTime = Percentage * TimeForOnePercent;

// Reset the PrevPercentage
PrevPercentage = Battery Percentage;
}

Again you should recalibrate your BatteryDies time. Currently we are talking about car's battery that condidered dies at 11.9V but for other project it may die at any level depends on your project.

0
None
beicchienline

Reply 11 months ago

It's really a good one, but what about EstimateRemainingTime? Not defined? Need to put also as Global? Is it Int, Long or Double?

0
None
chienlinebeic

Reply 11 months ago

You can define it as long because we don't care about millisecond (decimal). You can define it in printVolt() or make it global if you want to use it outside printVolt()

^_^

0
None
beicchienline

Reply 11 months ago

Thank you Chien! ;)