Externe Interrupts beim Atmel AVR

URL: ../..dic/hardwarenahe_programmierung/avr_externer_interrupt.html

Externe Interrupts beim Atmel AVR

Diese Seite beschreibt die externen Interrupts des ATMega16severity symbol

Prinzipiell lässt sich diese Information auch auf andere Mikrocontroller der AVR Serie übertragen, es empfiehlt sich aber die Informationen mit dem entsprechenden Datenblatt zu vergleichen!

Informationen im Datenblattseverity symbol

Die Informationen dieser Seite entstammen dem originalen Datenblatt (Rev. 2466T–AVR–07/10) des ATMega16 von Atmel.

  • Seite 68-70 : Externe Interrupts

Allgemeines link symbol

Der ATMega16 hat drei Pins, die einen externen Interrupt auslösen können. Extern bedeuted in diesem Fall, dass die eigentliche Interruptquelle nicht innerhalb des Mikrocontrollers ist, sondern eben extern.

Pinbelegung link symbol

Die drei Pins sind in der folgenden Pinbelegung markiert.

Externe Interrup Pins beim AVR
Externe Interrup Pins beim AVR (Quelle: Datenblatt ATMega16, Lizenz © Atmel Corporation)
  • INT0 - PORT D - Bit 2
  • INT1 - PORT D - Bit 3
  • INT2 - PORT B - Bit 2 (zusätzliche Mehrfachbelegung mit dem analogen Komperator)

Bei entsprechender Konfiguration kann ein Interrupt ausgelöst werden, wenn sich der Pegel am entsprechenden Pin ändert.

Register zur Konfiguration link symbol

MCUCR link symbol

Der Grund für das Auslösen eines Interrupts bei den beiden externen Interrupts INT0 und INT1 wird über das Register MCUCR (MCU Control Register) gesteuert.

Bit 7 6 5 4 3 2 1 0
Name SM2 SE SM1 SM0 ISC11 ISC10 ISC01 ISC00
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
Init 0 0 0 0 0 0 0 0

Dazu haben wir vier verschiedene Konfigurationsmöglichkeiten für INT0 und INT1:

ISCx1 ISCx0 Beschreibung
0 0 Löst bei logisch 0 Pegel aus
0 1 Löst bei deiner Pegeländerung aus (steigende oder fallende Flanke)
1 0 Löst bei fallende Flanke (Pegeländerung von logisch '1' auf '0')
1 1 Löst bei steigender Flanke (Pegeländerung von logisch '0' auf '1')

MCUCSR link symbol

Der externe Interrupt für INT2 wird über das Register MCUCSR (MCU Control and Status Register) gesteuert.

Bit 7 6 5 4 3 2 1 0
Name JTD ICS2 - JTRF WDRF BORF EXTRF PORF
Read/Write R/W R/W R R/W R/W R/W R/W R/W
Init 0 0 0 - - - - -

Ist ISC2 auf logisch 0 wird der Interrupt bei einer fallenden Flanke ausgelöst. Bei logisch 1 wird entsprechend bei einer steigenden Flanke ausgelöst.

GICR link symbol

Die Freigabe der Interrupts erfolgt über das Register GICR (General Interrupt Control Register).

Bit 7 6 5 4 3 2 1 0
Name INT1 INT0 INT2 - - - IVSEL IVCE
Read/Write R/W R/W R/W R R R R/W R/W
Init 0 0 0 0 0 0 0 0

Die Bits INT0, INT1 und INT2 aktivieren die Interruptfreigabe.

Für den Aufruf der entsprechenden Interruptrountine sind nun folgende Punkte notwendig:

  • Das entsprechende Bit bei GICR ist gesetzt, damit der Interrupt freigegeben ist
  • Über sei() wurde die globale Interruptfreigabe aktiviert (siehe Interrupts im Skriptum)
  • Eine Pegeländerung entsprechend der Konfiguration unter MCUCR bzw. MCUCSR tritt beim entsprechenden Pin auf

GIFR link symbol

Über dieses Register kann das Statusflag beim entsprechenden Interrupt abgefragt werden. Dies ist notwendig, wenn die Detektion einer Pegeländerung genutzt werden soll, aber keine Interrupt Service Routine aufgerufen werden soll.

Bit 7 6 5 4 3 2 1 0
Name INTF1 INTF0 INTF2 - - - - -
Read/Write R/W R/W R/W R R R R R
Init 0 0 0 0 0 0 0 0

Tritt die konfigurierte Pegeländerung auf wird das entsprechende INTFx Flag gesetzt. Zurückgesetzt wird das Flag, indem entwededer die Interrupt Service Routine aufgerufen wurde oder indem man eine logische 1 an das entsprechende Bit schreibt.

Beispiel link symbol

In diesem Beispiel wird folgendes konfiguriert:

  • INT0 reagiert auf eine fallende Flanke und nutzt die entsprechende Interrupt Service Routine
  • INT1 reagiert auf jeden Pegelwechsel und fragt den Zustand per Polling über das GIFR Register ab
  • INT2 wird nicht genutzt

Umsetzung:

#include <avr/interrupt.h>

ISR(INT0_vect) {
  // Interrupt Service Routine für INT0
  // ...
}

int main(void) {
  MCUCR=0x06; // entspricht 0b0000 01 10 -> INT0 löst bei fallender Flanke aus, INT1 bei jedem Pegelwechsel
  MCUCSR=0x00; // entspricht 0b0 0 000000 -> INT2 löst bei fallender Flanke aus (wird aber nicht genutzt)
  GICR=0x40; entspricht 0b010 00000 -> INT0 Interrupt ist freigegeben, INT1 und INT2 nicht

  sei(); // globale Interruptfreigabe

  while(1) {
    // Hauptschleife

    if (GIFR&0x80) { // überprüfe Zustand von INT1
      GIFR|=0x80; // setze Flag für INT1 zurück
      // ...
    }

    // ...
  }

  return 0;
}