Voltage reading formula

Thread Starter

gogo00

Joined Oct 28, 2023
37
Hi there, I need some help understanding how to use a microcontroller's ADC to read voltages from a variable DC supply (0-12V) and display them on a screen. I know I need a voltage divider circuit since the microcontroller can only handle up to 5V. With a 10-bit ADC and a reference voltage of 5V, I'm calculating the voltage using:

Voltage = (ADC sample / Total ADC samples) * reference voltage

For instance, at 6V supply, I'm getting a 512 ADC value, which computes to 2.5V. How can I adjust the formula to display the correct voltage value (6V) on the screen? This is a general question, not specific to any microcontroller, display, or compiler
 

Thread Starter

gogo00

Joined Oct 28, 2023
37
Hi gogo,
Multiply by 2.
Post your divider circuit.
E
Thank you for your help! Your explanation clarified my query. I've figured out that if the supply voltage is set at 3V DC, resulting in an ADC value of 256, the calculation to get the corresponding voltage after multiplying by 2.4 would be:

256/
1023
×5×2.4=3V DC

This helps in understanding the relationship between the ADC value and the actual voltage. Appreciate your help
 

MrChips

Joined Oct 2, 2009
30,823
You can ignore all the fancy formulae and do the following:

If 6V gives 2.5V, 6 / 2.5 = 2.4
Hence multiply by 2.4.
This is a procedure called calibration.
 

BobaMosfet

Joined Jul 1, 2009
2,113
Hi there, I need some help understanding how to use a microcontroller's ADC to read voltages from a variable DC supply (0-12V) and display them on a screen. I know I need a voltage divider circuit since the microcontroller can only handle up to 5V. With a 10-bit ADC and a reference voltage of 5V, I'm calculating the voltage using:

Voltage = (ADC sample / Total ADC samples) * reference voltage

For instance, at 6V supply, I'm getting a 512 ADC value, which computes to 2.5V. How can I adjust the formula to display the correct voltage value (6V) on the screen? This is a general question, not specific to any microcontroller, display, or compiler
Your datasheet should have a formula and explanation for scaling.
 

Jerry-Hat-Trick

Joined Aug 31, 2022
552
When you are scaling like this, always multiply before dividing to maximise the display resolution in you are using integer numbers which you almost certainly are. Also, watch out for and compensate for the fact that the processor pin has an impedance, albeit high. If, for example, you are using potential divider to drop 12V to 5V by tapping the voltage between a 15K resistor and a 10K resistor to ground your processor will see 12 x 10/(10 + 15) = 4.8V but since the ADC pin has impedance in parallel with the 10K the actual voltage will be slightly lower, or at least different as resistance values are not exactly accurate.

So it's best to check the actual digital value when the input value is exactly 12V and calibrate from this number - lets say its an ADC value of 970. And lets say you are reading a voltage with an ADC value of 544; this represents a voltage of 544 x 12 /970 = 6.73V
 

MrChips

Joined Oct 2, 2009
30,823
Just as another example, how to multiply by 2.4?
Multiply by 12 and divide by 5.

But instead of doing that, you input 6V and record the number of ADC counts.
Your new formula becomes:

calculated voltage = 6V x (new ADC counts) / ( ADC counts @ 6V)

If you give us your calibration data, i.e. ADC counts at calibrated voltage, we can show you the math using integer arithmetic.
 

joeyd999

Joined Jun 6, 2011
5,287
If you treat the adc value as a fixed point fraction between 0.0 and 1.0, where 1 equals the full-scale input voltage (at the input of the divider), only a single multiplication is necessary.
 

BobTPH

Joined Jun 5, 2013
8,998
Look at the case when you are reading 12V. The divider gives you 5V, so the count is 1023.

So 1023/1023 = 1.

So what would you multiply by to get 12?
 

WBahn

Joined Mar 31, 2012
30,075
I still don't understand why you guys all insist on division. It's not necessary.
I agree -- division is a particularly expensive operation that should be avoided as much as possible. You can also sometimes avoid multiplication when you have control over the calibration. Adjust the voltage divider so that the math operations only involve add/sub and bit shifts.

For instance, if you adjust the the voltage divider so that 12 V produces an ADC output of 1100000000 (a voltage of about 3.754 V), then shifting it six places to the right gives you 12. If you adjust it to 11110000000 (about 4.692 V) and you shift it three bits to the right, you get 120. Display that on a three-digit display with the decimal point hard wired to be before the last digit and you have a display in showing 12.0 V. To get 4.692 V from 12 V, you need a divider with a gain of 0.391. To see how this works, let's see what happens if the voltage is pi (3.14 V). The divider makes this 1.2278 V, which will give an ADC output of about 251. Now shift that by three bits and you get 31, which would be displayed as 3.1 V.
 

joeyd999

Joined Jun 6, 2011
5,287
My way:

1) Treat the A/D values as a fixed point number. 10 bit example:

10 bit right justified: 000000.xx xxxxxxxx
10 bit left justified: 0. xxxxxxxx xx000000

2) If I'm not oversampling, I use a single left-justified conversion. Alternatively, I can oversample 64 10 bit right-justified conversions by summing them:

000000.xx xxxxxxxx summed 64 times = 0. xxxxxxxx xxxxxxxx

As a benefit, if you introduce 1/2 LSB white noise to your input signal, you actually gain 6 additional bits (3 are significant -- known as dithering).

3) Multiply the the the value by the full scale input voltage (or, a 10^n scaled input voltage):

4) Round the result if desired.

-------------------------
Example:

FS = 12V, Input voltage = 4.567V, desired output resolution 3 digits (10^3), 64 oversampled RJ conversions.

A/D out = .01100001 01101101

Multiply by 12,000 (12 * 10^3 for millivolt resolution):

.01100001 01101101 x 00101110 11100000 = 00010001 11010110 . 11010101 01100000 = [4566(d)].[spurious bits]

Add in 1/2 for rounding:

00010001 11010110 . 11010101 01100000 + .10000000 = 00010001 11010111 . 01010101 01100000 = [4567(d)].[discarded bits]

One multiply and an add, and all done.
 
Last edited:

MrChips

Joined Oct 2, 2009
30,823
I still don't understand why you guys all insist on division. It's not necessary.
We're not doing division. This is just a demonstration of what you need to pay attention to when you work with integer arithmetic.
You can still do the equivalent of ( (n + 512) >> 10 ).

I have calculated dewpoint to one decimal place from temperature and humidity readings entirely in integer arithmetic. I want to see someone else beat that.
 

joeyd999

Joined Jun 6, 2011
5,287
I have calculated dewpoint to one decimal place from temperature and humidity readings entirely in integer arithmetic.
What is your implication? That operations on fixed point binary values are not entirely integer arithmetic?

If so, I emphatically disagree. The fixed point simply implies a shift, which you do explicitly.
 
Top