Voltage Reading

For our project, we need to read voltages from our battery. We have set up a simple voltage divider so that a 12 volt battery will read .86 volts into the analog input pin on the arduino mega 2560. The main issue is that we are not sure how to properly convert the analog input value into the actual voltage. We believe the analog pin reads values from 0 to 1024 using the function analog read. We had first set the equation and circuitry up to read a 5v and 3.3v input directly from the arduino without a voltage divider, and it worked well. However when trying to read from a 12volt source through a voltage divider, the output readings are very incorrect.

voltage divider circuit R1 = 110k ohms R2 = 8.2k ohms Vout = (r2 / (r1+r2))*Vin so in other words Vout = .69374 * Vin Our output voltage equation is Vin = Vout / .069374

Any help would be greatly appreciated! Thanks!

Looks like you're doing it right (except you had a typo: you wrote Vout = .69374 * Vin when you meant 0.069374, but your Vin = Vout / 0.069374 equation is correct).

Let's stop using Vin and Vout because they're confusing. Let's use Vbat and Vadc for the battery voltage and the voltage read at the A/D converter. Then:

Vadc = Vbat * 0.069374.

Your number from 0 to 1023 will be:

Number = (Vadc/5V) * 1023 = (Vbat * 0.069374 / 5) * 1023 = Vbat * 14.1939

Turning it around:

Vbat = Number / 14.1939

and that's approximately:

Vbat = Number * 9 / 128

which is efficiently implemented as:

Vbat = (Number * 9) >> 7;

-- The Gadget Shield: accelerometer, RGB LED, IR transmit/receive, speaker, microphone, light sensor, potentiometer, pushbuttons

segs: ... voltage divider circuit R1 = 110k ohms R2 = 8.2k ohms Vout = (r2 / (r1+r2))*Vin so in other words Vout = .69374 * Vin ...

Huh? By my reckoning Vout / Vin = 8.2/(110 + 8.2) = 0.06937... which is exactly what you observe.

First of all, with Vref = 5.0 Volts why the heck do you want to divide the input down to 0.89 Volts. Why not make it something closer to 5.0 Volts so that you can attain better precision with your readings?

Volts per bit = Full Scale Voltage divided by 1024.

For example why not give your meter something like 15 Volts full scale. That is, for 15 Volt input, it applies 5 Volts to the Arduino. This gives you a little headroom over 12 Volts. (12 Volt batteries may have somewhat more than 12 Volt outputs when fresh and/or fully charged, and you don't want to lose accuracy by "pegging the meter" with the maximum actual value of voltage.)

So, for 15 Volts in and 5 Volts out, you want Vout / Vin = 1.0/3.0. That's easy.

Off of the top of my head:

R2 = 11K, R1 = 22k gives Vout / Vin = 11/(11+22) = 1/3. Didn't even need a cocktail napkin (let alone an abacus) to do the math, right?

This puts something less than 400 microamps through the divider, which may be acceptable (or not). Any resistors having the same ratio will give the same voltage output results, assuming the current into the analog input pin is much less than the current through R2. This places an upper limit on the practical values of R1 and R2. I wouldn't use 100 Megohms for R2 and 200 Megohms for R1, for example.

Anyhow, for given values of analog Vref and resistors R1 and R2, the voltage calculation from the 10-bit ADC reading goes something like this:

    const float R1 = 22000.0; // Put exact value here
    const float R2 = 11000.0; // Put exact value here
    const float Vref = 5.0;   // Put exact value here
    int adcReading = analogRead(0); // Or whatever analog input channel you use

    // Define the formula in terms of variables so that the program
    // will easily accommodate it if you change (or measure) the
    // actual values.
    float v = (R1+R2)/R1 * adcReading * Vref / 1024.0;

Note that, if the Arduino 5 Volts is off by, say 2%, then the readings will be off by 2% (assuming you know exact values for R1 and R2). If can accurately measure the value of Vref, substitute that value in place of "5.0" Similarly, if you can accurately measure values of R1 and R2, use the actual values.



You could also switch from using the default internal 5 volt reference to the 1.1 internal reference (INTERNAL1V1). You would be able to keep your current divider configuration and even if the battery voltage jumps to 15v it should keep you just below the reference limit. You'll also get better stability and precision with your readings.

wayneft: ...1.1 internal reference (INTERNAL1V1). You would be able to keep your current divider configuration...

A really good point, and I overlooked the reasoning behind the selection of that particular scale factor.

Anyhow, just plug the values into the formula that I gave to convert ADC reading to voltage.

A final note: The internal 1.1 Volt reference is specified plus or minus 0.1 Volts, so the readings could be off by something like nine or ten percent unless the system is calibrated to take the actual reference voltage into account. There have been a couple of threads on this forum that showed ways to approach this if the application requires better accuracy.

The really good news about the internal reference is that is not very sensitive to changes in the ATmega Vcc (5 Volts applied to the processor chip).



The really good news about the internal reference is that is not very sensitive to changes in the ATmega Vcc (5 Volts applied to the processor chip).

Nor is it very sensitive to ambient temperature in the 60F to 85F range. Beyond that I don't know.

Sorry for the confusion with the 0.069 value, it was a typo. I also probably should have mentioned my resistor choices, I have a shoe box full of resistors, capacitors, chips, etc and those resistors where simply the first I pulled out. Ideally I will set up a divider such that it can convert, 22V(solar panel max open circuit is 20V) and 15V(Battery being charged) to something around 2-4V being read by one of the analog pins.

Thank you for the equation suggestions I think I was using the 1024 value incorrectly in my equation. I will try out your suggestions tonight and get back to guys with my results.


I am currently at a loss. I changed my resistor values such that the output to the analog pin is 2V from a 12.56V battery. The circuit is simply the battery voltage running across a 43k and 8.2k in series with the an analog pin connected in between them. I tried implementing Dave's and rugged circuit's equations and still no dice.

At this point I figured "well what the heck is that pin reading?" So I had the arduino print the analog value directly to my lcd display and gave a 4sec delay between readings. The display is continuously showing a reading of 0.00 or 1023.00 with no noticeable order.

Obviously something is wrong. I've never put more than 5V into the arduino, I double check the voltage with a meter before connecting the pin to it. I also set a nice long delay for the on board capacitors to charge from the pin. (I read that this may be needed with output impedances above 10k)

What is really perplexing me is that for the past 2 weeks I've used the board to read/display voltages across a voltage divider using a photo diode and a single resistor with no problems using the arduino's 3.3V as a source. I set up a similar circuit use the same equations plus your's but with 12V and it doesn't work.

Anyways any further help would be appreciated

The display is continuously showing a reading of 0.00 or 1023.00 with no noticeable order.

Open circuit / analog pin not connected? Are you certain you connected to the same pin you are reading?

So I double checked the analog pin locations and everything is fine. I then hooked up the 5V rail to test and it displayed the correct value. I then hook up the battery and it shows the funky values again.

This leads me to believe it has something to do with Vref (which I'm guessing) or maybe the way the I'm connecting the battery? The battery circuit is literally +terminal--->43k--->analog pin--->8.2k---> -terminal.

my equations im using are:

voltage = ( sensorvalue * vref)/1024

battery voltage = voltage / ( R2/(R1+R2)

where: voltage is the analog pins reading being converted battery voltage is whats being displayed R1=43k R2=8.2k vref=5V

Do you have the battery -terminal connected to the Arduino GND?

Jeez :roll_eyes: that did it. So much headache for something so little

Thanks Coding badly

You are welcome and thank you for the follow-up.