Willkommen zu einem weiteren Beitrag des Programmierkurses mit Arduino und Protocoder für Maker! In dieser Lektion lernen wir, wie man Unterbrechungen bzw. Interrupts verwendet. Aber worum handelt es sich eigentlich? Ein Interrupt ist ein Signal, das die aktuelle Aktivität des Prozessors unterbricht, damit eine andere Funktion ausgeführt werden kann. Die Unterbrechung kann extern, wie zum Beispiel durch das Drücken eines Tasters, oder intern, beispielsweise durch eine Zeituhr oder ein Software-Signal hervorgerufen werden. Einmal aktiviert unterbricht Interrupt die Aktivität des Prozessors und sorgt dafür, dass eine andere Funktion ausgeführt wird. Bekannt ist dies unter dem Namen Unterbrechungsroutine oder ISR, nach der englischen Abkürzung. Sobald die ISR abgeschlossen ist, kehrt das Programm wieder zu seiner vorherigen Aktivität zurück. Wenn du mehr über Interrupts erfahren möchtest, gehe zur Referenzseite, die du hier findest.
Materialliste
- ZUM BT-328, Arduino-Platine oder kompatibel.
- Taster oder Schalter
Elektrische Verbindungen
Die Anzahl der Pins, die als Interrupts verwendet werden können, hängt von der Art der Platine ab, die wir verwenden. Für die ZUM BT-328 Platine, Arduino Uno und affine sind es zwei. Sie befinden sich in den Pins 2 und 3 und entsprechen dem Interrupt 0 oder dem Interupt 1.
Die Verwendung von Interrupts
Um die Interrupts verwenden zu können, müssen wir zuerst den gewünschten Interrupt festlegen. In unserem Fall verwenden wir den Interrupt 0, der sich beim Pin 2 befindet und bestimmen daher wie folgt:
1 |
int interrupcion = 0; |
Im Setup müssen wir angeben, welche Funktion aufgerufen werden soll, wenn die Unterbrechung eintritt. Hierfür verwenden wir die Funktion attachInterrupt mit der folgenden Syntax:
1 |
attachInterrupt(interrupt, ISR, mode); |
Die Argumente der Funktion attachInterrupt lauten:
- Interrupt: Nummer des Interrupts, das heißt, in welchem Pin auf die Unterbrechung “gelauert” wird.
- ISR: die Funktion, die aufgerufen wird, wenn die Unterbrechung eintritt.
- Mode: Bestimmt die Art, wie die ISR einsetzen wird, das heißt, was passieren muss, damit die Unterbrechung stattfindet. Die verschiedenen Modi lauten:
- LOW: wird immer dann ausgeführt wenn der Wert des Pisn 0 beträgt.
- CHANGE: wird immer dann ausgeführt wenn eine Veränderung auftritt.
- RISING: wird ausgeführt solange der Wert von 0 bis 1 geht (oder von 0 bis 5 Volt).
- FALLING: wird ausgeführt solange der Wert von 1 bis 0 geht (oder von 5 bis 0 Volt).
Es ist wichtig, darauf zu achten, dass die Modes mit Großbuchstaben geschrieben werden, da sonst ein Fehler auftritt. In unserem Fall verwenden wir:
1 |
attachInterrupt(interrupcion, funcionInterrupcion, FALLING); |
Diese Funktion bemerkt, wann wir deb Taster loslassen. Außerdem müssen wir die Funktion festlegen, die beim Entdecken der Unterbrechung aufgerufen wird. In diesem Fall haben wir die Funktion funcionInterrupción aufgerufen und definieren sie mit dem gleichen Namen, den wir in attachInterrupt verwendet haben. Die Funktion lautet daher:
1 2 3 4 5 |
void funcionInterrupcion(){ Serial.print("Interrupt numero "); Serial.println(numInterrupt); numInterrupt++; } |
Hier drucken wir auf den seriellen Monitor die Anzahl, wie oft die Unterbrechung eingesetzt hat. Eine der Besonderheiten der Interrupts ist, dass sie kein Argument in ihrer Definition enthalten dürfen und auch keinen Wert ausgeben. Um sicherzustellen, dass die ISR Zugriff auf die Variablen besitzt, müssen wir einen volatile-Variablentyp verwenden, was in diesem Fall der int-Typ ist. Wenn du mehr über volatile erfahren möchtest, gehe zu dieser Referenzseite. Eine weitere Einschränkung der Interrupts ist, dass der Rest der Interrupts nicht erkannt wird, solange wir uns in einer ISR befinden. Es funktioniert kein delay und auch der Wert der millis wird nicht aktualisiert. Daher sollten die ISRs so kurz wie möglich sein.
Der Code
Hier könnt ihr den kompletten Code sehen. Denkt daran, dass ihr den Code auch zusammen mit den Bildern herunterladen könnt, die am Ende dieses Beitrags verwendet werden.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
int interrupcion = 0; // Interrupt.0 befindet sich beim digitalen Pin 2 // Interrupt.1 befindet sich beim digitalen Pin 3 /* Wir erstellen die Variable mit dem Schlüsselwort volatile, um sicherzustellen, dass die Variable vom normalen Programmfluss und vom Interrupt verfügbar ist. */ volatile int numInterrupt = 0; void setup() { Serial.begin(9600); // Syntax der Unterbrechungen: // attachInterrupt(numero_interrupt,función_a_ejecutar,modo); // Modi LOW,CHANGE,RISING,FALLING attachInterrupt(interrupcion, funcionInterrupcion, FALLING); } void loop() { /*Wir simulieren eine Aufgabe, die Zeit benötigt. Wir verwenden While(true), da die Bedingung immer erfüllt ist und der enthaltene Code fortlaufend ausgeführt wird. */ while(true){ Serial.print("."); delay(250); } } void funcionInterrupcion() { Serial.print("Interrupt numero "); Serial.println(numInterrupt); numInterrupt++; // Wir erhöhen die in numInterrupt gespeicherte Zahl um eine Einheit. } |
Zuerst bestimmen wir die Variablen, die wir verwenden werden. In unserem Fall sind es Interrupt, mit der wir dem Mikroprozessor angeben, welche Unterbrechung wir durchführen wollen und numInterrupt, die die Anzahl angibt, wie oft auf die Unterbrechung zugegriffen wurde. In der Setup-Funktion starten wir den seriellen Port und bestimmen die Unterbrechung, die wir mit attachInterrupt(); verwenden. In der loop-Funktion wird eine Handlung simuliert, die eine bestimmte Zeit für die Ausführung benötigt. In diesem Fall wird ein Punkt “.” auf den seriellen Port geschrieben, um zu vermeiden, dass die Visualisierung des Programm-Outputs überladen wird. Wenn die Unterbrechung eintritt, beim Loslassen des Tasters in unserem Fall, wird die Ausführung des Programms unterbrochen und auf dem seriellen Port erscheint “Interrupt numero ” gefolgt von der Anzahl, wie oft in die Unterbrechung gegangen wurde. Als Übung schlage ich dir Folgendes vor: Verändere die Art und Weise, wie in die Unterbrechung gegangen wird und sieh dir an, wie dies den Kreislauf beeinflusst.