Interrupts richtig einsetzen!

Was ist ein Interrupt?

Ein Interrupt bei einem Mikroprozessor ist ein Ereignis, das den normalen Programmablauf unterbricht, um eine spezielle Aufgabe oder eine dringende Anforderung zu behandeln. Interrupts ermöglichen es dem Mikroprozessor, auf externe Signale zu reagieren oder interne Ereignisse zu verarbeiten, ohne dabei den laufenden Programmcode zu blockieren.

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);
  }
}
				
			

Zum Video

★☆★ Wenn ihr den Kanal unterstützen wollt über ★☆★

oder über

Twint Spenden Code

Letzte Aktualisierung am 26.04.2024 / Affiliate Links / Bilder von der Amazon Product Advertising API