In todays part we do something a bit more interesting and write an interrupt handler, something you cannot easily do within the Arduino programming language.
Imagine you have have an external signal, such as a button which a user can press, or a signal which is send to you by some other machine, and you want to react to that signal. Instead of the button in the circuit you can also just use two cables and hold them together.
void setup() {
pinMode(13, OUTPUT); // configure pin 13 as output
pinMode(2, INPUT); // configure pin 2 as input
digitalWrite(2, HIGH); // use internal pullup resistor
}
void loop() {
if (digitalRead(2) == LOW) {
toggleLed();
}
// do something else
}
void toggleLed() {
digitalWrite(13, !digitalRead(13));
}
That kind of sequence is often very fine, but depending on the part of "do something else, e.g. when it takes a long time to execute, you might actually miss when someone presses the button. Or when "do something" is very short, and your grandmother presses the button, it will toggle all the time. So this code is actually very errorprone. It is just a simple example.
We define some requirements first:
The behaviour we would like is:
- whenever someone presses the button, the LED should be toggled (PIN2 goes low)
- the LED should toggle only once per button press. (PIN2 stays low)
- the LED shall not toggle when the button is released (PIN2 goes high again).
- No matter when someone presses the button, we want to react.
To meet these requirements, interrupts come to the rescue, and the Atmel chip which is used inside the Arduino has many kinds of Interrupts. Two very simple to programm ones are INT0 and INT1 which are associated with Pin2 and Pin3 (have a look at http://justjoheinz.posterous.com/idiots-guide-to-avr-programming-i for the pin mapping). These are hardware interrupts and the almighty wikipedia tells us, that
A hardware interrupt causes the processor to save its state of execution and begin execution of an interrupt handler.
In English: when the interrupt occurs we can execute the interrupt handler at any time, and resume our execution anywhere where we had been before the interrupt started.
Atmel chips use a table which assigns a given interrupt a function which shall be executed. In reality it is slightly different, but never mind.
Do define the interrupt handler and assign it to the according entry in the table we write this:
ISR(INT0_vec) { // INT0_vec is the predefined vector which is assigned to INT0 aka pin 2, ISR sets this vector in the vector table
digitalWrite(13, !digitalRead(13));
}
This methods replaces toggleLed() which we wrote before, and because toggleLed is now removed from our code, we can also delete everything in the loop() function. We can compile and execute our sketch now, but nothing will happen, because we have not told the processor yet that we want to deal with interrupts and we have not told it yet how we want to deal with interrupts.
To do this, the setup method has to be enriched with some AVR magic. Add the following to the end of your setup() function:
EICRA |= _BV(ISC01);
EIMSK |= _BV(INT0);
sei();
EICRA and EIMSK are again special registers and they are defined in the datasheet, have a look at the bottom of page 73. In the table you can see that for INT0 any time you want to trigger an interrupt on the falling edge of INT0 the Interrupt Sense Control bit 1 need to be set (EICRA |= _BV(ISC01);). Study the other possibilities as well.
Have a look at the next page for the explanation of register EIMSK and you see that we need to enable INT0 (EIMSK |= _BV(INT0);)
The call to sei() simply enables interrupt handling in general.
The finished sketch:
void setup() {pinMode(13, OUTPUT); // configure pin 13 as outputpinMode(2, INPUT); // configure pin 2 as inputdigitalWrite(2, HIGH); // use internal pullup resistorEICRA |= _BV(ISC01);EIMSK |= _BV(INT0);sei();}void loop() {}ISR(INT0_vect) {digitalWrite(13, !digitalRead(13))}
Oh, by the way: if your LED blinks a little erratic - it is because you have shaky hands or your button bounces. And one more really useful thing: instead of configuring pin 2 as an input pin, you can also use it as an output pin. Whenever you write something to this pin in your normal control flow, you are able to trigger the interrupt, depending on your ISC bits.

Keine Kommentare:
Kommentar veröffentlichen