The attachInterrupt() interrupt command

FunduinoLast updated on

Den laufenden Programmablauf sofort auf einen Tastendruck reagieren lassen

Ein Arduino-Programm arbeitet seine Schleife ständig von oben nach unten ab. Wer während eines langen delay auf einen Taster drückt, wartet vergeblich – der Tastendruck geht verloren, weil das Programm gerade woanders beschäftigt ist.

Genau dafür gibt es Interrupts. In dieser Anleitung lernst du den Befehl attachInterrupt() kennen und schaltest damit eine LED per Tastendruck um – unabhängig davon, was das Hauptprogramm gerade tut.

Steckplatine mit Arduino, einer LED und einem Taster
Aufbau: Taster an Pin 2, LED mit Vorwiderstand an Pin 7

Material

Für dieses Projekt brauchst du:

  • 1× Mikrocontroller mit passendem USB-Kabel
  • 1× Steckbrett
  • 1× LED
  • 1× Vorwiderstand 220 Ohm
  • 1× Taster
  • Steckkabel männlich/männlich

Was ein Interrupt ist

Bisher hat dein Programm alles der Reihe nach abgearbeitet: Der Mikrocontroller läuft die Schleife durch und reagiert erst dann auf einen Taster, wenn er gerade an der passenden Stelle ist. Steckt er in einem langen delay, geht ein kurzer Tastendruck einfach verloren.

Ein Interrupt löst dieses Problem. Er unterbricht den laufenden Programmablauf sofort, führt eine festgelegte Funktion aus – die Interrupt-Service-Routine – und kehrt danach an die Stelle zurück, an der er unterbrochen hat.

Wann genau der Interrupt auslöst, legst du mit einem von vier Modi fest:

  • LOW – solange der Pin auf LOW liegt
  • CHANGE – bei jedem Wechsel des Pegels, also in beide Richtungen
  • RISING – nur beim Wechsel von LOW nach HIGH
  • FALLING – nur beim Wechsel von HIGH nach LOW
Tabelle mit den Interrupt-Modi LOW, CHANGE, RISING und FALLING
Die vier Auslösemodi von attachInterrupt() im Überblick

Aufbau

Die LED kommt mit ihrem Vorwiderstand an Pin 7, der Taster an Pin 2. Der Taster schaltet gegen GND – einen zusätzlichen Widerstand brauchst du nicht, weil der interne Pull-up-Widerstand des Mikrocontrollers im Sketch eingeschaltet wird.

Beim Arduino UNO können nur die Pins 2 und 3 einen Interrupt auslösen. An jedem anderen Pin passiert nichts. Andere Boards haben andere oder mehr interruptfähige Pins – beim ESP32 zum Beispiel jeder GPIO.

Steckplatine mit Arduino, einer LED und einem Taster
Aufbau: Taster an Pin 2, LED mit Vorwiderstand an Pin 7

Der Befehl attachInterrupt()

attachInterrupt(digitalPinToInterrupt(TASTER), LEDSchalten, FALLING);

Der Befehl hat drei Teile:

  • digitalPinToInterrupt(TASTER) rechnet die Pin-Nummer in die zugehörige Interrupt-Nummer um.
  • LEDSchalten ist der Name der Funktion, die bei einem Interrupt aufgerufen wird.
  • FALLING legt fest, wann ausgelöst wird – hier beim Drücken, weil der Pegel dabei von HIGH nach LOW wechselt.

Wichtig ist außerdem das Schlüsselwort volatile. Jede Variable, die sowohl im Hauptprogramm als auch in der Interrupt-Routine verwendet wird, muss damit gekennzeichnet werden. Sonst darf der Compiler ihren Wert zwischenspeichern, und das Hauptprogramm arbeitet unter Umständen mit einem veralteten Stand weiter:

volatile bool LEDStatus = LOW;

Der Sketch schaltet die LED bei jedem Tastendruck um: einmal drücken schaltet sie ein, noch einmal drücken schaltet sie wieder aus.

Mit CHANGE statt FALLING würde der Interrupt auch beim Loslassen auslösen. Die LED würde also zweimal umgeschaltet und wäre danach wieder im Ausgangszustand – es sähe so aus, als würde der Taster nicht funktionieren.

Mechanische Taster prellen: Ein einziger Druck erzeugt oft mehrere Flanken hintereinander. Es kann deshalb vorkommen, dass die LED bei einem Druck zweimal umschaltet. Halte den Taster in dem Fall sauber und kurz gedrückt, oder ignoriere in der Routine Auslösungen, die weniger als etwa 200 Millisekunden auseinanderliegen.

Sketch: LED per Interrupt umschalten
#define LED 7
#define TASTER 2

/*
  Je nach Zustand der Variablen LEDStatus ist die LED ein- oder ausgeschaltet.
  Beim Start des Programms ist sie ausgeschaltet.
  volatile sorgt dafuer, dass Hauptprogramm und Interrupt-Routine
  immer denselben aktuellen Wert sehen.
*/
volatile bool LEDStatus = LOW;

void setup()
{
  pinMode(LED, OUTPUT);

  // Mit INPUT_PULLUP liegt der Taster im Ruhezustand auf HIGH
  // und wird beim Druecken auf LOW gezogen.
  pinMode(TASTER, INPUT_PULLUP);

  /*
    FALLING = der Interrupt wird genau dann ausgeloest,
    wenn der Pegel von HIGH nach LOW wechselt, also beim Druecken.
    Mit CHANGE wuerde er auch beim Loslassen ausloesen und
    der Zustand der LED waere danach wieder derselbe.
  */
  attachInterrupt(digitalPinToInterrupt(TASTER), LEDSchalten, FALLING);
}

void loop()
{
  // LED entsprechend dem gespeicherten Zustand schalten
  digitalWrite(LED, LEDStatus);
}

// Interrupt-Service-Routine: wird beim Tastendruck aufgerufen
void LEDSchalten()
{
  // LEDStatus umdrehen: aus true wird false, aus false wird true
  LEDStatus = !LEDStatus;
}
Rate the instructions

Comments

Ask a question or share an experience

Contact us if something doesn’t work. Please include your board and the error message.

We review every comment before publication. Your email address remains with us.