3

When using the built-in analog to digital converter of the Arduino Uno Rev 3's Atmega328P with a reference voltage of 5V, what is the appropriate function to interpret the output? There is conflicting information on the Arduino website and in the datasheet for the Atmega328P (Arduino Uno Rev 3's chipset).

A lot of code examples on the internet indicate that the appropriate conversion factor is 5V/1023 (including the Arduino website: float voltage= sensorValue * (5.0 / 1023.0);).

Per the Atmega328P's datasheet, it indicates the conversion factor is 5V/1024: enter image description here

If Vin and Vref are 5V, then the ADC reading would need to be 1024 in order to have a true reading of 5V, which is not possible since 1023 is the max output of the ADC. The closest reading to 5V we can get from this equation is ~‭4.9951 (5V*1023/1024).

With the Arduino example's conversion factor of 5V/1023, we get 5V for an ADC output of 1023.

Additionally, since the information from both sources is in conflict, it got me thinking a little more: The ADC is inherently sampling, and I am not sure if the ADC rounds up/down to the nearest value, so perhaps the closest approximation of Vin is an equation like the following that splits the difference:

Vin = (ADC+(ADC+1))/2 * 1024/Vref

Using the above equation, an ADC reading of 0 with Vref=5V would give Vin = (0 + (0+1))/2 *1024/5V = ~0.00244. This equation never gives a reading of 5V or 0V, but rather a value that splits the difference between samples.

Perhaps I am splitting hairs since the absolute accuracy of the ADC is "±2 LSB absolute accuracy", but I would still like to know which is the best equation to convert an output from the ADC into a voltage measurement.

8
  • You're overthinking things here. It really doesn't matter if you use 1024 or 1023 - the ADC isn't that accurate anyway.
    – Majenko
    Commented Jan 15, 2020 at 20:28
  • Besides, you divide by the maximum value, not the number of steps - so 1023 is the correct one. The two would be the same if counting started at 1, but it doesn't - it starts at 0
    – Majenko
    Commented Jan 15, 2020 at 20:30
  • @Majenko Even if the ADC isn't that accurate, I would still like my readings from it to be as accurate as possible and not introduce unnecessary error by use of the wrong equation. Also, if you are confident that 1023 is the correct value, then you are confident it is just a persistent typo that it appears in multiple AVR chipset datasheets (including ATmega2560, ATtiny85, ATmega1284)? Commented Jan 15, 2020 at 20:47
  • It's an argument that has been raging for years and years. The difference between the two is so minor that it is dwarfed by the inaccuracy of the ADC. It really is pointless. Use whichever you feel happiest with.
    – Majenko
    Commented Jan 15, 2020 at 20:50
  • 1
    Here's one thread of the argument. As I say, it's been raging for years. forum.arduino.cc/index.php?topic=303189.0
    – Majenko
    Commented Jan 15, 2020 at 21:41

3 Answers 3

3

the Atmega328P's datasheet, it indicates the conversion factor is 5V/1024 [...]

Indeed. And the datasheet is the only authoritative source. All the other sources are second-guessing.

If Vin and Vref are 5V, then the ADC reading would need to be 1024 in order to have a true reading of 5V

You can't get a true reading of 5 V. As per the datasheet (emphasis mine): “0x000 represents analog ground, and 0x3FF represents the selected reference voltage minus one LSB”.

Any input voltage larger that the maximum representable voltage will read as 0x3ff (i.e. 1023), just like any negative voltage (within the forward voltage of the protection diode) will read as zero. Thus, reading either 0 or 1023 should be interpreted as a saturation of the ADC, meaning the actual voltage is unknown.

The ADC is inherently sampling, and I am not sure if the ADC rounds up/down to the nearest value

In principle it should round to the nearest value. The transition in the reading from 0 to 1 should ideally happen at Vref/2048. C.f., again, the datasheet, subsection “ADC Accuracy Definitions”: “Offset: The deviation of the first transition (0x000 to 0x001) compared to the ideal transition (at 0.5 LSB).

A little bit further in the page it is stated that the ideal position of the last transition (1022 to 1023) is “at 1.5 LSB below maximum”.

Perhaps I am splitting hairs since the absolute accuracy of the ADC is "±2 LSB absolute accuracy"

Indeed. If you really care you should probably calibrate your ADC. See Response of the Arduino ADC.

Edit: in a comment you mention that the factor 1024 could conceivably be “a persistent typo that it appears in multiple AVR chipset datasheets”. It may be an error, but certainly not a typo, as the datasheet contains multiple independent statements that confirm the factor 1024.

1
  • 1
    The calibration curves are interesting -- looks fairly straight, but the slopes differ. On could do much of the calibration by looking for the ratio that gives ADC==1 and ADC==1022 and fitting just those points.
    – Dave X
    Commented Jan 24, 2022 at 3:03
3

As others have said, the difference between 1023 and 1024 is quite small.

However, the fact is that your input range for the ADC is 0 to 1023. (That's 1024 steps, but since it starts at 0, it won't go up to 1024)

You'll get 0 at the minimum input, and 1023 at the maximum value.

If you're using a 5.0V reference voltage and no voltage dividers, that means you will get 1023 at 5V (ignoring measurement error.) If you want your output value to be the VOLTAGE measured, you would want Vin / 1023.0 * 5.0. That would give you a value of 5.0 at the max input of 1023 (representing 5.0 volts) and 0 at 0 volts input.

Edit:

Since my posting, I read the threads on this, and there is a raging debate on the subject. I am now less clear that there is "right" way to do this.

The issue is that the ADC value doesn't give you a certain reading, it indicates a range. When you get a value of 1024, the ADC is tellling you that the measured voltage is in the top 1/1024th of voltages, from about 4.995V to 5V (or above, for that matter.)

The steps are actually in 1024ths. That argues that you should divide the measured value by 1024, and then return a range of possible voltages:

value = analoglRead(pin);
float lower_value = value / 1024.0 * 5.0;
float upper_value = (value + 1) / 1024.0 * 5.0;

For an analog reading of 0, that would give you a range of 0.0v. to 0.0048828125v.

For an analog value of 1023, that would give you a range of 4.9951171875v to 5.0v

0
0

After reading through various arguments for use of different transfer functions, this is my summary:

In order to achieve the manufacturer-stated absolute accuracy of ±2 LSB, you should use the manufacturer's equations and published guidelines on usage to ensure that accuracy (e.g. ensuring appropriate ADC clock speed / sampling time and implementing noise reduction techniques).

It may be possible to achieve better results using another transfer function by calibrating specific to each individual circuit. If you go this route, all of the responsibility of ensuring accurate calibration across the range of expected operating conditions (including offset/gain drifts due to environmental factors) are your responsibility to characterize and account for when developing the transfer function. This is where the transfer function Vin = 5V/1023 * ADC fits in. This transfer function may in fact be a better representation of the actual outputs for a specific chip. However, use of this transfer function shifts responsibility onto its user to verify that it actually produces better results.

A couple of important notes:

  • Manufacturer's claims are not always accurate. However, they are likely based on a large statistical sample size and if the manufacturer's published statements are wrong, this potentially opens the manufacturer up to lawsuits depending on the impact of an incorrect published specification. For this reason, I tend to trust manufacturer datasheets from large chip makers until proven otherwise.
  • The question assumed a perfect 5V reference for simplicity of discussion, however the actual value of a real voltage reference is almost impossibly a true 5V and has some degree of noise affecting its stability which should also be considered when attempting to read a true voltage value. Ideally, if you are trying to read a sensor value and can create a circuit in which the voltage reference cancels out of the final measurement, that will help with accuracy of the sensor reading.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.