Rounding ADC values properly, ATmega328p-PU

6 posts / 0 new
Author
Message

Dear all,

I came across to a code snippet recently, which is not quite clear to me. The snippet sources from a program written for ATmega family, and utilizes the onboard ADC module for some measurements.

Starting direct after the loop_until_bit_is_clear(ADCSRA, ADSC); what's  the purpose of the lines below. I am guessing that they do some re-scaling and rounding, but if someone could explain it to me in very simple way, what's the intention and why it is done in this way and not other way would help a lot. Sorry for basic question btw.

while (1) {

voltage = ADC * vcc + vcc / 2;
voltage = voltage >> 10;
volts = voltage / 10;
tenths = voltage % 10;
transmitByte('0' + volts);

work in progress...

On the AVR8s, if Vin <= Vref then
ADC = Vin * 1024 / Vref
rearranging gives
Vin = ADC * Vref / 1024

If 'your Vin' is > Vref then you need to scale it down (eg via a resistive divider on the input) to avoid damage and also to not saturate the ADC count, therefore
'your Vin' = k * ADC * Vref / 1024
(You need to see the circuit on that analogue input to properly determine the scaling factor k)

Assuming that voltage is a 16-bit integer variable then
voltage = ADC * vcc + vcc / 2; will produce a 5-digit decimal value of the form abcde
voltage = voltage >> 10; is voltage / 1024 which produces a 2 digit decimal value ab
volts = voltage / 10; extracts the decimal digit a
tenths = voltage % 10; extracts the decimal digit b
transmitByte('0' + volts); produces a human-readable character of the decimal digit a

mikech wrote:
Assuming that voltage is a 16-bit integer variable then
voltage = ADC * vcc + vcc / 2; will produce a 5-digit decimal value of the form abcde

Surely we need to know the type and value of the mysterious "vcc".

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Thanks for the clarification. Although this expression is still odd to me. Does this source from math. or its a C programming trick. Is this used often while coding those kind of stuff.

voltage = ADC * vcc + vcc / 2; will produce a 5-digit decimal value of the form abcde

Coming back to the question of the mysterious Vcc and its value let's see the small picture, I ripped this from a book. As book author states,  his Vcc level is 5.08 Volts (I assume measured at AVcc ? ....),

Why does he needs to multiply it with x 10? and get 50.8 Volts?. The Vcc is not higher than Logic voltage in this case, to use a voltage divider and its constant ' k' as stated by poster " mikech "

int main(void) {
uint16_t voltage;
uint8_t volts;
uint8_t tenths;
uint8_t vcc = 51;

clock_prescale_set(clock_div_1);
initTimer0();
initTimer2();
sei();
initUSART();

while (1) {

voltage = ADC * vcc + vcc / 2;
voltage = voltage >> 10;

}
return 0;
}

work in progress...

All the calculations are done with integers, therefore the x10 scaling of Vref is a way to get the tenths-of-volts.
eg.
with a Vref of 5.08, an input voltage of 3.969 V produces an ADC count of 800
- if the variable vcc (Vref) is 51 then voltage = ADC * vcc + vcc / 2; produces 40825, which after the divide-by-1024 gives 39
- if vcc = 5 we get 4002, which after the divide-by-1024 produces 3
The volts = and tenths = expressions are, in-effect, a divide-by-ten to 'reverse' the x10 Vref.

The + vcc / 2 term in voltage = ADC * vcc + vcc / 2; is a DC offset for the analogue input.
Why ???. Does the author say what signal they are measuring (or trying to do) ?