I often find myself having to rouse a few extra brain cells to remember the math for getting a meaningful number from a raw ADC value. When I'm measuring voltages to check on supply voltage or for some other reason, late in the afternoon the voltage divider, voltage reference and resolution figures go around and around until I eventually remember how to mash them together to get an accurate number for my code to use. To that end I realised its probably time to throw a quick calculator together to make this quick and painless. And being an open source fan I thought it might be helpful for someone else having afternoon brain fade.
So here it is, a simple spreadsheet with some numbers and some reference material, and even a picture! Put in your resolution, voltage reference, voltage divider resistor values and it will give you the multiplier values to turn a raw ADC result into a float in volts or millivolts! It will even highlight if you are trying to measure a voltage that is out of range, so you can fiddle with voltage divider resistor values till something works. Here's a screenshot and the .xlsx file is attached here:
Edited to calculate resolution from total number of possible values instead of full scale value (ie. divide by 1024 instead of 1023 for a 10 bit resolution) thanks to the patient forum members who pointed this out to me
@anon56112670 yes you are correct, however when calculating mV per ADC step, we need to look at the total number of voltage steps or transitions and not the total number of possible values, and this is always total number of possible values minus 1 (1023 for a 10 bit resolution). A simplified way to see this is if we reduce our resolution all the way down to 1 bit. Technically a 1 bit resolution still has two possible values, however if we divide 3.3 by 2 we end up with 1650mV. A result of 0 calculates to 0V as expected, but a result of 1 calculates to 1.65V instead of 3.3V as it should.
Realistically no-one is going to see a scale error of 1 in a 10 bit setup (the noise is usually at least 2-4 LSB in the real world with no filtering anyway). So it's not exactly a major problem if you go with 1024 instead of 1023
You can both calculate it that way if you like, however you will never reach full scale by calculating it that way. Using 1024 as the divider and reading 3.3V will give you a result of 3.297V, whereas calculating with 1023 as divider gives the correct value, so.... Whatever you like
There is no "correct value" if the ADC reads 1023.
The integer returned by an ADC always represents a range of possible values, and a value of 1023 simply means that the input voltage is equal to or above the threshold.
So how many people actually read a value and then treat it as a range instead of a figure in the real world? To me FSD = VREF is more logical than FSD = VREF - 1LSB.
Unfortunately, few Arduino users understand how an ADC works, and many of them make the mistake of assuming that the answer is exact. This means that they also don't understand why resolution is important.
Thanks @jremington for linking this in, my humble apologies for previous ignorant posts. That makes sense now, I'm embarrassed to say I've been calculating it this way since the days of programming PIC MCU's in ASM 15 odd years ago, so haven't spent alot of time googling this - amazing to see how much discussion there is around one 1024th of a number haha Amending spreadsheet... Thanks for your patience!
Yes! Unfortunately , as many people have pointed out, the difference between 1023 and 1024 is usually insignificant compared to other popular but wrong assumptions, for example, assuming that Vref for the ADC is "exactly" 5.000 V.
…names each of the 1024 boxes between 0 and Vcc with their midpoints and has the happy side effect of avoiding divides by zero and logs of 0 for things like voltage dividers and thermistor calculations.
Alternately, you can name the 1024 intervals by their 'floors' using Vref*ADC/1024 to name the bottom interval zero; or name the 1024 intervals by their 'ceilings' with Vref*(ADC+1)/1024, to get a the top interval named Vref; or finally, the bastardized mix of the bottom interval named by its floor and the top interval named by its ceiling using Vref*ADC/1023 but that madness is susceptible to off-by-one errors.
My take on 1023 or 1024: If the ADC result shifts by 1, the input value (or range of values) shifts by 1/1024 of the full scale. Yes, a result higher than 0x3F (1023) is impossible, but the shift-per-step remains 1/1024.
I will use 1024 anyday.
Oh dear. The main "error" wasnt the 1023 - it was this:
A 10 bit adc with an analog reference of 3.30V DOES NOT give 3.2226563mV.
NOR does it give this: 0.00322265625V
you cant get 12 decimal digit resolution from a 10 bit digital value.
Nor is the ADC precise or linear to that degree of accuracy. Especially near zero.
So why give a conversion fator that would lead an inexperienced user to believe his reading of 1 from the adc means their input voltage is 0.00322265625V?