Measure 12V input voltage to Arduino Uno

Hi all,

I know this is a common question but I cannot find the answer I’m looking for.

I’m powering the Uno with a 12V battery through the external power connector and I’m trying to measure the battery voltage. There are many explanations about how to scale down and measure voltages. I am wondering what are the pitfalls when measuring the same voltage that is powering the board.

It seems that there are two general approaches:

1- Make a voltage divider with two resistors to scale down the voltage and measure it with an analog input pin.
This approach is used here http://www.instructables.com/id/Arduino-Battery-Voltage-Indicator/
but it lacks details on how to chose the right resistors.

and here Measuring Voltage with Arduino, although this one measures an external battery, not the one powering the arduino.

2- the second approach uses some internal voltage coming from the board chip, against which the voltage of interest is measured.

but the code given here doesn’t appear to be for the Uno (maybe Mega?).

Thanks for all your help

(deleted)

Hi Spycatcher,

thanks for your reply.

Do you get the voltage of the board from the Vin pin, connect it to the divider and read the voltage from an analog sensor?

Thanks!

Either is fine - if the uC is getting 5V from the regulator, than the 12V divided to under 5V for measurement works using EXTERNAL for ARef so 5V is full scale, or to under 1.1V if INTERNAL is used so 1.1 to 1.2V is full scale.

Get the voltage from wherever is convenient, as long as it gets divided down before going into an analog pin.

EXTERNAL ? It's not DEFAULT for 5V full scale?

Ciao, Ale.

Default Aref is the 5volt supply.
That can vary a bit on external supply, USB supply or load changes (flashing LEDs, etc.).
Better to use the internal ~1.1volt Aref for voltage measurements.
Here is some code to try.
Leo…

/*
  0 - ~16volt voltmeter for 3.3volt and 5volt Arduinos
  uses the stable internal 1.1volt reference
  6k8 resistor from A0 to ground, and 100k resistor from A0 to +batt
  100n capacitor from A0 to ground for stable readings
  (100k + 6k8) / 6k8 = 15.70588 | used in formula
*/
float Aref = 1.075; // ***calibrate here*** | change this to the actual Aref voltage of ---YOUR--- Arduino
unsigned int total; // can hold max 64 readings
float voltage; // converted to volt

void setup() {
  analogReference(INTERNAL); // use the internal ~1.1volt reference  | change (INTERNAL) to (INTERNAL1V1) for a Mega
  Serial.begin(9600); // set serial monitor to this value
}

void loop() {
  for (int x = 0; x < 64; x++) { // multiple analogue readings for averaging
    total = total + analogRead(A0); // add each value to a total
  }
  voltage = (total / 64) * 15.70588 * Aref / 1024 ; // convert readings to volt
  // print to serial monitor
  if (total == (1023 * 64)) { // if overflow
    Serial.print("voltage too high");
  }
  else {
    Serial.print("The battery is ");
    Serial.print(voltage);
    Serial.println(" volt");
  }
  total = 0; // reset value
  delay(1000); // one second between measurements
}

hi Wawa,

thanks for your reply and helpful code.

Can I use different resistors than the one you used?

of course I will have to calculate the total resistance this way: (100k + 6k8) / 6k8 = 15.70588 | used in formula

and then put the number in this formula:

voltage = (total / 64) * 15.70588 * Aref / 1024 ; // convert readings to volt

This last formula is still somewhat mysterious to me (why 1024?), but I'll use it nevertheless.

Last question: where do I find the "actual Aref voltage of ---MY--- Arduino"?

Thanks!

Gerry

gerardospinelli:
Can I use different resistors than the one you used?

voltage = (total / 64) * 15.70588 * Aref / 1024 ; // convert readings to volt
This last formula is still somewhat mysterious to me (why 1024?), but I’ll use it nevertheless.

Last question: where do I find the “actual Aref voltage of —MY— Arduino”?

  1. Yes, but these values are calculated/optimised for the voltage range of a 12volt car battery.

When using 1.1volt Aref, the voltage divider has to bring down the “voltage to measure” to <= 1.1volt.
If you e.g. would use 1k and 100k, you could measure to ~100volt.
That will bring down resolution though. Now the 1024 steps of the A/D are spread out over 100volt.

  1. Arduino has a 10-bit A/D.
    10^2 = 1024.

  2. 1.1volt Aref is stable, but not factory calibrated. So it’s different for every Arduino board.
    It could be 1volt to 1.2volt. The boards I have used hover around the value I have used in the sketch.
    Just change the value slightly untill you have the correct voltage readout.
    Leo…

Hi Leo,

thanks.

I would like to have some protection, meaning that even if the battery goes up to 15V (or 30V), the analog pin still doesnt get more than 5V and I dont burn it. I'm currently using 1Mohm and 100Kohm for resistors that give me a factor of 1100k/100k=11.

I took this values from some post online so I'm not sure they will give good accuracy, but so far I'm reading reasonable voltage values. Do you suggest I switch to your resistors? Would they provide the protection I'm looking for?

I'm not looking for perfect accuracy. I just need to know if a battery is healthy (about 12V) or it's about to die (below 11.5V).

When you say "Just change the value slightly untill you have the correct temp readout.", do you mean the correct voltage readout?

and what is the "correct" voltage readout? I suppose I could use my multimeter as a calibration tool... I guess my question was: is there a way to output the 1.1Aref voltage from the Arduino?

Thanks again and have a wonderful weekend!

Gerry

gerardospinelli:
I would like to have some protection, meaning that even if the battery goes up to 15V (or 30V), the analog pin still doesnt get more than 5V and I dont burn it.

I’m currently using 1Mohm and 100Kohm for resistors that give me a factor of 1100k/100k=11.
I took this values from some post online so I’m not sure they will give good accuracy, but so far I’m reading reasonable voltage values.

Do you suggest I switch to your resistors? Would they provide the protection I’m looking for?

I’m not looking for perfect accuracy. I just need to know if a battery is healthy (about 12V) or it’s about to die (below 11.5V).

When you say “Just change the value slightly untill you have the correct temp readout.”, do you mean the correct voltage readout?

and what is the “correct” voltage readout? I suppose I could use my multimeter as a calibration tool…
I guess my question was: is there a way to output the 1.1Aref voltage from the Arduino?

  1. 100k/6k8 will keep the analogue pin under 5volt up to 78.5volt input.

  2. That ratio might have been for default 5volt Aref, or to measure a 9volt battery.

  3. Yes, yes.

  4. My values and code give about the highest accuracy you can get from Arduino’s 10-bit A/D.
    100k:8k2 gives a fraction higher resolution at the cost of a lower ceiling of ~14volt.

  5. Yes. Corrected. I just posted a temp sketch in another part of the forum. Duhhh.

  6. Best to calibrate the final output with a DMM.
    You could measure 1.1volt Aref on the Aref pin (with internal Aref enabled).
    But calibrating the final result also eleminates the inaccuracy of the voltage divider resistors.
    Leo…

Wow this is great, thanks!

My very last question is:

Is it fine to connect the Arduino Uno to the battery with the 2.1mm barrel jack and then use the battery voltage from the Vin pin though the 100k resistor to A0 to measure battery voltage? This would save me a cable going to the battery.

Thanks, and have a fabulous weekend!

Gerry

The Vin voltage passes through a seriese diode first so it will not be the same as the power jack.

Correct. Not wise to do, because Vf of that reverse protection diode depends on current draw and temp. Leo..

I see. So the best thing to do is to send another positive 12V from the battery into the 100k resistor of the voltage divider. Is it safe to take the GND from the Uno for the 6.8K resistor?

Thanks!

gerardospinelli: Is it safe to take the GND from the Uno for the 6.8K resistor?

Yes.