Gli interruptData di pubblicazione: 17-10-2003 | Versione Italiana | (No English Version) Parole chiave: - PIC - |
Gli interrupt
L'interrupt � una particolare caratteristica dei PICmicro (e dei microprocessori in generale) che consente di intercettare
un evento esterno, interrompere momentaneamente il programma in corso, eseguire una porzione di programma specializzata
per la gestione dell'evento verificatosi e riprendere l'esecuzione del programma principale.
Volendo fare un paragone con il mondo reale possiamo dire che l'interrupt rappresenta per il PIC quello che per noi
rappresenta ad esempio la suoneria del telefono.
Per poter ricevere telefonate non dobbiamo preoccuparci di alzare continuamente la cornetta per vedere se c'� qualcuno
che vuol parlare con noi, ma, grazie alla suoneria, possiamo continuare tranquillamente a fare le nostre faccende in
quanto saremo avvisati d� questa ogni volta che qualcuno ci sta chiamando.
Appena sentiamo lo squillo, possiamo decidere di interrompere momentaneamente le nostre faccende, rispondere al telefono e,
una volta terminata la conversazione, riprendere dal punto in cui avevamo interrotto.
Riportando i termini di questo paragone al PIC abbiamo che:
- le nostre faccende corrispondono al programma in esecuzione;
- la chiamata da parte di qualcuno corrisponde all'evento da gestire;
- lo squillo del telefono corrisponde alla richiesta di interrupt;
- la nostra risposta al telefono corrisponde alla subroutine di gestione dell'interrupt.
E' evidente quanto sia pi� efficiente gestire un evento con un interrupt anzich� controllare ciclicamente
il verificarsi dell'evento con il programma principale. Gran parte degli aspetti legati alla gestione dell'interrupt
vengono inoltre trattati direttamente dall'hardware interno del PIC per cui il tempo di risposta all'evento � praticamente
immediato.
Tipi di evento e bit di abilitazione
Il PIC16F84A � in grado di gestire in interrupt quattro eventi diversi, vediamo quali sono:
- Il cambiamento di stato sulla linea RB0 (External interrupt RB0/INT pin).
- La fine del conteggio del registro TMR0 (TMR0 overflow interrupt).
- Il cambiamento di stato su una delle linee da RB4 ad RB7 (PORTB change interrupts).
- La fine della scrittura su una locazione EEPROM (EEPROM write complete interrupt).
L'interrupt su ognuno di questi eventi pu� essere abilitato o disabilitato indipendentemente dagli altri
agendo sui seguenti bit del registro INTCON:
- INTE (bit 4) se questo bit viene messo a 1 viene abilitato l'interrupt sul cambiamento di stato sulla linea RB0
- T0IE (bit 5) se questo bit viene messo a 1 viene abilitato l'interrupt sulla fine del conteggio del registro TMR0
- RBIE (bit 3) se questo bit viene messo a 1 viene abilitato l'interrupt sul cambiamento di stato su una delle linee da RB4 ad RB7
- EEIE (bit 6) se questo bit viene messo a 1 viene abilitato l'interrupt sulla fine della scrittura su una locazione EEPROM
Esiste inoltre un bit di abilitazione generale degli interrupt che deve essere settato anch'esso ad uno ovvero il bit GIE
(Global Interrupt Enable bit) posto sul bit 7 del registro INTCON.
Interrupt vector ed Interrupt handler
Qualunque sia l'evento abilitato, al suo manifestarsi il PIC interrompe l'esecuzione del programma in corso,
memorizza automaticamente nello STACK il valore corrente del PROGRAM COUNTER e salta all'istruzione presente
nella locazione di memoria 0004H denominata Interrupt vector (vettore di interrupt).
E' da questo punto che dobbiamo inserire la nostra subroutine di gestione dell'interrupt denominata
Interrupt Handler (gestore di interrupt).
Potendo abilitare pi� interrupt, tra i primi compiti dell'interrupt handler � la verifica di quale,
tra gli eventi abilitati, ha generato l'interrupt e l'esecuzione della parte di programma relativo.
Questo controllo pu� essere effettuato utilizzando gli Interrupt flag.
Interrupt flag
Dato che qualunque interrupt genera una chiamata alla locazione 04H, nel registro INTCON sono presenti dei flag che
indicano quale � l'evento che ha generato l'interrupt, vediamoli:
- INTF (bit 1) Se vale 1 l'interrupt � stato generato dal cambiamento di stato sulla linea RB0.
- T0IF (bit 2) Se vale 1 l'interrupt � stato generato al termine del conteggio del timer TMR0.
- RBIF (bit 0) Se vale 1 l'interrupt � stato generato dal cambiamento di stato di una delle linee da RB4 a RB7.
Come si vede per l'interrupt sul fine scrittura in EEPROM non � previsto alcun flag di segnalazione per cui l'interrupt
handler dovr� considerare che l'interrupt � stato generato da questo evento quando tutti e tre i flag sopra citati valgono 0.
Importante: Una volta rilevato quale flag � attivo, l'interrupt handler deve azzerarlo altrimenti non verr� pi� generato
l'interrupt corrispondente.
Ritorno da un interrupt handler
Quando viene generato un interrupt il PIC disabilita automaticamente il bit GIE (Global Interrupt Enable) del registro
INTCON in modo da disabilitare tutti gli interrupt mentre � gi� in esecuzione un interrupt handler. Per poter ritornare
al programma principale e reinizializzare a 1 questo bit occorre utilizzare l'istruzione:
RETFIE
Esempio pratico di gestione di un interrupt
Vediamo ora un esempio pratico di gestione degli interrupt. Prendiamo come base di partenza il source
LED.ASM usato nella lezione 1 per realizzare il lampeggiatore a led. Come ricorderete questo programma
fa semplicemente lampeggiare il LED1 a ciclo continuo utilizzando un ritardo software introdotto dalla
subroutine Delay.
Vediamo ora come � possibile fargli rilevare la pressione di un tasto ed accendere il LED 2 contemporaneamente
all'esecuzione del programma principale.
Il source d'esempio che andremo ad analizzare � disponibile nel file INTRB.ASM
Proviamo a compilarlo ed a eseguirlo utilizzando lo stesso schema elettrico realizzato nella lezione 3
(file example3.pdf in formato Acrobat Reader 12Kb).
Una volta scaricato il programma INTRB.ASM nella scheda PicTech noteremo che il LED 1 lampeggia esattamente
come avveniva con il programma LED.ASM. Proviamo ora a premere uno qualsiasi dei tasti da SW1 a SW4 e
vedremo che il LED 2 si accende immediatamente e rimane acceso per un tempo pari a 3 lampeggi del LED 1.
In pratica mentre il loop principale, derivato dal vecchio LED.ASM, continua a far lampeggiare il LED 1
utilizzando un ritardo software introdotto dalla subroutine Delay, il PIC � in grado di accorgersi della
pressione di un tasto e di segnalarlo immediatamente sul LED 2 senza influenzare in maniera evidente la
frequenza di lampeggio di LED1.
Prima di analizzare il source INTRB.ASM vediamo la differenza di comportamento con un altro source che
effettua le stesse operazioni ma senza ricorrere agli interrupt.
A questo proposito compiliamo ed inseriamo nel PICmicro il programma NOINTRB.ASM. Noteremo che
l'accensione del LED 2, in corrispondenza alla pressione di un tasto, � leggermente ritardata
in quanto la lettura dello stato delle linee RB4-7 non viene effettuata dall'hardware di gestione
dell'interrupt ma direttamente dal programma principale ad ogni ciclo di loop. Il leggero ritardo
� quindi dovuto alla presenza della subroutine Delay all'interno del loop principale.
Analizziamo ora il source INTRB.ASM
Partiamo dalla direttiva ORG 00H che, come sappiamo serve a posizionare il nostro programma a partire
dalla locazione di reset, ovvero dalla locazione con indirizzo 0.
Notiamo subito che la prima istruzione che incontra il PIC � un salto incondizionato alla label Start:
ORG 0x00
goto Start
seguito da un'altra direttiva:
ORG 0x04
e quindi dal codice della subroutine di gestione dell'interrupt:
bsf PORTB,LED2
movlw 3
movwf nTick
bcf INTCON,RBIF
retfie
Come abbiamo detto nella lezione precedente, l'interrupt handler deve necessariamente essere allocato a partire dall'indirizzo
0x04, quindi per evitare che venga eseguito al reset dobbiamo necessariamente saltarlo con una istruzione di salto incondizionato.
Il codice dell'interrupt handler, in questo caso, � molto semplice e si limita ad accendere il LED 2, quindi inserire
nel registro utente nTick il numero di lampeggi raggiunto il quale il LED 2 deve spegnersi e quindi azzerare il flag RBIF
per consentire alla circuiteria di generazione dell'interrupt di continuare a funzionare.
L'istruzione RETFIE consente al PIC di tornare ad eseguire il programma interrotto dall'interrupt.
Ma perch� viene generato un interrupt quando premiamo un tasto qualsiasi ?
Tra le prime istruzioni che esegue il nostro PIC al reset troviamo le seguenti:
movlw 10001000B
movwf INTCON
dove in pratica viene messo ad uno il bit GIE (bit 7) che abilita in generale la circuiteria di generazione degli
interrupt e quindi il bit RBIE (bit 3) che abilita, in particolare, l'interrupt su cambiamento di stato delle linee RB4-7.
In pratica, avendo collegato i pulsanti PU1, PU2, PU3 e PU4 proprio sulle linee di I/O RB4, RB5, RB6 ed RB7, con la
pressione di uno di questi otteniamo un cambiamento di stato e quindi un interrupt.
Nel loop principale, oltre alle operazioni di accensione e spegnimento del LED 1, viene decrementato il
contatore nTick fino al raggiungimento dello zero. In corrispondenza di questo viene spento il LED 2.
Esempio pratico di gestione di pi� interrupt
Vediamo ora come gestire pi� interrupt contemporaneamente.
Utilizzando sempre come base il source precedente INTRB.ASM proviamo a gestire anche l'interrupt sulla fine conteggio del registro
TMR0. Ovvero facciamo lampeggiare il LED 3 in corrispondenza di ogni fine conteggio di TMR0.
Il source da utilizzare � DBLINT.ASM.
Compiliamo e scarichiamo il programma DBLINT.ASM nella scheda PicTech e vediamo che oltre a LED 1 che
lampeggia con la solita frequenza, c'� il LED 3 che lampeggia contemporaneamente con una frequenza pi� elevata.
Premendo un tasto qualsiasi, inoltre, otteniamo la solita accensione per tre cicli del LED 2. L'effetto finale
che otteniamo � l'esecuzione di tre compiti ad una velocit� tale da sembrare in esecuzione parallela.
Analizziamo ora il source DBLINT.ASM
Le modifiche maggiori riguardano l'interrupt handler all'inizio del quale viene effettuato un controllo su
quale evento abbia generato l'interrupt. Con le istruzioni:
btfsc INTCON,T0IF
goto IntT0IF
btfsc INTCON,RBIF
goto IntRBIF
viene controllato il flag T0IF e RBIF per vedere rispettivamente se l'evento che ha scatenato l'interrupt proviene dal
registro TMR0 o dalle porta RB4-RB7. Quindi vengono lanciate in esecuzione le relative subroutine di gestione a partire
dalle label IntT0IF e IntRBIF.
Prima di ridare il controllo al programma principale vengono azzerati i flag T0IF e RBIF assicurarsi che i successivi
eventi possano scaturire nuovamente gli interrupt.
Segnala questo articolo:
Parole chiave: - PIC -
|