TheMunkee:
That code is blowing my mind! Is that two different types of code? I really dont get the "GIMSK &= ~_BV(INT0)" parts. So, what exactly is AVR?
OK... (LOL!) AVR is the "brand name" of the Atmel microcontrollers that are used in (most of) the Arduino boards.
For example, the full name of the chip in an Arduino UNO is "Atmel AVR-MEGA ATmega328P". The chip in the larger "Mega2560 R3" board is an "Atmel AVR-MEGA ATmega2560".
The Atmel AVR series of microcontrollers are very similar as far as internal layout, register names, bit names, etc... they mostly differ in memory size (for example, the 328P has 32K of flash memory to store programs while the 2560 has 256K of flash memory - similarly the 328P has 2K of RAM while the 2560 has 8K - the 328P has one UART (serial interface) while the 2560 has 4, etc.......).
See? Different amounts of memory and features, but all belong to the "AVR family".
As far as the "mind blowing code", let me try to help you there (the following examples assume an Arduino UNO board):
Let's say you want to connect an LED to pin 8 and make it blink. You can do it 2 different ways. The first way is to use the "Arduino style" function "digitalWrite" as such:
void setup (void)
{
pinMode (8, OUTPUT);
}
void loop (void)
{
digitalWrite (8, HIGH);
// some delay
digitalWrite (8, LOW);
// some delay
}
But, what exactly IS "pinMode" and "digitalWrite" doing? Well, you can probably guess that first the bit you want to use ( the particular one that drives Pin 8 ) needs to be set as an OUTPUT and that then you need to set that pin high, wait a while, set it low, wait a while, etc.....
So, first I will look at the schematic diagram for the Arduino UNO and find what "Pin 8" is actually connected to... hang on a sec... OK got it... Pin 8 is connected to the ATmega328P pin 14 which happens to be PORT B, Bit 0.
Looking elsewhere in the databook, I find that there are 3 different "registers" that control PORTB. These are "PORTB" (the output), PINB (the input) and DDRB (the data direction register - that is "make a bit input or output?").
I want PORTB, Bit 0 to be an output, so first thing I need to do is this:
[b][tt][b]
DDRB |= _BV(0);[/b]
// "|" means "OR"[/b][/tt]
Read out loud, that says "Take the bit value of bit 0, get the current value of data direction register B and OR in the bit 0 value".
In the chip, let's assume that DDRB bits 6 and 7 are already set as outputs by something else. DDRB looks like this:
[b]BIT 7 6 5 4 3 2 1 0[/b]
[b]VALUE 1 1 0 0 0 0 0 [color=red]0[/color]
[/b]
after I "or-in" the bit value for bit 0, DDRB will look like this (the difference shown in red):
[b]BIT 7 6 5 4 3 2 1 0[/b]
[b]VALUE 1 1 0 0 0 0 0 [color=red]1[/color][/b]
Got it so far? Good.
Now we want to turn the bit on and off, and it's bit 0 so we will use the same _BV(0) statement. By the way, "_BV" is just a macro or a "helper" that returns the numeric value of a bit. For example, the decimal value of bit 5 is "32", so _BV(5) returns "32" (saves you the grief of having to figure it out yourself).
OK, now the rest of the code. Since we want to control an output, we need PORTB (not PINB, which is an input). So, to turn the LED on, we would do this:
[tt][b]PORTB |= _BV(0); // the "|" means "or"
[/b]
[/tt]simple enough... we OR in the bit value of bit 0 into PORTB, then do our time delay (not shown above). But how to turn the bit OFF??? Looking at logic, we know that 0 or 1 is 1, and also 1 or 1 is one. But how do we get 0? By using AND.
0 and 1 is 0, while 1 and 1 is one, so to get that bit to be a zero, we need to AND it with a 0. Notice that we DO NOT want to mess up any other bits... we ONLY want to set bit 0 to 0 (low).
So, using AND we need this:
[tt][tt][b]BIT 7 6 5 4 3 2 1 0
1 1 1 1 1 1 1 [color=red]0[/color][/b]
[/tt]
[/tt]but, how do we get that value using _BV? We could just use "0xFE" now that we know the value needed, but in a large program, do you want to bother figuring out the AND value to use for every and any bit? Heck no, it's a pain in the rear!
Luckily, there's a shortcut... the "~" (tilde) character. It means "take any 1 bit and make it 0, take any 0 bit and make it 1".
Cool!!! So, our original _BV(0) looked like this:
[b]BIT 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 [color=red]1[/color][/b]
...and when we use the tilde to "flip it over" we get this:
[b] 1 1 1 1 1 1 1 [color=red]0[/color][/b]
how cool is that?
So, to turn OFF the LED, all we need is this:
[tt][b]PORTB &= ~_BV(0); // the "&" means "and"[/b][/tt]
now, put it all together and we have:
DDRB |= _BV(0); // set port b, bit 0 as an output
while (1) { // do forever (loop)
PORTB |= _BV(0); // LED on
// some delay
PORTB &= ~_BV(0); // LED off
// some delay
}
Does this all make sense now? If not, read it through a few times... you'll get it!
