Interaction Design WikiElectrical Engineering

Interrupt Service Routine

Unter einer Interrupt Service Routine (ISR) versteht man eine Unterbrechung der Hauptroutine um ein zeitkritisches Programmstück auszuführen. Beim Arduino bedeutet dies, dass der loop() für eine wichtigere Funktion unterbrochen werden kann. Diese Unterbrechung wird in der Regel von einem digitalen Input ausgelöst. Interessant ist die Verwendung von einer ISR beispielsweise bei der Messung einer Drehzahl oder auch zum Auslesen von Rotationsencodern – also immer dann, wenn Eingaben sehr schnell verarbeitet werden müssen.

Wir verwenden  die Funktion attachInterrupt(INTERRUPT, ISR, MODE) im setup() um an einem PIN auf ein schnelles Event zu "horchen". Beim Arduino UNO haben wir zwei Interrupt Pins (D2 = INTERRUPT 0, D3 = INTERRUPT 1) zur Verfügung, beim Arduino YUN sind es fünf Interrupt Pins (D3 = INTERRUPT 0, D2 = INTERRUPT 1, D0 = INTERRUPT 2, D1 = INTERRUPT 3, D7 = INTERRUPT 4), wobei nur INTERRUPT 0, INTERRUPT 1 und INTERRUPT 2 genutzt werden können. Der Parameter ISR bezeichnet die Funktion, welche beim Auslösen des Interrupts aufgerufen werden soll. In der Regel erledigen wir in dieser Funktion nur einfache Routinen. Es wird beispielsweise nicht empfohlen die serielle Schnittstelle zu verwenden, da das senden von Daten zu lange benötigt. Ebenfalls verwenden wir innerhalb der ISR sogenannte volatile Variablen. Diese Variablen sind als volatil gekennzeichnet, da sie jederzeit geändert werden können. Der Mode schliesslich gibt an, wann die ISR ausgeführt werden soll. Es gibt drei Modi: RISING, FALLING oder CHANGE. RISING bedeutet, dass der Interrupt von LOW auf HIGH gesetzt wird. FALLING bedeutet, dass der Interrupt von HIGH auf LOW gesetzt wird und CHANGE wird bei beiden Events ausgeführt.

Rotationsencoder 

Im Folgenden ein Beispiel, bei dem ein Rotationsencoder mit dem Arduino ausgelesen wird. Wir verwenden den EC12 von ALPS (Datenblatt). 

 

Beispiel Interrupt  Expand source
#define ENCODER_A 2
#define ENCODER_B 4
volatile int encoderValue = 0;
volatile int oldEncoderReading = 0;
int oldEncoderValue = 0;
void setup()
{
  Serial.begin(9600);
  pinMode(ENCODER_A, INPUT_PULLUP);
  pinMode(ENCODER_B, INPUT_PULLUP);
  attachInterrupt(0, readEncoder, CHANGE);
}
void loop()
{
  if (encoderValue != oldEncoderValue)
  {
    Serial.print("ENCODER: ");
    Serial.println (encoderValue, DEC);
    oldEncoderValue = encoderValue;
  }
}

void readEncoder()
{
  int currReading = digitalRead(ENCODER_A);
  if (oldEncoderReading == LOW && currReading == HIGH)
  {
    if (digitalRead(ENCODER_B) == LOW)
    {
      encoderValue++;
    }
    else
    {
      encoderValue--;
    }
  }
  oldEncoderReading = currReading;
  delayMicroseconds(500);
}

 

Weitere Informationen:

attachInterrupt() - auf Arduino.cc

Interrupts - von Nick Gammon