Standardmäßig stellt der Arduino UNO mit der Funktion „attachInterrupt()“ nur 2 Interrupt-Pins (Pin 2 und 3) zu Verfügung. Durch entsprechende Registerprogrammierung kann jedoch durch jeden 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 pro Port programmiert wurde, welcher Pin einen Interrupt ausgelöst hat, muss in der „Interrupt-Serviceroutine“ erfolgen.
Verwendete Register:
PCICR = Pin Change Interrupt Register
PCMSKx = Pin Change Mask Register x (0 / 1 / 2)
SREG = Statusregister
Vorgehensweise:
1. Alle Interrupts sperren
2. Port für Interrupt freischalten
3. Pin(s) für Pin Change Interrupt freigeben
4. Alle Interrupts freigeben
5. Interrupt-Serviceroutine
1. Alle Interrupts sperren
Während der Manipulation der Interruptregister sollte kein Interrupt ausgelöst werden. Durch löschen des Global Interrupt Enable Bits (I) im Status Register (SREG) werden alle Interrupts gesperrt
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
I | T | H | S | V | N | Z | C | |
SREG – Status Register |
// Löschen des Global Interrupt Enable Bits (I) im Status Register (SREG) cli(); // alle Interrupts sperren // Setzen des Global Interrupt Enable Bits (I) im Status Register (SREG) // sei(); // alle Interrupts zulassen // oder SREG |= 0x80; // alle Interrupts zulassen
2. Port für Interrupt freischalten
Im Pin Change Interrupt Control Register (PCICR) wird festgelegt welcher Ports für einen Pin Change Interrupt zugelassen werden. Den Ports sind bestimmte Pins zugeordnet.
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PCICR | PCIE2 | PCIE1 | PCIE0 | |||||
Pin | D0 – D7 | A0 – A5 | D8 – D13 | |||||
Port | D | C | B | |||||
PCICR – Pin Change Interrupt Control Register |
In Abhängigkeit für welche Pins ein Interrupt ausgelöst werden soll, ist das entsprechende Pin Change Interrupt Enable Bit (PCIEx) zu setzen.
// Setzen des PCIE2-Bit im Pin Change Interrupt Control Register (PCICR) PCICR |= (1 << PCIE2); // Zurücksetzen / löschen des PCIE2-Bit im Pin Change Interrupt Control Register (PCICR) // Abfragen
3. Pin(s) für Pin Change Interrupt freigeben
Durch setzen des Pin Change Enable Mask Bit (PCINTx) im entsprechenden Pin Change Enable Mask Register (PCMSKx) wird die Auslösung eines Interrupt ermöglicht.
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PCMSK0 | PCINT7 | PCINT6 | PCINT5 | PCINT4 | PCINT3 | PCINT2 | PCINT1 | PCINT0 |
PIN | D13 | D12 | D11 | D10 | D9 | D8 | ||
Port B | ||||||||
PCMSK0 – Pin Change Mask Register 0 |
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PCMSK1 | PCINT14 | PCINT13 | PCINT12 | PCINT11 | PCINT10 | PCINT9 | PCINT8 | |
PIN | A5 | A4 | A3 | A2 | A1 | A0 | ||
Port C | ||||||||
PCMSK1 – Pin Change Mask Register 1 |
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PCMSK2 | PCINT23 | PCINT22 | PCINT21 | PCINT20 | PCINT19 | PCINT18 | PCINT17 | PCINT16 |
PIN | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
Port D | ||||||||
PCMSK2 – Pin Change Mask Register 2 |
//Setzen des Pin Change Enable Mask Bit 18 (PCINT18) ==> Digital-Pin D2 PCMSK2 |= (1 << PCINT18); // Zurücksetzen / löschen // Abfragen
4. Alle Interrupts freigeben
Durch setzen des Global Interrupt Enable Bits (I) im Status Register (SREG) werden alle Interrupts freigegeben. Siehe 1. Alle Interrupts sperren.
5. Interrupt Serviceroutine
Wird ein Pin Change Interrupt ausgelöst, verzweigt das Programm in die entsprechende Serviceroutine. Die Namen der Interrupt-Serviceroutinen sind vom System fest vorgegeben und können nicht ohne weiteres verändert werden.
Pin Change Interrupt PCMSK0 -> Serviceroutine ISR(PCINT0_vect)
Pin Change Interrupt PCMSK1 -> Serviceroutine ISR(PCINT1_vect)
Pin Change Interrupt PCMSK2 -> Serviceroutine ISR(PCINT2_vect)
ISR = Interrupt Service Routine
Beispeilcode
Als Beispiel soll der Pin Change Interrupt am Digital-Pin D2 ausgelöst werden:
void setup(){ //Löschen des Global Interrupt Enable Bits (I) im Status Register (SREG) cli(); //Setzen des PCIE2-Bit im Pin Change Interrupt Control Register (PCICR) PCICR |= (1 << PCIE2); //Setzen des Pin Change Enable Mask Bit 18 (PCINT18) ==> Digital-Pin 2 PCMSK2 |= (1 << PCINT18); //Setzen des Global Interrupt Enable Bits (I) im Status Register (SREG) SREG |= 0x80; // gleichwertig mit "sei();" } ... //Aufruf der Interrupt Serviceroutine ISR(PCINT2_vect){ //Programmcode der Service-Routine }
Quellen:
arduino-projekte.webnode.at
ATmega328/P Datenblatt