I have a quick silly question. I was browsing the tutorials to try and get familiar with the arduino and i saw the following example:
"This function will read a sensor five times with analogRead() and calculate the average of five readings. It then scales the data to 8 bits (0-255), and inverts it, returning the inverted result.
int ReadSens_and_Condition(){
int i;
int sval = 0;
for (i = 0; i < 5; i++){
sval = sval + analogRead(0); // sensor on analog pin 0
}
sval = sval / 5; // average
sval = sval / 4; // scale to 8 bits (0 - 255)
sval = 255 - sval; // invert output
return sval;
}
"
my specific question is about this line:
sval = sval / 4; // scale to 8 bits (0 - 255)
why do we do this? isn’t the value already in 8 bit format? since an analogue sensor would report a value from 0 - 255 anyways right? so
taking the average of 5 values i.e. (255+255+255+255+255)/5 = 255 is the average…and binary 11111111 = decimal 255. So we are already an 8 bit value are we not?
or is it since the MCU has a 16-bit architecture that values read in from an analogue sensor are actually 16 bit values and we are scaling them down to 8 bits? but then shouldn’t we just divide by 2? as 16/2=8?
Im rather confused, could someone help me to understand please?
As westfw said the Analog to Digital convertor returns 10 bit results.
In order to convert the value from 10bit to 8bit it has to be scaled down. A 10bit value can hold a maximum of 1024 and an 8bit value can hold a maximum of 256.
In other words an 8bit value is a quarter of the size of a 10 bit value. So inorder to scale it down to being an 8bit value we have to divide by four. In otherwords we are mapping a value in the 0-1024 range to a value in the 0-256.
Thats the simple explanation.
There is another way of converting a 10 bit value to an 8 bit value, using bit shifting. You simply shift the 10bit value 2 bits to the right to make it into an 8bit value.
Shifting a value 1 bit to the right is the same as dividing by to, so shifting 2 bits to the right is the same as dividing by 4. So the code could also have been written as
sval = sval >> 4
The trick of shifting values to the right to divide by 2 and shifting to the right to mulitply by 2 is something assembly language programmers often use. But since we have the lovely abstraction of the Wiring language we don't have to worry about that.
I checked now in the playground and found this which explains the whole thing about bit shifting for math if you are interested in reading further:
And usually the avr-gcc compiler is smart enough to convert that into shifts, and not the Wiring lib, its a lib, not a pre-processor/pre-compiler/compiler thingie.
Just to clarify, the ATmega328 has an 8-bit architecture. The A-D converter result is internally represented by two registers (ADCH and ADCL). ADCL is the low byte and ADCH is the high byte, unless you set the A-D converter to left-aligned mode, in which case you can get an 8-bit value directly from ADCH.
Luckily, the Ardunio libraries hide this complexity and let you work directly with the full 10-bit value. Point being simply that the ATmega328 is just a lowly 8-bit MCU. Even the ATmega2560 on the Arduino Mega is just a really big 8-bit microcontroller.