Gli interrupt sono dei segnali asincroni (letteralmente interruzioni) che rappresentano una “richiesta di attenzione” da parte di una periferica. Esistono diversi tipi di interrupt, e diversi modi di gestione, ma in generale alla richiesta di interruzione il processore interrompe il flusso di programma per eseguire una specifica routine di interruzione (routine che può variare per le diverse interruzioni). Alla conclusione della routine il flusso del programma riprende. Il processo che  porta all’interruzione del flusso di programma è piuttosto complesso (dovendo gestire valori dei registri, stack pointer, stato della macchina ecc…) e diciamo trasparente al programmatore.

Sull’arduino possiamo usare gli interrupt per svolgere una certa routine in background. Essi si dividono in interrupt interni ed interrupt esterni. Dei primi non ce ne occupiamo in quanto necessitano di una conoscenza dell’ATMega328 molto approfondita. Mentre gli interrupt esterni sono quelli che useremo. Nella maggior parte delle board i pin utilizzabili come interrupt sono due, il pin 2 e 3. Vediamo come usarli.

I comandi a nostra disposizione per la gestione degli interrupt sono 2:

  • attachInterrupt(interrupt, function, mode)
  • detachInterrupt(interrupt)

Il primo serve per impostare un’interrupt, il secondo per toglierlo. Vediamone insieme la sintassi.

volatile int Stato = LOW;
void setup() {
pinMode(13, OUTPUT);
attachInterrupt(0, Cambia, FALLING);
}
void loop() {
digitalWrite(13, Stato);
}
void Cambia() {
Stato = !Stato;
}
xxx interrupt
Download

con questo sketch ed il cablaggio indicato siamo in grado di far accendere il LED premendo il pulsante. Notiamo che ci si riferisce al pin2 come interrupt 0 ed al pin3 come interrupt 1.

Mentre usando il comando detachInterrupt() disattiviamo l’interrupt.

Function indica quale funzione viene chiamata al verificarsi dell’interrupt.

Mode invece indica con quale modalità acquisire l’interrupt. Le possibili modalità sono:

  • LOW attiva l’interrupt ogni volta che il pin è al valore logico basso;
  • CHANGE attiva l’interrupt quando il pin cambia stato;
  • RISING attiva l’interrupt quando il pin passa da LOW a HIGH;
  • FALLING attiva l’interrupt quando il pin passa da HIGH a LOW;

Nota: Abbiamo usato il qualificatore volatile. Tutte le variabili che modifichiamo all’interno della funzione “attaccata” all’interrupt devono essere dichiarate con questo attributo. Questo serve a memorizzare il valore della variabile nella RAM e non nei registri dell’ATMega328: durante l’esecuzione di un interrupt il valore dei registri viene modificato, ed i dati ivi memorizzati possono andare persi.

Precisazioni (grazie a Marco):

Dai commenti ricevuti ci siamo resi conto che manca una nota importante,.

All’interno della funzione chiamata dall’ interrupt attach() non funzionano tutti quei comandi che hanno a che fare  con le temporizzazioni, in particolare i delay() e i millis() non funzionano correttamente: il primo non garantisce il ritardo indicato, il secondo non viene incrementato (ritorna sempre lo stesso valore).  Inoltre le comunicazioni seriali ricevute nel periodo in cui stiamo eseguendo l’interrupt verranno scartate.