[Solved] Arduino not reading the expected voltage on a voltage divider

This is my wiring (270k resistor on the left, 820k on the right):

This is my code:

String str1 = "A0: ";
String str2 = "V; A1: ";
String str3 = "V";

double analog_A0;
double analog_A1;

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

void loop() {
  analog_A0 = analogRead(A0) / 200.19;
  analog_A1 = analogRead(A1) / 200.19;
  Serial.println(str1 + analog_A0 + str2 + analog_A1 + str3);
}

So what I want to do is the arduino Uno be able to read voltages between 0 and ~20V like a voltmeter. I need to divide voltages by 4, so 20V is divided to 5V.

I read the first part of this article and I understood that I could use a voltage divider to do so, and the sum of its resistors could be about 1Mohm.

Then I calculated two good standard resistor values, 820k and 270k, and bought them.
You can see how much voltage results with a voltage divider like this, at this online calculator:

Then I built the wiring as shown above and wrote the above code. I double checked wiring connections in case of any mistake.

The arduino Uno is connected to the computer via USB.

I measured the 5V pin on the arduino with a multimeter, and it reads ~5.11V, so I use this as the reference for the analogRead().
So the analogRead() returns 0-1023 values, and in case it returns 1023, the real voltage should be 1023 / 200.19 = 5.11V (hence the 200.19 in the code).

Now it should read 1.266V at A1 pin, but it is reading 1.43V:

I discovered that there is a "special" effect when reading these voltages with my multimeter: as the multimeter at 20V range doesn't have a much different impedance than the voltage divider (while the voltage divider has 1.09Mohm, the multimeter seems to have 1Mohm, or at least a few Mohms), when I try to read the voltage across the 270kOhm resistor using the multimeter, it influences the circuit so that the serial readings start to be 1.30V at A1 pin, and the multimeter reads 1.09V.

But it seems to me that if this influence of the analog input high impedance was the problem, then the read voltage should be lower than expected, not higher. It's like connecting a big resistor in parallel with the voltage divider resistor. The resistance will decrease, the current increases, and voltage decreases. I can't see why it's reading 1.43V instead of the expected 1.26V.

I also tried including the real measured values of the resistors in the online calculator, but it doesn't seem to make much a difference.

What is wrong? Thank you in advance.

Why such high values for your divider? Try R1 = 22k and R2 = 6.8k. 22k + 6.8k = 28.8k, 6.8k / 22.8k = 0.23611,
5V * 0.23611= 1.18V, 20V * 0.23611 = 4.722V.

The article you read is giving bad advice. The analog input has very high DC input resistance (>100 Megohm), but it also has a capacitor that must be charged, and the recommended maximum source impedance (the voltage divider) is 10 K.

For your high impedance voltage divider, you must add a 100 nF capacitor from the divider output to ground, in order to reduce the effective impedance of the voltage source. That will slow down the response substantially, but that is fine for infrequent voltage measurements.

Some cheap multimeters have 1 Megohm input impedance. To correct for the meter loading effect in such a case, recalculate the effective voltage divider, which is 820K over 270K in parallel with 1 M (=212.6 K).

So the effective division ratio is 212.6/(820+212.6) = 0.205, instead of 270/(820 + 270) = 0.248, so the meter reading will seem too low.

You also need to calibrate the ADC for the actual ADC reference voltage. Use your multimeter to measure that.

I would use a much smaller capacitor, no need for 100 nF. 1-2 nF should be more than enough, as it’s about two orders of magnitude larger than the internal one.

Nonetheless it should work without the external capacitor, but you have to read A1 twice. The first reading sets the MUX to that input, and as it takes a moment to charge the internal cap the reading is bound to be off (a bit too high, likely, as the voltage has to drop) Then the second reading will be much more accurate as the ADC has had time to settle.

The better method is of course to lower the resistor values. The recommended input impedance for the ADC is <10k, you have over 200k (calculate the parallel resistance of the two resistors).

For overall more accurate measurements: bring down your input voltage to <1.1V, and use the internal reference. You have to calibrate this reference voltage once (it has a 10% tolerance) but it’s stable, usually far more stable than your 5V supply, and independent from the supply voltage. E.g. a 1k2 and a 22k resistor combination will do fine for your 20V input.

JCA79B:
Why such high values for your divider? Try R1 = 22k and R2 = 6.8k. 22k + 6.8k = 28.8k, 6.8k / 22.8k = 0.23611,
5V * 0.23611= 1.18V, 20V * 0.23611 = 4.722V.

I wanted to interfere as little as possible with the circuit that is being read. So when I read that article, I thought the bigger resistance, the better. It says multimeters usually have 10MOhms impedance, and then gives an example with about 1MOhm impedance. So I thought it was a good number, as it would just draw a few microamps.

That seems to me also a good combination of resistors. But I only bought 820k and 270k resistors, I can buy others, but as of now I still don’t know what’s going on with the wrong reads, and it would be better if I could use these I already have.

jremington:
The article you read is giving bad advice. The analog input has very high DC input resistance (>100 Megohm), but it also has a capacitor that must be charged…

When does it must be charged?

jremington:
For your high impedance voltage divider, you must add a 100 nF capacitor from the divider output to ground, in order to reduce the effective impedance of the voltage source. That will slow down the response substantially, but that is fine for infrequent voltage measurements.

I’d like to be able to read voltage quickly and frequently. Also right now I only have a 10uF capacitor I took of a broken device. Does not fit, correct?

jremington:
Some cheap multimeters have 1 Megohm input impedance. To correct for the meter loading effect in such a case, recalculate the effective voltage divider, which is 820K over 270K in parallel with 1 M (=212.6 K).

So the effective division ratio is 212.6/(820+212.6) = 0.205, instead of 270/(820 + 270) = 0.248, so the meter reading will seem too low.

Yes, it looks like my cheap multimeter really has 1Mega ohm impedance.
Now, any explanation about why the arduino reads 1.43V normally and about 1.30V when I connect the multimeter?

jremington:
You also need to calibrate the ADC for the actual ADC reference voltage. Use your multimeter to measure that.

If I understand you correctly, I did that. I measured 5.11V between GND and 5V pins with the multimeter and am using it in the calculations. So Vref = 5.11V.

wvmarle:
I would use a much smaller capacitor, no need for 100 nF. 1-2 nF should be more than enough, as it’s about two orders of magnitude larger than the internal one.

What is the advantage of a 1-2 nF instead of a 100nF?

wvmarle:
Nonetheless it should work without the external capacitor, but you have to read A1 twice. The first reading sets the MUX to that input, and as it takes a moment to charge the internal cap the reading is bound to be off (a bit too high, likely, as the voltage has to drop) Then the second reading will be much more accurate as the ADC has had time to settle.

Do you mean like this:

void loop() {
  analog_A0 = analogRead(A0) / 200.19;
  analog_A1 = analogRead(A1) / 200.19;
  Serial.println(str1 + analog_A0 + str2 + analog_A1 + str3);
  analog_A0 = analogRead(A0) / 200.19;
  analog_A1 = analogRead(A1) / 200.19;
  Serial.println(str1 + analog_A0 + str2 + analog_A1 + str3);
}

or this?

void loop() {
  analog_A0 = analogRead(A0) / 200.19;
  analog_A1 = analogRead(A1) / 200.19;
  analog_A0 = analogRead(A0) / 200.19;
  analog_A1 = analogRead(A1) / 200.19;
  Serial.println(str1 + analog_A0 + str2 + analog_A1 + str3);
}

None of these fix the issue, though. The same result.

wvmarle:
The better method is of course to lower the resistor values. The recommended input impedance for the ADC is <10k, you have over 200k (calculate the parallel resistance of the two resistors).

So between every analog input I use and the GND I should not have more than 10kOhms?

wvmarle:
For overall more accurate measurements: bring down your input voltage to <1.1V, and use the internal reference. You have to calibrate this reference voltage once (it has a 10% tolerance) but it’s stable, usually far more stable than your 5V supply, and independent from the supply voltage. E.g. a 1k2 and a 22k resistor combination will do fine for your 20V input.

Do you mean using analogReference(INTERNAL)? Being max input 1.1V won’t it be less accurate?


I also still don’t understand how a resistor in parallel (like the multimeter or ADC impedance) can increase the read voltage instead of decrease it.

EDIT: Just saying that when I switch the resistor positions, then it reads ‘correctly’:

I'd like to be able to read voltage quickly and frequently

How frequently? State the reading rate.

Now, any explanation about why the arduino reads 1.43V normally and about 1.30V when I connect the multimeter?

Same explanation. The meter resistance changes the voltage divider ratio.

What is the advantage of a 1-2 nF instead of a 100nF?

The voltage divider will respond more rapidly to input voltage changes, but the voltage readings will show more variation (be noisier).

I also still don't understand how a resistor in parallel (like the multimeter or ADC impedance) can increase the read voltage instead of decrease it.

It doesn't. You must be doing something else wrong. Study this tutorial on a loaded voltage divider.

Benur21:
When does it must be charged?

The ADC has a small capacitor built in, that must be charged up to the voltage you want to measure. If you don't give it time to settle to the (new) voltage or to follow a changing voltage, you get a wrong reading.

I'd like to be able to read voltage quickly and frequently. Also right now I only have a 10uF capacitor I took of a broken device. Does not fit, correct?

That'll slow down your readings badly. Your RC constant is about 2 seconds in that case, so voltage takes about 10 seconds (5*RC) to settle.

What is the advantage of a 1-2 nF instead of a 100nF?

It settles 50-100 times faster than the 100 nF, but may also have more noise. The faster your signal changes, the least you want to slow this down, so you want a smaller capacitor. The noisier your electrical environment, the more noise you have, and you'll want a larger capacitor for better noise suppression. The final value is as always a compromise.

Do you mean like this:

void loop() {

analog_A0 = analogRead(A0) / 200.19;
  analog_A1 = analogRead(A1) / 200.19;
  Serial.println(str1 + analog_A0 + str2 + analog_A1 + str3);
  analog_A0 = analogRead(A0) / 200.19;
  analog_A1 = analogRead(A1) / 200.19;
  Serial.println(str1 + analog_A0 + str2 + analog_A1 + str3);
}

No: you're still switching between every reading.

  analog_A0 = analogRead(A0); // Dummy reading - to set the MUX to A0 and allow input to settle.
  analog_A0 = analogRead(A0) / 200.19; // Actual reading.
  analog_A1 = analogRead(A1);
  analog_A1 = analogRead(A1) / 200.19;

Do you mean using analogReference(INTERNAL)? Being max input 1.1V won't it be less accurate?

No, more accurate (more stable reference voltage), same resolution (1024 ADC points on the full scale of 0-1023). After all you're working with ratios. Absolute values don't matter for the measurement itself.

When buying resistors don't get the one or two values you think you need, get one of those kits with 20 pcs of 30 values. It's dirt cheap, I got a set of 1% such resistors for less than USD 1 equivalent. You'll end up not needing some values but you never know which one you need when... they come in useful when you least expect it. Cheap enough and small enough to just keep on hand, and a great convenience when you need them, like now. Same for capacitors, a set of multiple values ceramics is the same price. Electrolytics cost a little more, still not much. Very common values I buy in bulk, couple hundred a time, like the 10k, that's used all over the place. Same for the 100 nF capacitor.

jremington:
How frequently? State the reading rate.

Everytime I want the analogRead to read the value on a pin. Something like I did in the code I posted. I don't know how fast it runs. I think serial makes it slower, but probably at the actual speed (with the serial) it's already good.

wvmarle:
No: you're still switching between every reading.

  analog_A0 = analogRead(A0); // Dummy reading - to set the MUX to A0 and allow input to settle.

analog_A0 = analogRead(A0) / 200.19; // Actual reading.
analog_A1 = analogRead(A1);
analog_A1 = analogRead(A1) / 200.19;

Oh, I wouldn't have thought like that.
IT WORKS! Thank you!!!

Now I know the problem was something with the capacitor, so it would not read accurately.
Are there any limitations / disadvantages of doing like this instead of using a 1-2nF capacitor? Other than the normal time to read an analog input being doubled?

wvmarle:
No, more accurate (more stable reference voltage), same resolution (1024 ADC points on the full scale of 0-1023). After all you're working with ratios. Absolute values don't matter for the measurement itself.

Thanks for the suggestion, then!

A small cap on the pin should help it to settle faster, and you probably don't need the second reading method.

Try it out! See what works best for you.