Pin Change Interrupt beim Attiny45/85

Standardmäßig stellt Attiny mit der Funktion "attachInterrupt()" beim Attiny45/85 nur einen Interrupt-Pin (Pin PB2) zu Verfügung. Durch entsprechende Registerprogrammierung kann aber bei jedem Ein-/Ausgangspin ein "Pin Change Interrupt" ausgelöst werden.

Wie der Name "Pin Change Interrupt" bereits sagt, wird bei jeder Zustandsänderung eines Eingangssignals, also sowohl bei steigender, als auch bei fallender Flanke ein Interrupt ausgelöst. Die Auswertung, welche Flanke den Interrupt ausgelöst hat, bzw. falls mehr als ein Pin Change Interrupt programmiert wurde, welcher Pin einen Interrupt ausgelöst hat, muss in der "Interrupt-Serviceroutine" erfolgen.


Verwendete Register:

  • Status Register: SREG
  • General Interrupt Mask Register: GIMSK 
  • Pin Change Mask Register: PCMSK


Vorgangsweise:

  1. Alle Interrupts sperren
  2. Pin Change Interrupts zulassen
  3. Pin(s) für Pin Change Interrupt freigeben
  4. Alle Interrupts freigeben
  5. Interrupt-Serviceroutine erstellen


1. Alle Interrupts sperren

  • Durch Löschen des Global Interrupt Enable Bit (I) im Status Register (SREG) werden alle Interrupts gesperrt. Während der Manipulation der Interrupt-Register soll kein Interrupt ausgelöst werden können.


  • 2. Pin Change Interrupts zulassen

    Im General Interrupt Mask (GIMSK) wird mit dem Pin Change Interrupt Enable Bit (PCIE) festgelegt, dass Pin Change Interrupts zugelassen werden.


    3. Pin(s) für Pin Change Interrupt freigeben

    Durch Setzen des Pin Change Enable Mask Bit (PCINTx) im Pin Change Enable Mask Register (PCMSK) wird die Auslösung eines Pin Change Interrupt ermöglicht. Nachfolgende Aufstellung zeigt die Zuordnung der Pin Change Enable Mask Bits (PCINTx) zu den Pins PB0 bis PB5.


    4. Alle Interrupts freigeben

    Durch Setzen des Global Interrupt Enable Bits (I) im Status Register (SREG) werden alle Interrupts freigegeben.


    5. Erstellen der Interrupt-Serviceroutine

    Wird ein Pin Change Interrupt ausgelöst, verzweigt das Programm in eine zu erstellende Serviceroutine ISR(PCINT0_vect).

    Die Namen der Interrupt-Serviceroutine ist vom System fix vorgegeben und darf nicht verändert werden!

    In der aufgerufenen Serviceroutine können nun z.B. folgende Maßnahmen gesetzt werden:

    • Überprüfen, ob der Interrupt nicht wiederholt durch "Prellen" ausgelöst worden ist (bounce-time).
    • Feststellen, welcher Pin einen Interrupt ausgelöst hat, für den Fall, dass mehr als ein Pin für Pin Change Interrupt freigegeben wurde.
    • Extrahieren des interruptauslösenden Bits aus dem Port zur Ermittlung, ob der Interrupt durch eine steigende oder fallende Flanke ausgelöst wurde.
    • Setzen von Merker in Abhängigkeit der Interruptauslösung durch steigende oder fallende Flanke, auf die dann im Hauptprogramm entsprechend reagiert werden kann.


    Die einzelnen Schritte im Programm zusammengefasst:

    Als Beispiel soll der Pin Change Interrupt am Pin PB2 ausgelöst werden:

    void setup()

    {

      //Löschen des Global Interrupt Enable Bits (I) im Status Register (SREG)

      SREG &= 0x7F; //gleichwertig mit "cli();"


      //Setze des Pin Change Interrupt Enable Bit

      GIMSK |= (1 << PCIE);


      //Setzen des Pin Change Enable Mask Bit 2 (PCINT2)  ==> Pin PB2

      PCMSK |= (1 << PCINT2);


       //Setzen des Global Interrupt Enable Bits (I) im Status Register (SREG)
      SREG |= 0x80; // gleichwertig mit "sei();"

    }


    //Aufruf der Interrupt Serviceroutine

    ISR(PCINT0_vect)

    {

      //Programmcode der Service-Routine

    }


    Beispiel:

    Ein Anwendungsbeispiel ist z.B. in meinem Projekt "Servosteuerung" im Abschnitt Modellbahnschranke ersichtlich.