Hi all,

I’m attempting to build a voltmeter with an Arduino and getting horribly skewed readings through voltage divider. My layout is as follows:

Analog reference set to 1.1v
R1 = 1M ohms (1% tolerance)
R2 = 8.2k ohms (1% tolerance)

Junction of voltage divider going to A2. I feed 5.0v (DMM reads 4.98v) from board to R1, and get a reading of 2.11322 volts in Arduino (calculated with voltage divider.)

Using circuit simulators and my DMM, I can confirm the correct reading of ~0.040 volts at the junction I’m pulling into the Arduino. If I manually change vout in the code to 0.040 volts my voltage divider calculation works perfectly fine.

To test the ADC accuracy of my board, I’ve removed all resistors, changed AREF to 5.0 and read directly from a AA battery. DMM gives me 1.25 volts and Arduino reads 1.2453. Pretty dead on.

Any help would be greatly appreciated. I’m a software engineer by trade, and trying to expand my knowledge into hardware… but it’s really kicking my butt.

I’ve included a picture of my voltage divider, and here is my code

``````#define ANALOG_INPUT A2
#define ANALOG_RESOLUTION 1024.0
#define VREF 1.1
#define R1 1000000.0
#define R2 8200.0

const float voltageDividerRatio = (R2 / (R1 + R2));

void setup() {
Serial.begin(9600);

if (VREF == 1.1)
analogReference(INTERNAL);

pinMode(ANALOG_INPUT, INPUT);
}

void loop() {
float vout = (analogRead(ANALOG_INPUT) * VREF) / ANALOG_RESOLUTION;
float vin = vout / voltageDividerRatio;

Serial.print(vout, 5);
Serial.print(" ");
Serial.print(vin, 5);

Serial.println();

delay (1000);
}
``````

The circuit connected to an (AVR at least) analogue pin should have a maximum of 10k impedance.

From the ATmega328p data sheet:
"The ADC is optimized for analog signals with an output impedance of approximately 10 k or less"

Edit:
Maybe try to change the voltage divider to 10k / 82 ohms. If you don't like the power wastage, switch the top of the divider with a digital pin and only on when you want to make a measurement.

Try “printing out” the raw ADC reading. It should be about 38 (at 40mV with a 1.1V reference).

…If the meter reads 40mV the source impedance isn’t the issue. The meter and Arduino are both reading the same physical voltage, but the meter is probably filtered/smoothed to minimize noise and the meter is probably more accurate.

If the raw ADC value is wrong, what Arduino are you using? (The internal references and reference commands are different on some Arduinos.) You can also check the AREF pin with your multimeter.

Once you get this sorted out, note that the 1.1V reference is stable but it’s not necessarily super-accurate. So you may need to do some calibration (in software) depending on how much accuracy you need.

And, if you are really going to read 5V you’re loosing a lot of resolution by reducing the voltage that much with a voltage divider. I assume you are planning on reading higher voltages?

Here is a good place to do the divider thing http://www.ohmslawcalculator.com/voltage-divider-calculator.

When I used an Uno, the item that made the largest difference in settling down the A:D readings was to put a cap into the aRef and gnd connectors on the board and soldering the divider components vs using a breadboard.

Hey all,

Thanks for taking the time to respond!

My apologies for not stating that I intend to use this as a multi-purpose voltmeter. I'm just using the 5v as a known good, stable reference to calibrate my readings. Having decent range would be desirable.

DVDdoug,
I printed out the raw ADC values. Varying slightly at 30-31. As I mentioned before, I took the resistors out of the circuit and my arduino read a AA battery accurately at 1.25 volts. The inaccuracies start with the addition of resistors.

I've measured the 5v and AREF on the Arduino, they're ~4.80 and 1.1 +/- .02 volts. Started out using an Uno, which it's ADC values did -not- reflect the accurate voltage of a AA battery, but the Leonardo I'm using did.

6v6gt,
I was under the assumption that the "10k or less" was measured from R2 to analog input? I suppose this is where my elementary understanding of basic circuits is failing me. I'll give that a shot, but is there any other way to get more range out of this? I was hoping to measure up to at least 50vdc if that's feasible.

Idahowalker,
I attempted a 44nF capacitor from R2 to ground. Would that be enough? It didn't really change the reading for me at all, except it slightly delayed returning to 0.00 volts when I removed the 5v lead.

I'll try soldering everything together later on tonight.

What board are you using?

Current I'm using the Leonardo

I was under the assumption that the "10k or less" was measured from R2 to analogue input?

Correct...almost.

Assuming that the output impedance of the supply providing the 5V to R1 is low enough to be ignored then from an impedance point of view the +ve and -ve of the 5V supply have a very low resistance between them, equivalent to the supply internal resistance. That means that you can consider the 5V connection to R1 and the 0V connection to R2 to be connected together through the power supply. That means you can consider R1 and R2 to be in parallel for the purposes of calculating the output impedance from these 2 resistors as seen by the A2D input at the junction of R1 and R2. The A2D therefore sees:
1/((1/1000000) + (1/8200)) = 8.133k Ohms.

Ok. But the sampling capacitor in the adc has to be charged in a reasonable amount of time. The rate of charge will be affected by the high value resistor. In a static situation like this it is not so important, but for high sampling rates it begins to have an impact.

6v6gt:
The circuit connected to an (AVR at least) analogue pin should have a maximum of 10k impedance.

From the ATmega328p data sheet:
"The ADC is optimized for analog signals with an output impedance of approximately 10 k or less"

Edit:
Maybe try to change the voltage divider to 10k / 82 ohms. If you don't like the power wastage, switch the top of the divider with a digital pin and only on when you want to make a measurement.

1M/8k2 divider has a source impedance of less than 10k, since its load is seeing 1M || 8k2.

Small voltage offsets will happen if you fail to use star-grounding for your divider.

6v6gt:
Ok. But the sampling capacitor in the adc has to be charged in a reasonable amount of time. The rate of charge will be affected by the high value resistor. In a static situation like this it is not so important, but for high sampling rates it begins to have an impact.

I suspect you are considering the situation of the 1M Ohm resistor alone and trying to apply it to the situation we are discussing, they are not the same.

If there were just the 1M Ohm resistor then the sampling capacitor would be charging through 1M Ohm to 5V.

This situation is the sampling capacitor charging to 0.04V from a source impedance of 8.133k Ohms. Different source impedance, different voltage.

What is the maximum voltage you want to read? With the divider you have (attenuation factor of 132) it would take 145V to reach full scale (ADC value of 1023). 5 volts would be way down in the mud, ADC value of 35, 142 mV per count.

I highly recommend using the voltage divider calculator at: http://www.ohmslawcalculator.com/voltage-divider-calculator.
Another thing check the accuracy you are trying to get, you show 6 digits in your calculation. To validate this you need a 7 digit meter (an order of magnitude better) to be sure of what you are getting. How accurate is your DMM and how many digits. Has it been calabrated recently? How accurate is your voltage source? What is the tolerance of your parts, 1% will not support 6 digits straight up.
The following link gave me this table: What is the relation between ADC resolution and DVM digits?? | AVR Freaks Just because the math can calculate 5 digets it in no way indicates your measurement is accurate to that. Don't get too hung-up on bit count, all they do is give you precision. They don't give you accuracy. Dig deeper into the datasheet.

Decimal digits Bits required to represent:
5 17
6 20
7 24
8 27
9 30
Another note, do not use the arduino 5V regulator to drive anything else, simply turning on a LED can cause a measurable difference in your reference voltage.

Good Luck & Have Fun!
Gil

OOPS! Math blunder: >:( Should have been:
With the divider you have (attenuation factor of 123) it would take 135V to reach full scale (ADC value of 1023).
5 volts would be way down in the mud, ADC value of 38, 132 mV per count.

OK. It looks like I still have to do some homework on impedance networks.

The OP's problem is, however, the assumption about the internal reference voltage on an 32U4 chip (Leonardo).
Unlike the 328P (Uno etc.) , this voltage is 2.56 volts, not 1.1 volts.

The OP's problem is, however, the assumption about the internal reference voltage on an 32U4 chip (Leonardo).
Unlike the 328P (Uno etc.) , this voltage is 2.56 volts, not 1.1 volts.

Ah!
I was making that mistake too! ++Karma;

Sorry for the delayed replies, all.

I had a horrible time last night, as my soldering iron was busy dying on me. A Hakko 888 should be waiting for me when I get home from work.

6v6gt,
Magnificent! I didn't even realize that. Seems I need to read more datasheets, and pay more attention. I'm leagues closer to an accurate reading than before!

A 12.45 volt LiPo 3S battery pack reads 12.29 volts (used to be ~10.3), the 5v reference is saying 4.61 volts and 3v3 reference is staying 3.07.

New soldering iron tonight and no distractions - I'll be back on this shortly!

Thanks for all of your replies.

Hey guys,

I purchased perfboard, solder and a Hakko 888. I’ve soldered everything together, but still no dice. Removed all of the analogReference calls, using 5 volt reference again. Arduino reads 4.99v on it’s own 5v reference without voltage divider, and (11 ADC) 3.60v going through the divider.

Picture of the board I’ve soldered is attached, and amended code posted.

Before this, I tried 10k and 220 ohm resistors on the breadboard, with the same problem. Very funny, skewed readings. I’m not one to give up, but this just seems to be unattainable for me.

``````#define ANALOG_INPUT A2
#define ANALOG_RESOLUTION 1024.0
#define VREF 5
#define R1 1000000.0
#define R2 8200.0

const float voltageDividerRatio = (R2 / (R1 + R2));

void setup() {
Serial.begin(9600);

pinMode(ANALOG_INPUT, INPUT);
}

void loop() {
float vout = (analogRead(ANALOG_INPUT) * VREF) / ANALOG_RESOLUTION;
float vin = vout / voltageDividerRatio;

Serial.print(" ");
Serial.print(vout, 3);
Serial.print(" ");
Serial.print(vin, 3);

Serial.println();

delay (1000);
}
``````

Serial.print(vin, 3);
~135volt with three decimal places requires 135000 A/D counts.
More than 100x what you actually have.

Serial.print(vin, 1); // would be realistic
But even that is not possible without some oversampling.
Leo..