I've been trying to replicate the setup seen in this Arduino Playground article, which features a TSL1402 linear sensor array. Basically, it's used for sensing the brightness of light hitting it along an array of photodiodes (think of it as a one dimensional digital camera sensor).
I've got it working using the code in the article (I haven't figured out how to graph the serial data yet, but at least I can see it in the serial monitor).
There are a few interesting things that I've been trying to understand in the code:
// To set up the ADC, first remove bits set by Arduino library, then choose
// a prescaler: PS_16, PS_32, PS_64 or PS_128:
ADCSRA &= ~PS_128;
ADCSRA |= PS_32; // <-- Using PS_32 makes a single ADC conversion take ~30 us
This is done in order to change the division factor between the system clock and ADC clock (learned about that here). This increases the sampling rate of the ADC.
My main question is how does it work? I've been reading through the bitmath tutorial in order to understand it.
Maybe it would be best just to focus on one line of code:
It's my understanding that this is declaring a value for PS_32, which would be a prescaler (division factor) of 32. It's putting a 1 into ADPS2 and also in ADPS0. I just don't see how. When I look at "1 << ADPS2", I read "shift 1 left by (value of ADPS2) spaces," but how does that Change the value of ADPS2 to 1?
That is how it is used for the ATmel microcontrollers. Together with the 'c'-language it makes such strange constructions.
All bits in the ATmega registers are the bit number, not the mask.
The bit on the right is bit 0 and the bit on the left is bit 7.
Suppose the third bit from the right has to be set, that is bit number 2.
The trick is to shift a '1' two times to the left and put that into the register.
To add that to the register, or to remove it, the 'and' and 'or' and 'not' are used.
The macro _BV() and the Arduino function bitSet() do nothing else than that trick with shifting a '1' a number of times.
ADPS0 and ADPS2 are bit numbers in the ADCSRA register. They have the the values of 0 and 2. Now for the bitmath part. It is very important that you view all numbers in binary in order to understand.
(1<<ADPS0) will shift the value 00000001 left by 0 steps giving a result of 00000001
(1<<ADPS2) will shift the value 00000001 left by 2 steps giving a result of 00000100
(1<<ADPS0)|(1<<ADPS2) will make a bitwise or of the two previous results yielding a final result of 00000101
Similarly (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) will yield a result of 00000111.
It is common to use a expression of the type(1<<bitnr) to set that bit.
If we continue
~PS_128 will invert the bits of our previous result yielding a value of 11111000
ADCSRA &= ~PS_128 will make a bitwise and of the contents of the ADCSRA register and 11111000 which means the 3 least significant bits will be cleared. Since we now know that these bits are cleared
ADCSRA |= PS_32 will set bits 0 and 2 yielding a result of xxxxx101 where x designates a bit that has not changed.
Wow, thank you both very much. As I'm sure you can imagine, all these bitwise operations are very unintuitive to me as a newbie, but now they are starting to become clear to me. I understand exactly how they work in this sketch now.
Nilton - The way you spelled it out for me step by step was very helpful. Your response is exactly what I was looking for. Thank you.