analogRead - divide by 1023 or 1024?

But you agreed when I quoted:

0x000 represents analog ground, and 0x3FF represents the selected reference voltage minus one LSB.

Minus one LSB is clearly 4.995 volts if the reference voltage is 5V. It isn't some other value.

[quote author=Nick Gammon link=msg=2110889 date=1424846583] But you agreed when I quoted:

Minus one LSB is clearly 4.995 volts if the reference voltage is 5V. It isn't some other value. [/quote]

Would that not mean that our input range is 0 - 4.995V, meaning each bin is worth 4.995 / 1024 = 0.004877929687V. And 1023 * 0.004877929687 = 4.9901220698V?

On the other hand if the input range is 0 - 4.999...V, this means each bin is worth 4.999... / 1024 = 0.0048828125V. And 1023 * 0.0048828125 = 4.9951171875V

You are double-handling there. Let's assume that the ADC converts 0 to 5V to 0 to 1024.

However it stops one LSB short of 1024. Therefore it reports 4.995 as 1023.

[quote author=Nick Gammon link=msg=2110896 date=1424847165] You are double-handling there. Let's assume that the ADC converts 0 to 5V to 0 to 1024.

However it stops one LSB short of 1024. Therefore it reports 4.995 as 1023. [/quote]

But is it not valid to assume that 4.995 to 4.999...V is still part of the 1024th bin? and that 5.000V to 5.005V is part of a non-existent 1025th bin?

Let's not bring non-existent bins into the mix.

Ps991: But is it not valid to assume that 4.995 to 4.999...V is still part of the 1024th bin?

Exactly. 1023 (the 1024th bin) represents 4.995 to 5V.

but...but...then you can measure 0 to 4.9999...V, its just you can only represent then in 1024 0.0048828125V increments, you can still map 4.999...V to 0 to 1023

I can but the processor can't because it rounds down.

[quote author=Nick Gammon link=msg=2110916 date=1424848181] I can but the processor can't because it rounds down. [/quote]

Then we can both agree that the processor is stupid and obsolete and that we must introduce organic brains into microprocessors! Finally somebody that agrees with me on this!

If you are going to argue with me again, explain what the datasheet meant about "minus one LSB."

0x3FF represents the selected reference voltage minus one LSB.

This means that 0x3ff represents 5V (reference voltage) minus 1 LSB (5 / 1024)V, thus 5 - 0.005V = 4.995V

It can represent the voltage as 0 to 4.995V, but it can measure/map 0 to 4.999…V

I assume they mean that the last bin is the “trash bin”. 1023 represents a voltage range that extends to Vcc+0.5

Maybe this will help. The converter does two things...

  1. Compare two voltages. The comparison answers one question ... is the sample-and-hold voltage (which is the analog input voltage if everything works as desired) less than the current comparison voltage.

  2. Change the current comparison voltage in discrete steps. Each step is Vref (5V) / 1024.

We know #1 and #2 are true because that's how successive approximation converters work. We know the step size is correct because the company that made the converter told us the step size.

The last step is over-sized (reaches Vcc+0.5) because the converter can only make a less-than comparison. The first step does not include a precise zero because the converter can only make a less-than comparison.

You can avoid the conundrum entirely if you just work directly with the result of analogRead. Generally, I'd expect any thresholds relating to making decisions in a sketch to be #defined or declared const, so there's no reason not to express them in the 0-1023 range. Comments can relate them back to voltage if desired.

Given that, I don't see much (if any) benefit in expending CPU cycles converting to voltage.

After reviewing the replies and datasheets (AVR and SAM), for the AVR, I will now use 1024 as the divisor.

AVR:

Referring to the datasheet for the Atmel 328P, page 252 24.7 ADC Conversion Result: Here it states that the result is ADC = (Vin * 1024) / Vref and that 0x000 represents analog ground and 0x3FF (1023) represents the selected reference voltage minus one LSB.

Therefore, the ADC binary range of 0-1023 represents an input voltage range of 0-4.9951171875 volts

Converting a 1023 reading to volts, I agree here that using (1023 * 5) / 1024 = 4.9951171875 volts is the accurate method to use.


SAM:

Now, in the datasheet for the SAM3X (Due), page 1329 44.1 (ADC) mentions: A digital error correction circuit based on the multi-bit redundant signed digit (RSD) algorithm is employed in order to reduce INL and DNL errors.

Here, WIKIPEDIA: Successive approximation ADC under Algorithm, it mentions: The objective is to approximately digitize x to an accuracy of 1/2n.

Does this mean that here, for 10-bit ADC, one should use 1023.5 and for 12-bit ADC (Arduino default) one should use 4095.5 as the divisor? (it appears so to me).

middle of the bin corresponding to the value zero is 5/2048 volts, the middle of the bin corresponding to value 1023 is 5*2047/2048 volts, thus the correct calculation for the expected voltage value given an ADC value is

5 * (2n+1) / 2048 volts, or in C:

  float volts = 5.0 * (analogRead (pin) + 0.5) / 1024.0 ;

MarkT, that makes sense to me, especially for the AVR.

EDIT: Your calculation effectively puts approx +0.5% offset on the result, which will range from 0.00244140625 volts to 4.99755859375 volts for readings from 0 to 1023.

I wonder if this would apply to the SAM where it seems to have the 1/2 bin approximation buit-in (RSD Algorithim??). If so, then then would the correct calculation for the SAM be this?

float volts = 5.0 * (analogRead (pin)) / 4096.0 ;

(edit: I know, this is really splitting hairs here!)

Ps991: but...but...then you can measure 0 to 4.9999...V, its just you can only represent then in 1024 0.0048828125V increments, you can still map 4.999...V to 0 to 1023

[quote author=Nick Gammon date=1424848181 link=msg=2110916] I can but the processor can't because it rounds down. [/quote]

It's not the processor but the programmer who rounds down when simply dividing the bin number by 1024. You would round up by adding one to the bin number first. By rounding up you can get exactly 5V with a reading of 1023, such as by calculating 5 * ((1023 + 1) / 1024) = 5, but then you lose a calculated 0V at the bottom end.

But given a reading of 0, you don't really know that the input was exactly 0V. You know only that it was less than 0.0049V.

Likewise, given a reading of 1023, you don't really know that the input was exactly 5V but that it was somewhere between 4.9951V and 5V at least 4.9951V. (Thanks to AWOL for pointing out this error.)

This is just the nature of quantizing an analog signal.

You could report a reading of 1023 as either 4.9951V or 5V, but both of those have an error of 0.0024V on average and an error of 0.0049V in the worst case. You could report it as 4.9976V, which has no error on average and an error of only 0.0024V in the worst case. You could even report it as 4.9976 +/-0.0024V, which has the measured error built-in.

Likewise, given a reading of 1023, you don't really know that the input was exactly 5V but that it was somewhere between 4.9951V and 5V.

Nope You only know that the voltage was greater than 4.99xxx Volts

dlloyd:
Does this mean that here, for 10-bit ADC, one should use 1023.5 and for 12-bit ADC (Arduino default) one should use 4095.5 as the divisor? (it appears so to me).

No, I don’t think so. The answer given below your reply, of adding 0.5 to the reading, seems more correct than dividing by a different number than that recommended in the datasheet.

christop:
It’s not the processor but the programmer who rounds down when simply dividing the bin number by 1024. You would round up by adding one to the bin number first. By rounding up you can get exactly 5V with a reading of 1023, such as by calculating 5 * ((1023 + 1) / 1024) = 5, but then you lose a calculated 0V at the bottom end.

That’s just replaced one rounding error (rounding down) with another one (rounding up).

As I said earlier, the error is going to be less than 1/10th of a percent (ie. 1/1024) or indeed half of that, as the error is stated to be +/- 0.5 LSB. So really the error is going to be (roughly) +/- 1/20th of a percent.