Lo scopo di questo esercizio, è di capire come gestire gli Interrupts.
In questo esempio utilizzerò tre Interrupts disponibili per il chip ATMEGA328, per valutarne il comportamento.
Per richiamare gli Interrupts, utilizzo alcuni pulsanti, collegati ai Pins del microcontrollore di Arduino, precisamente:
Ogni qualvolta che premo un pulsante, il programma principale è interrotto per eseguire la Macro associata all’Interrupt, completato il ciclo della Macro il programma riprende dal punto in cui è stato interrotto.
Le Macro associate a ciascun Interrupt, hanno lo scopo di verificare se quando il pulsante è premuto, il programma principale si ferma per eseguire il sottoprogramma associato all’Interrupt.
Una curiosità
Utilizzando interrupts IOC su porte diverse, il funzionamento è corretto.
Se collego altri pulsanti alla medesima porta, utilizzando lo “Interrupts IOC”, anziché richiamare la Macro associata a ciascun pulsante, il sistema esegue solo la Macro associata all’ultimo pulsante della stessa porta.
Non so se questo comportamento è contemplato nelle specifiche di fabbrica, oppure è un errore di sistema; anche con i PIC, ottengo il medesimo errore.
In pratica, l’utilizzo dello “interrupt IOC”, funziona solo, se collego un solo interrupt su porte diverse, la mia ricerca riguardo all’utilizzo di questo tipo di Interrupts multipli sulla medesima porta, fa riferimento al supporto della gestione del GPIO del microcontrollore.
Timer Register
Arduino, contiene al suo interno un orologio che può essere utilizzato per misurare gli eventi correlati con il tempo.
Questi Timer o contatori, possono essere pianificati in modo da ottenere la base per il tempo necessario per lo svolgimento del programma, che necessita un’esecuzione precisa, come la realizzazione di un orologio o un conta tempo.
Questi Timer, possono essere configurati mediante un pre-scaler, per ottenere una precisa frequenza di riferimento.
Il chip ATMEGA328, ha 3 contatori al suo interno che dipendono dalla frequenza di clock di Arduino, generalmente 16 MHz.
Ogni impulso di clock incrementa questi contatori.
In Arduino, i contatori sono configurati alla frequenza di 1 KHz, tramite registri speciali, e sono normalmente abilitati.
TRM0, ha un registro a 8 bit, può contenere 256 impulsi prima di generare il segnale di overflow; è utilizzato con la funzione Ritardo (Delay) per la gestione millisecondi e microsecondi, pertanto, se si utilizza TRM0 come base dei tempi, questa è influenzata dalla esecuzione del programma.
Dopo aver generato il segnale di overflow, il conteggio nei registri riparte da zero.
Con la frequenza di 16.000.000 MHz, la velocità massima d’incremento del contatore del Timer è di 1/16.000.000 al secondo, che corrisponde a circa 63 nanosecondi, in questo modo, il contatore impiegherà 10/16.000.000 = 0,0000006 secondi per raggiungere il valore 9 (i Timers sono indicizzati a 0) e 100/16.000.000 = 0,00000063 secondi per raggiungere il valore 99.
In alcune situazioni, questa velocità di riempimento dei contatori, è troppo elevata, ed è necessario rallentarla.
Il “Timer Match Register”, è il comparatore che genera l’overflow, quando il contatore del timer è pieno:
con TRM0, 256/16.000.000 secondi (circa 16 microsecondi) per riempire gli 8 bit del contatore associato a TRM0 .
con TRM1, 65.536/16.000.000 secondi (circa 4 microsecondi) per riempire il contatore associato a TRM1.
Questi valori non sono utili se si vuole interrompere il programma 1 volta al secondo.
È possibile controllare questa velocità, utilizzando il “prescaler”, che determina la velocità secondo la formula:
(velocità del timer(Hz)) = (frequenza di clock di Arduino (16MHz))/ prescaler
Pertanto:
È possibile calcolare la frequenza di interrupt con la seguente equazione:
Frequenza di interrupt(HZ)= Clock di Arduino (16MHz) / (prescaler* (Compare Match Register + 1)
Più 1, perché è indicizzato a zero.
Ricavando Compare Match Register dall’equazione:
Compare Match Register = [16MHz/(prescaler * frequenza desiderata)] -1
Quindi, se si vuole ottenere un segnale di interrupt di 1 Hz, da utilizzare per il progetto del nostro orologio,
Utilizzeremo il TRM1 (registro a 16bit) che può contenere 65.536 conteggi.
65.536 = [16000000/(prescaler * 1)]-1
65.536 = 16000000 /1024*1]-1 = 15.625
Ciò significa che il programma principale sarà interrotto 15.625 volte il secondo.
Configurazione e selezione della frequenza del Timer
È possibile selezionare frequenza diverse dell’oscillatore, per ciascun timer.
Calcolare la frequenza necessaria per avere due chiamte di Interrupt, ogni secondo, utilizzando TRM1.
Dividere la frequenza di 16.000.000 utilizzando il prescaler (16.000.000/256 =62.500).
Dividere il risultato per la frequenza che si vuole ottenere (62.500/2 Hz = 31.250).
Verificare se il valore ottenuto può essere contenuto nel registro del contatore; 31.250 è minore di 65.536 che è il valore massimo che TRM1 può contenere.
Pertanto, 31.250, sarà la frequenza necessaria per richiamare la Macro di Interrupt, 2 volte al secondo.
Riccardo Monti