Generalità
L'interrupt è un evento che:
interrompe l'esecuzione del programma principale
salva l'indirizzo della prossima istruzione da eseguire nello stack
esegue la routine di interrupt
riprende il programma principale dall'istruzione salvata nello stack e quindi dal punto in cui il programma principale era stato interrotto.
L'evento può essere:
esterno (un fronte di salita su un pin, la ricezione di un carattere dalla periferica seriale, ecc) )
interno (un timer che raggiunge l'overflow, una periferica che termina un'attività...)
La programmazione con interrupt, detta ad eventi presenta diversi pregi:
evita il continuo controllo degli eventi (polling),
semplifica il main. Significativo è il caso limite di un programma che non presenta istruzioni all'interno del ciclo principale!
evita l'impegno della cpu in inutili attività temporalmente lunghe (scrittura su eeprom, attesa di trasmissione caratteri, attesa fine conversioni AD..).
Interrupt per la famiglia PIC16F87x
Rispetto a micro ben più potenti l'architettura di gestione degli interrupt nei pic della famiglia 16F è fin troppo semplice.
Esiste una sola routine per tutti gli interrupt e se è abilitato più di un interrupt è necessario controllare chi ha provocato l'evento.
I PIC16F87x dispongono di 14 interrupt diversi.
Si sottolinea che lo stack conserva solo il valore del registro PC e che all'uscita della routine di interrupt il programma principale può ritrovare valori dei registri completamente diversi! Se questo è un problema bisogna provvedere in qualche modo.
Non è prevista la gestione delle priorità.
Ad ogni interrupt è associato un bit d abilitazione e un bit (flag) di evento non servito dalla routine di interrupt.
Un ulteriore bit abilita o no tutti gli interrupt.
Quindi affinchè l'evento produca effetti è necessario che siano soddisfatte tre condizioni:
il bit GIE, general interrupt enable, del registro INTCON deve essere attivo (1). In tal modo è possibile abilitare o disabilitare con una sola istruzione tutti gli interrupt.
il bit di abilitazione del particolare interrupt deve essere attivo (1)
il bit di flag di evento non servito associato al particolare interrupt deve essere disattivato (0). In tal modo è possibile:
controllare quale int ha provocato l'evento
evitare che un ulteriore evento che si verifica durante l'esecuzione della routine di int, produca effetti.
///////////////////////////////////////////////////////
Gestione di Timer0
TMR0 valore iniziale del contatore
4/fosc durata del ciclo di clock
PR prescaler; divisore della frequenza di clock
PSW postscaler sw da implementare possibilmente nel main, ma anche all'interno della funzione di interrupt se non ci sono esigenze stringenti di precisione. Infatti, poichè durante l'esecuzione della funzione di interrupt il timer è bloccato, è opportuno limitare la durata di tale funzione e quindi il numero di istruzioni.
TMR0, PR e PSW devono essere interi.
Risulta:
T=(256-TMR0)*4/fosc*PR*PSW
TMR0 < 255; conviene piccolo per evitare un continuo ingresso in interrupt
PR compreso tra 1 e 256; conviene elevato per evitare un continuo ingresso in interrupt
Se con TMR0=0 e PR=256 si ottiene un valore maggiore di quello desiderato,
quindi se T< 256*4/fosc*256, non è necessario il postscaler sw.
//////////////////////////////////////////////////////////////////////////////////////////////////////////
ES. Dimensionare per T=10s con fosc=12MHz
Risulta 256*4/fosc*256=21,8453ms
E' necessario il PSW
Pongo PR=256 e TMR0=0; devo ottenere un valore maggiore di 10s; aumentando TMR0 si può scendere ai 10s desiderati.
Pongo 256*4/fosc*256*PSW=10
PSW=10/( 256*4/fosc*256)=457,76 che rappresenta il valore minimo
Pongo 256*4/fosc*256*PSW=11
PSW=11/( 256*4/fosc*256)=503,54
Scelgo PSW=503 e ricavo TMR0
T=(256-TMR0)*4/fosc*PR*PSW
10=(256-TMR0)*4/12MHz*256*503
(256-TMR0)=10*12MHz/4/256/503
TMR0=256-10*12MHz/4/256/503=23,022
E' un buon risultato perchè l'approssimazione con 23 non comporta eccessivi errori.