Incorrect analog read from voltage divider on Arduino Uno vs. ESP32 simple test circuit

Hello,

I'm getting an incorrect reading when trying to read voltage using a voltage divider with two known resistors in a very simple circuit using an Arduino Uno and two 6.8K ohm resistors. When validating with a multimeter i'm measuring the expected voltage after the first resistor/ voltage drop.

I'm using the simple circuit below. Vin = 5V. Both resistors are 6.8KOhm. This circuit is just to validate the correct way of measuring the voltage drop using a divider and analog read op Pin A0.

When using the Multimeter, i'm measuring the expected 2.5V (since both resistors are equal = 50% voltage drop).
When using analog read on A0 i'm measuring the raw value of 440. When converting this to voltage using (440/1023)*5V, im getting 2.15V.

I would expect a raw reading on A0 of approximately 512, leading to the expecterd 2.5V

What am i doing wrong? Or what is the explanation for this unexpected reading result on A0 pin?

Thanks a lot for your support!
Mojies

Are you sure about that 5 there?

Hello Mojies
Take a view here to gain the knowledge.
Measure DC Voltage and Current with an Arduino.

Have a nice day and enjoy coding in C++.
Дайте миру шанс!

Please, do one more experiment and report the result:
1. With your DVM, measure the voltage of the of the 3.3V test point of the UNO Board.
2. Using a jumper, connect this test voltage with A3-pin.
3. Read the signal from A3-pin as count in decimal.
4. Convert the count of Step-3 into voltage.
5. How much have you got in Step-4?

That's weird... Usually the Arduino is very linear, and accurate if the ADC reference is accurate, within one or two counts. And since (presumably) you're using voltage-divided Vcc as your reference you should always read Vcc/2 if the resistors are accurate.

I'd expect the biggest source of error to be the resistor tolerance but you measured with your multimeter.

As another experiment you can try swapping the resistors around (or just swap the 5V and ground connections). If the resistors are exactly equal nothing will change.

If you can't find anything, show us your code.

It's unlikely that the Arduino is bad but that is a possibility.

That's why I have requested to perform another experiment in post #4.

Hello
Did you select the resistors in kOhm range?
Check the values of the resistors.

Measure the voltage on the AREF pin ... by default, that's the value being used for ADC.

Could reverse calculate:

(440/1023)*AREF=2.15 , therefore AREF=4.99875

Oh, OK, never mind ... how about:

  • checking your resistor values (also with multimeter)
  • measuring A0 voltage with a multimeter

Hi all,

Thanks a lot for your comments and advise! Highly appreciated!

My final project will run on an ESP board (DFROBOT FireBeetle 2 ESP32-E). Since i was having trouble with reading of the analog pin, i transferred to an Arduino Uno board (like said above) to verify. However in the sketch i forgot to change the pin for reading the analog signal to A0/0 and left it on pin 34 (like my ESP is using). I changed for the uno the code now to pin A0 and the readings were perfect again and in line with my Multimeter.. sorry this was my mistake!

However the problem remains on my ESP board like i described in original post for the Uno board: The analog reading is not as expected but now with 3.28V as Vin. Analog pin 34 i'm reading a converted voltage of 1.50V instead of the expected 1.63V. I validated the 3.28V on Vin and the 1.63V on pin 34 with Multimeter but can't get it working with the sketch / output. Below is my code snippet. Circuit is similar to the Arduino Uno scheme in original post.

int analogPin = 34;
int raw = 0;
float Vin = 3.28;
float Vout = 0;
float R1 = 6800;
float R2 = 6800;
float buffer = 0;

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

void loop(){
  raw = analogRead(analogPin);
  if(raw){
    buffer = raw * Vin;
    Vout = (buffer)/4095.0;
    
    Serial.print("Vout: ");
    Serial.println(Vout);
      
    Serial.print("Raw: ");
    Serial.println(raw);
    
    delay(1000);
  }
}

leading to the following output Vout

photo1653162843

I would expect a 1.63V reading with the 50% voltage drop of 3.28V.

Any help is highly appreciated!
Mojies

Not likely the source of your problem but this is wrong. For scaling, you use the number of ADC steps, 4096.

Normally, for most devices, Vin is a higher voltage than the MCU operating voltage. It's usually passed through a regulator. So, are you connecting power to the right pin?

Thanks, i changed to 4096 but with no big difference in reading of course :slight_smile:

From here, it says the default ADC attenuation is 11db. There's some functions you could use to adjust...

analogSetAttenuation();     // Sets the attenuation for all ADC channels
analogSetPinAttenuation();  // Sets the attenuation for a specific analog channel pin

How is power applied to the board? You need to measure between the 3.3V and ground pin, not the Vin pin. Also the Vin pin would have 5V or more on it.

Hi all,

Issue solved!

After @dlloyd suggestion i further deepdived into ESP32 specific configuration. However this did not result in a different reading on the pin.

Apparently the issue is the way the polynomial value (V) is calculated from the measured value.
When using the following calculation method I was able to calculate the expected 1.63V!

https://github.com/G6EJD/ESP32-ADC-Accuracy-Improvement-function/blob/master/ESP32_ADC_Read_Voltage_Accurate.ino

However still don't understand why there is a different way in calculating for the ESP (method above) vs. Arduino Uno with the following:
Vout = (buffer)/4096.0;

Happy to learn if anyone can explain what I accidentally found out to be the correct method.

Maurice

Ahh, OK, the ESP32's ADC is Non-linear, so the code you found corrects for this.

I don't completely understand it, but it's a calibration/correction (which may not be needed).

i.e. If you're reading 440 at 2.5V and you know it should be 512, you can correct for the error. And you can correct multiple points along the line.

But... If you are reading 440 when you expect 512 you've got a serious problem and it should be solved and not simply calibrated-out!

You have to calibrate with known voltages (which means you need a good-calibrated voltmeter) and for a particular-individual device. Not every Uno or ESP can be calibrated the same. Every single ADC/processor needs it's own separate calibration. So if you go into-production every unit has to be individually calibrated. And if you're building something for yourself you can't use someone else's calibration data.

Where I work we have a precision multimeter connected to a computer and the calibration is part of a simi-automated test that every unit goes-through. (This is not Arduino-related, it's just ADC & DAC calibration.)

It's more common to have simple straight-line calibration with an offset (usually measured at zero) added/subtracted from the reading, plus a slope correction which is a multiplication factor. (If the device is perfect and doesn't need calibration you'd have an offset of zero and a slope correction of 1.0)

Usually the slope is corrected at maximum, or around the measurement-of interest... If you expect to be measuring 2.5V you can correct the slope at 2.5V and the offset at zero. If you are making a general-purpose voltmeter, you'd usually calibrate zero and maximum.

So you'd normally read 0V (or close to zero) and if you don't read zero, add or subtract to read zero. Then read the maximum (or higher) voltage with the offset applied to the reading, and calculate the required multiplication factor to make that reading "perfect".

The Uno's 10-bit ADC shouldn't normally need any calibration except for taking the actual reference voltage into-account. It should be accurate and linear to within one or two counts.

With 12-bits you may benefit from more-precise calibration/correction.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.