Basic battery monitor circuit for Arduino Uno: looking for assistance

After working to find a working design for a voltage divider, I eventually created this code:

/*   Battery Monitor

A working 9v battery monitor that checks the battery your arduino runs on!
Created with the blood and tears of many in the forums, and then converted
to a working program with a serial and physical output. Steps 9 volts to
5 volt, safe for the arduino. Created for Arduino Uno.

100 ohm resistor from ground to A0
120 ohm resistor from Vin to A0
Battery +/- terminals to Vin/GND

NOTE: you can use different resistors, but you need to enter their values below for the maths.

I put a 1000nf capacitor (ceramic 104) in parallel with the 120 ohm to help the arduino calculate.
*/

const int ledPin =  13;

void setup(){
Serial.begin(9600); //serial at 9600 baud
}

void loop(){
  
int kk = analogRead(A0); //analog pin 0 readout
float voltageA0 = (float) kk / 1024.0 * 3.3; //the maths
float batteryVoltage = 1.0 / (3900.0 / (1000.0 + 1200.0)) * voltageA0; //more maths

if( batteryVoltage > 1) //threshold for a good battery
    {
    digitalWrite(ledPin,HIGH);
    Serial.print(" Battery is good");
    Serial.print('\n'); //starts a new line
                                     }
if (batteryVoltage < 1) //threshold for a bad battery
   {
    digitalWrite(ledPin,LOW);
    Serial.print(" Battery is low");
    Serial.print('\n'); //starts a new line
                                     }

delay(100); //sets a delay to avoid seizures when you read the serial monitor
}

I was wondering if there was a better design, since this seems to speed drain the battery and doesn’t show the exact voltage. Trying to display the raw analog input does nothing, only displays “26469” as the input no matter what voltage it gets, even though it can see if the battery is good or not. I hope that someone smarter than me can help fix this!

The voltage divider will draw about 40mA. If that is too much use lager resistors.

Use a multimeter and measure voltage between A0 and GND. Should not be more than 5V.

Add a 'Serial.println(kk);' to check the raw reading of A0. Should not show more than 1023.

int kk = analogRead(A0); //analog pin 0 readout
Serial.println(kk);

You calculate voltageA0 with a reference of 3.3V, shoud be 5V

float voltageA0 = (float) kk  * 5.0 / 1024.0; //the maths

If R1=100 and R2=120 (A0->GND), then batteryVoltage is

float batteryVoltage = voltageA0 * 220.0 / 120.0; //more maths

Then check threshold for good battery

if(batteryVoltage > 7.5)

If only threshold is of interest, I would calculate the expected value of A0, and just use that.

7.5V batteryvoltage, should give about 4.1V at A0.
1024 * 4.1 / 5 is about 837

void loop() {

  int kk = analogRead(A0); //analog pin 0 readout
  if (kk > 837) //threshold for a good battery
  {
    digitalWrite(ledPin, HIGH);
    Serial.println(" Battery is good");
   }
  else //threshold for a bad battery
  {
    digitalWrite(ledPin, LOW);
    Serial.println(" Battery is low");
  }

  delay(100); //sets a delay to avoid seizures when you read the serial monitor
}

leongjerland:
Add a 'Serial.println(kk);' to check the raw reading of A0. Should not show more than 1023.

Cannot be more than 1023

...R

Thank you for the help! I was wondering if there is a formula to calculate the maths for the voltage divider and the inputs for the code; if there is, I want to try to limit the power input to 1 volt. I read that that makes it more efficient and lowers battery drain. I accidentally did this in a test of my original resistors, but the code couldn't tell if the battery was removed or not. I will try with the better code and see if it works. Thanks!

Hi,
Instead of using;
100 ohm resistor from ground to A0
120 ohm resistor from Vin to A0

Which are draining you battery, try changing you resitors by a factor of 100 or 1000.

10,000 ohm resistor from ground to A0
12,000 ohm resistor from Vin to A0

This will drop the sample current, also a 0.1uF from A0 to gnd.

Thanks… Tom… :slight_smile:

But if I change the 100 ohm resistor, the A0 pin acts strange. . . I think it isn't being grounded correctly because the resistence is too high. Is this just my opinion?

KingDubDub:
But if I change the 100 ohm resistor, the A0 pin acts strange. . . I think it isn't being grounded correctly because the resistence is too high. Is this just my opinion?

Are you changing BOTH resistors?
Do you have DMM to measure the voltage at A0?
Can you post a picture of your project please, so we can see your layout?
Thanks.. Tom... :slight_smile:

Here's a picture

My Voltage Divider.png

Image from Reply #7 so we don't have to download it. See this Simple Image Guide

...R

Hi,
Remove the wire that goes to Vin. and increase the values of both resistors to what I have suggested.
My Voltage Dividere.jpg

Tom… :slight_smile:

TomGeorge:
Remove the wire that goes to Vin.

Isn't that what is powering the Arduino?

...R

Robin is right, I want to run the Arduino off the battery while it is running. I read that that also gives out more stable readings when the battery is tested while under a load. I have seen people put their Vin pins into the 5v pin on the arduino. I assume that would definitely be bad for the arduino since the voltage isn't being regulated?

I know the picture is trash, I WILL get Fritzing soon.

I just tried leongjerland's setup and it displayed "27499" as the input voltage every time. His setup did something, but it still doesn't work.

Looking back at the code in your Original Post …

It is a complete waste of time converting the analog reading to volts. What you need to do is work out what analog reading represents the threshold voltage and then do something like this

int thresholdBatteryADCValue = 600; // just for illustration
adcReading = analogRead(batteryVoltsPin);
if (adcReading < thresholdBatteryADCValue) {
  // do stuff
}

And before worrying about anything else create a simple program that calls analogRead() once per second and displays the value on the Serial Monitor. At the same time measure the voltage at the analogPin with your multimeter. You can then check the correlation with your calculator or spreadsheet.

…R

I agree that seeing the voltage in the serial monitor is useless. There is no point unless you just want some fancier code. I only want to see the raw input from the analog pin so I can find (or make) a dead battery that can't power the arduino correctly. I can see its value and adjust the code accordingly. This could also be useful if you change the voltage divider resistors themselves and need to re-calibrate the code. Aside from that, I really don't need it, I just want a working circuit that doesn't kill the battery and still reads it correctly.

Hi,
What voltage do you measure at A0 and at the battery terminal with respect to gnd?

Have you changed your resistors to higher values?

Tom.... :slight_smile:

I have used higher resistors, that's how I discovered the arduino likes a 100 ohm resistor between A0 and ground. Higher resistors mean less of a burn out, so I want to try for 1 volt to the arduino.

At battery terminals: 9.23 volts

At A0: 3.371 volts

At the leads of the resistors (before entering circuit): 8.3 volts

Not sure why the last one is different from 9.23 volts.

Hi,
Can you post a picture of your project so we can see your component layout?

What do you mean by;

I have used higher resistors, that's how I discovered the arduino likes a 100 ohm resistor between A0 and ground. Higher resistors mean less of a burn out,

  • Are you using Ohms Law , and potential divider equations to calculate your resistor values, or just trial and error?
  • Do you know how much current is flowing through your potential divider?

Thanks.. Tom... :slight_smile:

KingDubDub:
the arduino likes a 100 ohm resistor between A0 and ground.

That sounds like nonsense.

...R

If internal pull-up resistor (20K+) is enabled, that will affect the voltage divider, but only with a small amount with a 100 ohm resistor between A0 and GND.

Try this:

void setup() {
  pinMode(A0, INPUT);
  Serial.begin(9600); 
}

void loop() {
  int kk = analogRead(A0);
  Serial.println(kk);
  delay(1000);
}

Do you still get values above 1023?
If so, there must be something wrong with your Arduino.....

Try using another analog pin.