Eksterne interrupts kan brukes til å reagere på et elektrisk signal som kommer inn på en bestemt pinne på Arduino. Når signalet endrer tilstand (fra høy til lav, eller fra lav til høy), vil et interrupt utløses og ISR vil bli kalt. Du kan velge hvilken pinne du vil bruke for interrupt, og du kan også velge om du vil at interruptet skal utløses når signalet går fra høy til lav, eller omvendt.

Timer interrupts brukes til å utføre en funksjon med jevne mellomrom, for eksempel å måle tid eller å oppdatere en skjerm. Når timeren når et bestemt antall tellinger, vil interruptet utløses og ISR vil bli kalt.

For å bruke interrupts i Arduino, må du først konfigurere pinne eller timer som du vil bruke for interrupt. Deretter kan du definere ISR-funksjonen din og knytte den til riktig interrupt ved å bruke en "attachInterrupt" funksjon. Du kan også deaktivere interrupt ved å bruke "detachInterrupt" funksjonen.

Det er viktig å merke seg at når ISR-funksjonen kjører, vil Arduino ikke kunne utføre andre oppgaver eller interrupts. Derfor bør ISR-funksjonen din være så kort som mulig og ikke bruke for mye tid.

I det første eksempelet tar vi utgangspunkt i Arduino Uno. Her er det bare pinne 2 og 3 som kan brukes til eksterne interrupt. En oversikt over pinner som kan brukes på noen av de forskjellige Arduino-typene kan du finne her: https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ 

 

Eksterne interrupt

Enkelt eksempel:
På Arduino Uno fungerer eksterne interrupt bare på digital pinne 2 og 3.

const int interruptPinne = 2; // Definer hvilken pinne som skal brukes for interrupt
//Alle variabler som kan endres inne i en ISR må deklareres som "volatile"
volatile int interruptTeller = 0; // Variabel for å telle antall ganger interruptet har blitt utløst
void setup() {
pinMode(interruptPinne, INPUT_PULLUP);  // Konfigurer interruptPin som input
attachInterrupt(digitalPinToInterrupt(interruptPinne), knapp1Interrupt, CHANGE);   // Koble interrupt til interruptPin og kall ISR-funksjonen "handleInterrupt"
  Serial.begin(115200);  // Start seriell kommunikasjon med PC
}
void loop() {
Serial.print("Interrupt teller: ");  // Skriv antall ganger interruptet har blitt utløst til seriell monitor
Serial.println(interruptTeller);
  delay(1000);
}
// ISR-funksjonen som blir kalt når interruptet utløses
void knapp1Interrupt() {
interruptTeller++;  // Øk interruptCount med en hver gang interruptet utløses
}

I dette eksemplet vil interruptet utløses hver gang signalet på interruptPin endrer tilstand (fra høy til lav eller omvendt). Når interruptet utløses, vil ISR-funksjonen "handleInterrupt" bli kalt, og interruptCount vil øke med en. I loop-funksjonen vil antall ganger interruptet har blitt utløst skrives til seriell monitor hvert sekund.

Merk at "volatile" nøkkelordet brukes i deklarasjonen av interruptCount-variabelen. Dette forteller Arduino at interruptCount kan endre seg utenfor hovedprogrammet, i ISR-funksjonen. Uten dette nøkkelordet kan det oppstå uforutsigbare feil når interruptCount endres i ISR-funksjonen.

Som du ser når du kjører koden (med en knapp tilkoblet pinne 2), er det en del å ta tak i. Se oppgave 1 under "Oppgaver"-fliken.

Oppgaver:

Oppgave 1:  
Skriv om eksempelet i den første fliken, slik at telleren økes bare med 1 hver gang knappen trykkes.

Oppgave 2:
Legg til en knapp til. Bruk denne til å telle ned når knappen trykkes.

Løsningsforslag:

Oppgave 1:  
Skriv om eksempelet i den første fliken, slik at telleren økes bare med 1 hver gang knappen trykkes.

Så lenge vi er inne i ISR'en, vil ikke funksjoner som delay() og millis() fungere, dvs. verdiene blir ikke oppdatert. Vi kan likevel kalle millis() i starten for å registere når knappen er trykt inn. Denne verdien har jeg lagret i variabelen "sisteTrykk" i løsningsforslaget. Neste gang ISR'en kjøres sammenlignes denne med

const int interruptPinne = 2;  // Definer hvilken pinne som skal brukes for interrupt
//Alle variabler som kan endres inne i en ISR må deklareres som "volatile"
volatile int interruptTeller = 0;  // Variabel for å telle antall ganger interruptet har blitt utløst
volatile long sisteTrykk = 0;
void setup() {
  pinMode(interruptPinne, INPUT_PULLUP);                                             // Konfigurer interruptPin som input
  attachInterrupt(digitalPinToInterrupt(interruptPinne), knapp1Interrupt, FALLING);  // Koble interrupt til interruptPin og kall ISR-funksjonen "handleInterrupt"
  Serial.begin(115200);                                                              // Start seriell kommunikasjon med PC
}

void loop() {
  Serial.print("Interrupt teller: ");  // Skriv antall ganger interruptet har blitt utløst til seriell monitor
  Serial.println(interruptTeller);
  delay(1000);
}

// ISR-funksjonen som blir kalt når interruptet utløses
void knapp1Interrupt() {
  long naa = millis();
  if (naa > sisteTrykk + 200) { //Sjekker om det har gått 200 millisekunder siden siste trykk
  sisteTrykk = naa;  //Lagrer tiden første gang ISR'en kjøres etter knappe-trykk
  interruptTeller++; // Øk interruptCount med en hver gang interruptet utløses } }

Oppgave 2:

const int knapp1 = 2;  // Definer hvilken pinne som skal brukes for interrupt
const int knapp2 = 3;  // Definer hvilken pinne som skal brukes for interrupt
//Alle variabler som kan endres inne i en ISR må deklareres som "volatile"
volatile int interruptTeller = 0;  // Variabel for å telle antall ganger interruptet har blitt utløst
volatile long sisteTrykkKnapp1 = 0;
volatile long sisteTrykkKnapp2 = 0;

void setup() {
  pinMode(knapp1, INPUT_PULLUP);                                             // Konfigurer interruptPin som input
  pinMode(knapp2, INPUT_PULLUP);                                             // Konfigurer interruptPin som input
  attachInterrupt(digitalPinToInterrupt(knapp1), knapp1Interrupt, FALLING);  // Koble interrupt til interruptPin og kall ISR-funksjonen "handleInterrupt"
  attachInterrupt(digitalPinToInterrupt(knapp2), knapp2Interrupt, FALLING);  // Koble interrupt til interruptPin og kall ISR-funksjonen "handleInterrupt"
  Serial.begin(115200);                                                              // Start seriell kommunikasjon med PC
}

void loop() {
  Serial.print("Interrupt teller: ");  // Skriv antall ganger interruptet har blitt utløst til seriell monitor
  Serial.println(interruptTeller);
  delay(1000);
}

// ISR-funksjonen som blir kalt når interruptet utløses
void knapp1Interrupt() {
  long naa = millis();
  if (naa > sisteTrykkKnapp1 + 200) { //Sjekker om det har gått 200 millisekunder siden siste trykk
    sisteTrykkKnapp1 = naa;  //Lagrer tiden første gang ISR'en kjøres etter knappe-trykk
    interruptTeller++;  // Øk interruptCount med en hver gang interruptet utløses
  }
}
void knapp2Interrupt() {
  long naa = millis();
  if (naa > sisteTrykkKnapp2 + 200) { //Sjekker om det har gått 200 millisekunder siden siste trykk
    sisteTrykkKnapp2 = naa;  //Lagrer tiden første gang ISR'en kjøres etter knappe-trykk
    interruptTeller--;  // Øk interruptCount med en hver gang interruptet utløses
  }
}