Es gibt zwei Arten von Interrupts vom Typ "Stiftwechsel". Die externen Interrupts, von denen es zwei auf dem Uno gibt. Sie heißen 0 und 1, beziehen sich jedoch auf die digitalen Pins 2 und 3 auf der Platine. Diese können so konfiguriert werden, dass sie ansteigen, abfallen, sich ändern (ansteigen oder abfallen) oder NIEDRIG erkennen.
Zusätzlich gibt es "Pin-Wechsel" -Interrupts, die einen Wechsel des Pin-Zustands in einem der 20 Pins (A0 bis A5 und D0 bis D13) erkennen. Diese Pin-Wechsel-Interrupts basieren ebenfalls auf Hardware und sind an sich so schnell wie die externen Interrupts.
Beide Typen sind auf Registerebene etwas umständlich zu verwenden, aber die Standard-IDE enthält attachInterrupt (n) und detachInterrupt (n), wodurch die Schnittstelle zu externen Interrupts vereinfacht wird. Sie können auch die Pin-Change-Bibliothek verwenden , um die Pin-Change-Interrupts zu vereinfachen.
Wenn Sie sich jedoch für eine Minute von der Bibliothek fernhalten, können Sie feststellen, dass Pin-Wechsel-Interrupts genauso schnell oder schneller sind als externe Interrupts. Zum einen müssen Sie, obwohl Pin-Wechsel-Interrupts für Stapel von Pins funktionieren, nicht den gesamten Stapel aktivieren. Wenn Sie beispielsweise Änderungen an Pin D4 erkennen möchten, reicht dies aus:
Beispielskizze:
ISR (PCINT2_vect)
{
// handle pin change interrupt for D0 to D7 here
if (PIND & bit (4)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of PCINT2_vect
void setup ()
{
// pin change interrupt (example for D4)
PCMSK2 |= bit (PCINT20); // want pin 4
PCIFR |= bit (PCIF2); // clear any outstanding interrupts
PCICR |= bit (PCIE2); // enable pin change interrupts for D0 to D7
pinMode (4, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
Mein Test ergab, dass es 1,6 µs dauerte, bis der "Test" -Pin (Pin 5) auf eine Änderung am Interrupt-Pin (Pin 4) reagierte.
Wenn Sie nun den einfachen (faulen?) Ansatz wählen und attachInterrupt () verwenden, werden Sie feststellen, dass die Ergebnisse langsamer und nicht schneller sind.
Beispielcode:
void myInterrupt ()
{
if (PIND & bit (2)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of myInterrupt
void setup ()
{
attachInterrupt (0, myInterrupt, CHANGE);
pinMode (2, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
Das Wechseln des Teststifts dauert 3,7 µs, viel mehr als die obigen 1,6 µs. Warum? Weil der Code, den der Compiler für den "generischen" Interrupt-Handler generieren muss, jedes denkbare Register beim Eintritt in die ISR speichern (pushen) und sie dann vor der Rückkehr wiederherstellen (popen) muss. Hinzu kommt der Overhead eines weiteren Funktionsaufrufs.
Jetzt können wir das umgehen, indem wir attachInterrupt () vermeiden und es selbst tun:
ISR (INT0_vect)
{
if (PIND & bit (2)) // if it was high
PORTD |= bit (5); // turn on D5
else
PORTD &= ~bit (5); // turn off D5
} // end of INT0_vect
void setup ()
{
// activate external interrupt 0
EICRA &= ~(bit(ISC00) | bit (ISC01)); // clear existing flags
EICRA |= bit (ISC00); // set wanted flags (any change interrupt)
EIFR = bit (INTF0); // clear flag for interrupt 0
EIMSK |= bit (INT0); // enable it
pinMode (2, INPUT_PULLUP);
pinMode (5, OUTPUT);
} // end of setup
void loop ()
{
}
Das ist mit 1,52 µs die schnellste von allen - es sieht so aus, als wäre irgendwo ein Taktzyklus gespeichert worden.
Es gibt jedoch eine Einschränkung für PIN-Wechsel-Interrupts. Sie sind gestapelt. Wenn Sie also Interrupts an vielen Pins haben möchten, müssen Sie innerhalb des Interrupts testen, welcher geändert wurde. Sie können dies tun, indem Sie den vorherigen Pin-Status speichern und mit dem neuen Pin-Status vergleichen. Dies ist nicht unbedingt besonders langsam, aber je mehr Pins Sie prüfen müssen, desto langsamer wird es.
Die Chargen sind:
- A0 bis A5
- D0 bis D7
- D8 bis D13
Wenn Sie nur ein paar weitere Interrupt-Pins wünschen, können Sie jedes Testen vermeiden, indem Sie nur Pins aus verschiedenen Chargen verwenden (z. B. D4 und D8).
Weitere Details unter http://www.gammon.com.au/interrupts