Interrupts richtig einsetzen!
von Edi · 29/05/2023
Was ist ein Interrupt?
Wenn ein Interrupt auftritt, stoppt der Mikroprozessor die Ausführung vom aktuellen Programm und springt zu einer vordefinierten Interrupt-Service-Routine (ISR). Die ISR ist ein spezieller Codeabschnitt, der die erforderlichen Aufgaben für den Interrupt erledigt. Dies kann beispielsweise das Lesen von Daten von einem Eingabegerät, das Aktualisieren eines Timers oder das Verarbeiten eines Hardwarefehlers sein.
Es gibt verschiedene Arten von Interrupts, darunter Hardware-Interrupts und Software-Interrupts. Hardware-Interrupts werden durch externe Ereignisse ausgelöst, wie beispielsweise Tastendrücke. Software-Interrupts werden durch spezielle Befehle im Programmcode aktiviert, um bestimmte Aktionen auszuführen oder zu kommunizieren.
Nach Abschluss der ISR kehrt der Mikroprozessor zum unterbrochenen Programmablauf zurück und setzt die Ausführung beim nächsten Befehl fort.
Die Interrupt Service Routine (ISR)
Die ISR sollte so kurz wie möglich gehalten werden, um sicherzustellen, dass der normale Programmablauf schnell wieder aufgenommen werden kann. Lange ISR können zu Verzögerungen im System führen und die Reaktionsfähigkeit des Mikroprozessors beeinträchtigen. Daher werden in der Regel nur die absolut notwendigen Aufgaben innerhalb der ISR ausgeführt. Komplexere Aufgaben oder zeitaufwendige Operationen werden normalerweise außerhalb der ISR durchgeführt.
Der Syntax für die ISR Funktion sieht folgendermassen aus.
IRAM_ATTR void ISR() {
ISR Funktion;
}
Für die ISR gibt es ein paar Regeln die eingehalten werden sollten.
• Keine delay(), micros() oder millis() Funktion verwenden
• Nur globale Variable verwenden die als flüchtig (volatile) deklariert werden.
• Keine serielle Bibliothek, also keine Ausgabe auf dem seriellen Monitor verwenden
• Sicherstellen, dass der verwendete Pin ein Interrupt Pin ist
Die Interrupt Service Routine auslösen
Um die Interrupt-Service-Routine auszulösen, verwenden wir die Funktion attachInterrupt() im Abschnitt setup(). Deaktiviert kann der Interrupt mit detachInterrupt() werden. Die Funktion attachInterrupt() benötigt drei Parameter.
Der erste Parameter ist die Interruptnummer. Mit digitalPinToInterrupt(), wird die Nummer des digitalen Pins verwendet, an dem der Taster angehängt ist.
Der zweite Parameter ist der Name der Interrupt-Service-Routine die beim Auslösen vom Interrupt aufgerufen wird.
Der dritte Parameter ist der Interrupt-Modus. Der Interrupt-Modus definiert die Art des Signals, das den Interrupt auslöst. Es gibt vier verschiedene Interrupt-Modi:
• LOW – der Interrupt wird ausgelöst, wenn der Interrupt-Pin LOW ist
• RISING – der Interrupt wird ausgelöst, wenn das Signal von LOW auf HIGH geht
• FALLING – der Interrupt wird ausgelöst, wenn das Signal von HIGH auf LOW geht
• CHANGE – der Interrupt wird ausgelöst, wenn das Signal entweder von HIGH auf LOW oder von LOW auf HIGH wechselt
attachInterrupt(digitalPinToInterrupt(buttonPin), ISR_button, CHANGE);
Der Hardware Interrupt
In diesem Beispiel verwenden wir einen Wemos d1 mini, der über einen Taster eine LED an- und ausschaltet. Die Überprüfung, ob der Taster gedrückt ist, erfolgt mit einem Interrupt und auch das Taster entprellen fehlt hier nicht. Der Taster ist am GPIO D1 angehängt und die LED wird über D2 geschaltet.
const byte buttonPin = 5; //D1
const byte LEDPin = 4; //D2
byte lastButtonState = 0;
const int debounceTime = 30; // millis
byte toggleState = 0;
unsigned long lastButtonTimeChange = 0;
volatile int buttonFlag;
void setup() {
Serial.begin(115200);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(LEDPin, OUTPUT);
attachInterrupt(digitalPinToInterrupt(buttonPin), ISR_button, CHANGE);
}
IRAM_ATTR void ISR_button() {
buttonFlag = 1;
}
void loop() {
if (millis() - lastButtonTimeChange > debounceTime && buttonFlag) {
lastButtonTimeChange = millis();
if(digitalRead(buttonPin) == 0 && lastButtonState == 1){
toggleState =! toggleState;
digitalWrite(LEDPin, toggleState);
lastButtonState = 0;
}
else if(digitalRead(buttonPin) == 1 && lastButtonState == 0) {
lastButtonState = 1;
}
buttonFlag = 0;
}
}
Der Software Interrupt
const byte LEDPin = 4; //D2 - Wemos d1 mini
byte toggleState = 0;
long previousMillis = 0;
long interval = 1000; // 1000 Millisekunden = 1 Sekunde
void setup() {
Serial.begin(115200);
pinMode(LEDPin, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
toggleState =! toggleState;
digitalWrite(LEDPin, toggleState);
}
}
Letzte Aktualisierung am 9.09.2024 / Affiliate Links / Bilder von der Amazon Product Advertising API