|
|
Box |
Uso dell'interrupt
(parte 2)
Sommario
|
|
|
Per le informazioni riferite a questo argomento e per compilare i programmi è stata usata la vers. 7.0.0.2 di mikroBasic.
Altre versioni del compilatore potrebbero avere comportamenti diversi o non funzionare. |
Interrupt nel PIC16F628A
Alcune caratteristiche dei PIC16F628A (PIC16F627A, PIC16F648A).
16F... |
Pin |
Flash |
RAM |
Eeprom |
I/O |
Timer |
Clock
interno |
CCP |
ADC |
Comp |
Usart |
LVP |
Costo |
627A |
18 |
1k |
224 |
128 |
16 |
3 |
48kHz
4MHz |
1 |
- |
2 |
Usart |
Si |
€1,80 |
628A |
18 |
2k |
224 |
128 |
16 |
3 |
48kHz
4MHz |
1 |
- |
2 |
Usart |
Si |
€2,04 |
648A |
18 |
4k |
256 |
256 |
16 |
3 |
48kHz
4MHz |
1 |
- |
2 |
Usart |
Si |
€2,31 |
Vediamo gli interrupt che possono essere gestiti dal PIC16F628A (PIC16F627A, PIC16F648A).
Sorgente di Interrupt
(16F628A) |
Registri coinvolti |
Bit di Enable (abilitaz.) |
Bit di Flag (segnalaz.) |
Note |
Cambio stato ingressi PORTB.4, PORTB.5, PORTB.6, PORTB.7 |
INTCON |
RBIE |
RBIF |
|
Cambio stato ingresso PORTB.0 |
INTCON, OPTION_REG |
INTE |
INTF |
Possibilità di scegliere fronte di salita o discesa |
Overflow TMR0 (Timer zero) |
INTCON |
T0IE |
T0IF |
|
Overflow TMR1 (Timer 1) |
PIE1, PIR1 |
TMR1IE |
TMR1IF |
|
TMR2 uguale a PR2 (Timer 2) |
PIE1, PIR1 |
TMR2IE |
TMR2IF |
|
Capture/Compare CCP1 interrupt |
PIE1, PIR1 |
CCP1IE |
CCP1IF |
|
Trasmissione USART |
PIE1, PIR1 |
TXIE |
TXIF |
|
Ricezione USART |
PIE1, PIR1 |
RCIE |
RCIF |
|
Cambio stato Comparatori |
PIE1, PIR1 |
CMIE |
CMIF |
|
Scrittura EEPROM completata |
PIE1, PIR1 |
EEIE |
EEIF |
|
Il PIC16F628A contiene moduli di periferica, quindi sono presenti, oltre al registro INTCON, anche i registri PIE1 e PIR1, che permettono la gestione degli interrupt tramite l'impostazione di alcuni bit specifici.
|
Confrontando il registro INTCON con quello del PIC16F84A, notiamo che il bit 6 ha un'altro nome: PEIE.
Il bit PEIE abilita, se messo a 1, tutte le interruzioni abilitate (non mascherate), dei moduli di periferica.
Se messo a 0, invece, blocca tutte le interruzioni generate dai moduli di periferica.
Dopo un reset o quando viene data alimentazione al circuito, questo bit viene messo a 0.
Il bit GIE ha sempre la funzione di bloccare o sbloccare tutte le interruzioni.
Gli altri bit del registro INTCON hanno le stesse funzioni come viste nel 16F84A. |
Il bit EEIE, che abilita l'interruzione su fine scrittura EEprom, che, nel 16F84A, si trovava nel registro INTCON, è stato spostato nel registro PIE1.
Il registro Peripheral Interrupt Enable (PIE1), contiene i bit di abilitazione individuali per gli interrupt dei moduli di periferica.
Se un bit viene messo a 1, verrà abilitato l'interrupt del modulo di periferica associato a quel bit.
Se messo a 0, verrà disabilitato (si dice, anche, mascherato), l'interrupt per quella periferica.
Dopo un reset o quando viene data alimentazione al circuito, tutti i bit sono messi a 0.
Il registro Peripheral Interrupt Flag (PIR1), contiene i bit di flag individuali per gli interrupt dei moduli di periferica. Il bit di flag d'interrupt di una periferica viene messo a 1 quando si verifica una condizione d'interruzione per quella periferica.
I bit RCIF e TXIF sono di sola lettura, vengono settati o azzerati solo dall'hardware interno.
Per abilitare una interruzione di un modulo di periferica, non basta abilitarla nel registro PIE1, ma bisogna anche ricordarsi di mettere a 1 il bit PEIE del registro INTCON.
Vediamo ora, in dettaglio, come possiamo gestire e controllare i vari eventi con mikroBasic.
Cambio stato ingressi PORTB.4, PORTB.5, PORTB.6, PORTB.7
Questo è un interrupt esterno generato dagli ingressi PORTB.4, PORTB.5, PORTB.6, PORTB.7 che avviene quando, su almeno uno di questi ingressi, viene riscontrato un cambiamento di stato.
Questo interrupt può risvegliare il PIC dallo stato SLEEP.
Se qualcuno dei pin PORTB.4, PORTB.5, PORTB.6, PORTB.7 viene configurato come uscita anziché come ingresso, viene automaticamente escluso dalla possibilità di generare una interruzione.
program prova_Int_1
' 16F628A - 8MHz
sub procedure interrupt
if testbit(INTCON,RBIF) then
if testbit(PORTB,4) then
setbit(PORTB,2)
end if
if testbit(PORTB,5) then
clearbit(PORTB,2)
end if
clearbit(INTCON,RBIF)
end if
end sub
sub procedure pausa1000
delay_ms(1000)
end sub
main:
CMCON = %00000111 'comparatori spenti
PORTA = 0
TRISA = %00000
PORTB = 0
TRISB = %00110000
setbit(INTCON,RBIE) 'interr. portb.4, 5, 6, 7
setbit(INTCON,GIE) 'abilita tutti interrupt
while true
setbit(PORTA,0)
pausa1000
clearbit(PORTA,0)
pausa1000
wend
End.
|
Dopo l'etichetta main, impostiamo PORTA come uscita, PORTB.4 e PORTB.5 come ingressi, il resto come uscite.
Impostiamo a 1 il bit RBIE di INTCON, abilitando le interruzioni sul cambio stato degli ingressi PORTB.4, PORTB.5, PORTB.6 e PORTB.7.
Essendo, PORTB.6 e PORTB.7, uscite, non potranno generare interrupt.
Impostiamo a 1 il bit GIE di INTCON per abilitare tutti gli interrupt.
Facciamo lampeggiare un LED, con cadenza di circa 1 secondo, su PORTA.0.
A questo punto, quando verrà generato un'interruzione qualunque, il programma interromperà l'esecuzione e salterà all'indirizzo del vettore di interrupt dove c'è la sub procedura interrupt ed eseguirà il test del bit RBIF di INTCON.
Se questo bit sarà a 1, si eseguiranno le istruzioni per individuare quale ingresso (PORTB.4 o PORTB.5) ha causato l'interrupt e si eseguiranno le istruzioni predisposte.
Prima di uscire dalla sub, azzeriamo il bit RBIF di INTCON.
Ora, il programma uscirà dalla sub e riprenderà l'esecuzione da dove era stata interrotta precedentemente. |
Cambio stato ingresso PORTB.0 (RB0/INT)
Questo è un interrupt esterno generato dal piedino PORTB.0, che viene causato dal passaggio, da uno stato logico ad un altro, dell'ingresso PORTB.0.
Questo interrupt può risvegliare il PIC dallo stato SLEEP.
E' possibile far agire l'interrupt sia su un fronte di salita (passaggio da 0 a 1) che su un fronte di discesa (passaggio da 1 a 0).
L'una o l'altra modalità viene selezionata attraverso il bit INTEDG del registro OPTION_REG.
Se questo bit viene messo a 1, l'interrupt avviene in corrispondenza di un fronte di salita, mentre, se viene messo a 0, l'interrupt avviene in corrispondenza di un fronte di discesa.
Quando si alimenta il PIC o dopo un reset, questo bit viene messo a 1.
program prova_Int_2
' 16F628A - 8MHz
sub procedure interrupt
if testbit(INTCON,INTF) then 'portb.0 int
if testbit(PORTB,7) then
clearbit(PORTB,7)
else
setbit(PORTB,7)
end if
clearbit(INTCON,INTF)
end if
end sub
sub procedure pausa1000
delay_ms(1000)
end sub
main:
CMCON = %00000111 'comparatori spenti
PORTA = 0
TRISA = %00000
PORTB = 0
TRISB = %00000001
setbit(INTCON,INTE) 'abilita interr. portb.0
setbit(INTCON,GIE) 'abilita interrupt
while true
setbit(PORTB,2)
pausa1000
clearbit(PORTB,2)
pausa1000
wend
End.
|
Dopo l'etichetta main, impostiamo PORTB.0 come ingresso, il resto come uscite.
Impostiamo a 1 il bit INTE di INTCON, abilitando le interruzioni sul cambio stato dell'ingresso PORTB.0.
Impostiamo a 1 il bit GIE di INTCON per abilitare tutti gli interrupt.
Facciamo lampeggiare un LED, con cadenza di circa 1 secondo, su PORTB.2.
A questo punto, quando verrà generato un'interruzione qualunque, il programma interromperà l'esecuzione e salterà all'indirizzo del vettore di interrupt dove c'è la sub procedura interrupt ed eseguirà il test del bit INTF di INTCON.
Se questo bit sarà a 1, si eseguiranno le istruzioni predisposte.
Prima di uscire dalla sub, azzeriamo il bit INTF di INTCON.
Ora, il programma uscirà dalla sub e riprenderà l'esecuzione da dove era stata interrotta precedentemente. |
Azzeramento di TMR0
Il TMR0 è il registro che tiene il conteggio del Timer0 ed avanza automaticamente durante l'esecuzione di un programma.
Il microcontrollore genera un'interrupt non appena il valore di tale registro supera il limite di 255, ossia al verificarsi del relativo overflow e quindi azzeramento.
Questo interrupt non risveglia il PIC dallo stato SLEEP perchè, in quel caso, il Timer0 viene spento.
program prova_Int_3
' 16F628A - 8MHz
dim conta as byte
sub procedure interrupt
if testbit(INTCON,T0IF) then ' TMR0 int
Inc(conta)
TMR0 = 100
clearbit(INTCON,T0IF)
end if
end sub
main:
CMCON = %00000111 'comparatori spenti
PORTA = 0
TRISA = %00000
PORTB = %11111111
TRISB = 0
OPTION_REG = %11000101 'prescaler 1:64
TMR0 = 100
conta = 0
setbit(INTCON,T0IE) ' TMR0
setbit(INTCON,GIE) 'abilita interrupt
while TRUE
if (conta = 200) then
PORTB = not PORTB
conta = 0
end if
wend
end.
|
Dopo l'etichetta main,
impostiamo PORTB, il prescaler e il valore iniziale del registro TMR0.
Impostiamo a 1 il bit T0IE di INTCON, abilitando le interruzioni sull'azzeramento di TMR0.
Impostiamo a 1 il bit GIE di INTCON per abilitare tutti gli interrupt.
Tutta PORTB sarà impostata a 1. Ogni volta che la variabile conta arriva a 200, PORTB verrà invertita di stato.
Il risultato sarà che PORTB lampeggerà con cadenza di circa 1 secondo.
Quando verrà generato una interruzione qualunque, il programma interromperà l'esecuzione e salterà all'indirizzo del vettore di interrupt dove c'è la sub procedura interrupt ed eseguirà il test del bit T0IF di INTCON.
Se questo bit sarà a 1, verrà incrementata la variabile conta e reimpostato il valore di partenza di TMR0.
Prima di uscire dalla sub, azzeriamo il bit T0IF di INTCON.
Ora, il programma uscirà dalla sub e riprenderà l'esecuzione da dove era stata interrotta precedentemente. |
program prova_Int_6
' 16F628A - 8MHz
sub procedure interrupt
if testbit(PIR1,TMR1IF) then
..... vostre istruzioni
clearbit(PIR1,TMR1IF)
end if
end sub
main:
setbit(PIE1,TMR1IE) 'abil. interr. TMR1
setbit(INTCON,PEIE) 'abil. interr. perif.
setbit(INTCON,GIE) 'abil. tutti interrupt
while TRUE
..... vostre istruzioni
wend
end.
|
Azzeramento di TMR1
Il TMR1 è un registro a 16 bit (TMR1L - TMR1H) che tiene il conteggio del Timer1 ed avanza automaticamente durante l'esecuzione di un programma.
Il microcontrollore genera un'interrupt settando il bit di flag TMR1IF, in PIR1, non appena il valore, di tale registro, supera il limite di 65535, ossia al verificarsi del relativo overflow e quindi azzeramento.
Questo interrupt può risvegliare il PIC dallo stato SLEEP solo se il Timer1 viene fatto funzionare in modo asincrono (clock esterno). |
program prova_Int_7
' 16F628A - 8MHz
sub procedure interrupt
if testbit(PIR1,TMR2IF) then
..... vostre istruzioni
clearbit(PIR1,TMR2IF)
end if
end sub
main:
setbit(PIE1,TMR2IE) 'abil. interr. TMR2
setbit(INTCON,PEIE) 'abil. interr. perif.
setbit(INTCON,GIE) 'abil. tutti interrupt
while TRUE
..... vostre istruzioni
wend
end.
|
Uguaglianza di TMR2 con PR2
Il TMR2 è un registro ad 8 bit che tiene il conteggio del Timer2, avente un prescaler ed un postscaler ed avanza automaticamente durante l'esecuzione di un programma.
Non appena il valore, di tale registro, supera il valore impostato nel registro PR2, viene reimpostato a 0 e viene generato un'impulso di incremento per il postscaler, il quale al verificarsi del relativo overflow e quindi azzeramento, setta il bit di flag di interrupt TMR2IF in PIR1. |
program prova_Int_8
' 16F628A - 8MHz
sub procedure interrupt
if testbit(PIR1,CCP1IF) then
..... vostre istruzioni
clearbit(PIR1,CCP1IF)
end if
end sub
main:
setbit(PIE1,CCP1IE) 'abil. interr. CCP
setbit(INTCON,PEIE) 'abil. interr. perif.
setbit(INTCON,GIE) 'abil. tutti interrupt
while TRUE
..... vostre istruzioni
wend
end.
|
Interrupt del modulo Capture/compare (CCP)
Nella modalità CAPTURE, i registri CCPR1L e CCPR1H "catturano" il valore a 16 bit del timer TMR1 quando si verifica un determinato evento sul piedino RB3/CCP1.
Questo evento può essere:
un fronte di salita o di discesa
ogni 4 fronti di salita
ogni 16 fronti di discesa.
La modalità dell'evento viene determinata attraverso un registro di configurazione.
Appena è stata effettuata "la cattura", viene settato il bit di flag interrupt CCP1IF in PIR1.
Nella modalità COMPARE, il valore del registro CCPR1, a 16 bit, viene continuamente confrontato col valore del timer TMR1; quando i due valori sono uguali viene generato un evento sul piedino RB3/CCP1.
Questo evento può essere:
pin CCP1 posto alto
pin CCP1 posto basso
pin CCP1 invariato.
Contemporaneamente viene settato anche il bit di flag interrupt CCP1IF in PIR1. |
program prova_Int_9
' 16F628A - 8MHz
sub procedure interrupt
if testbit(PIR1,TXIF) then
..... vostre istruzioni
end if
end sub
main:
setbit(PIE1,TXIE) 'abil. interr. TX USART
setbit(INTCON,PEIE) 'abil. interr. perif.
setbit(INTCON,GIE) 'abil. tutti interrupt
while TRUE
..... vostre istruzioni
wend
end.
|
Interrupt su trasmissione USART Il bit TXIF indica lo stato del registro TXREG.
Il Transmit Shift Register (TSR) prende i dati dal Transmit Buffer Register (TXREG), a sua volta caricato via software.
Il registro TSR non viene caricato finchè non è stato trasmesso l'ultimo bit del dato precedente; non appena questo avviene, il TSR viene riempito con un nuovo dato dal TXREG in un ciclo istruzione.
TXREG rimane, allora, vuoto e ciò provoca il settaggio del bit di flag interrupt TXIF di PIR1, senza tener conto dello stato del bit di abilitazione TXIE.
TXIF sarà azzerato al caricamento di un nuovo dato in TXREG. |
program prova_Int_10
' 16F628A - 8MHz
sub procedure interrupt
if testbit(PIR1,RCIF) then
..... vostre istruzioni
end if
end sub
main:
setbit(PIE1,RCIE) 'abil. interr. RX USART
setbit(INTCON,PEIE) 'abil. interr. perif.
setbit(INTCON,GIE) 'abil. tutti interrupt
while TRUE
..... vostre istruzioni
wend
end.
|
Interrupt su ricezione USART Dopo la ricezione dell'ultimo bit, il dato viene trasferito dal Receive Shift Register (RSR) al registro RCREG e, quando il trasferimento è completo, viene settato il flag di interrupt RCIF di PIR1, che è un bit a sola lettura, azzerato dall'hardware quando RCREG è stato letto ed è vuoto.
Il bit di flag RCIF sarà settato quando la ricezione è completa ed un interrupt sarà generato se il bit RCIE in PIE1 è stato settato. |
program prova_Int_11
' 16F628A - 8MHz
sub procedure interrupt
if testbit(PIR1,CMIF) then
..... vostre istruzioni
clearbit(PIR1,CMIF)
end if
end sub
main:
setbit(PIE1,CMIE) 'abil. interr. compar.
setbit(INTCON,PEIE) 'abil. interr. perif.
setbit(INTCON,GIE) 'abil. tutti interrupt
while TRUE
..... vostre istruzioni
wend
end.
|
Interrupt su cambio stato dei comparatori Quando lo stato di uscita di uno dei due comparatori cambia, viene generato un'interrupt settando il bit di flag CMIF di PIR1, in risposta al quale è necessario, via software, andare a leggere i due bit C1OUT e C2OUT di CMCON per sapere quale dei due comparatori ha realmente cambiato stato. |
program prova_Int_5
' 16F628A - 8MHz
dim conta, scrivi as byte
sub procedure interrupt
if testbit(INTCON,RBIF) then
if testbit(PORTB,7) then
scrivi = 1
end if
clearbit(INTCON,RBIF)
else
if testbit(INTCON,INTF) then 'portb.0 int
if testbit(PORTB,2) then
clearbit(PORTB,2)
else
setbit(PORTB,2)
end if
clearbit(PORTB,3)
clearbit(INTCON,INTF)
else
if testbit(INTCON,T0IF) then 'TMR0 int
Inc(conta)
TMR0 = 100
clearbit(INTCON,T0IF)
else 'EEprom int
if testbit(PIR1,EEIF) then
setbit(PORTB,3)
clearbit(PIR1,EEIF)
end if
end if
end if
end if
end sub
main:
CMCON = %00000111 'comparatori spenti
PORTA = 0
TRISA = %00000
PORTB = 0
TRISB = %10000001
OPTION_REG = %11000101 'prescaler 1:64
TMR0 = 100
conta = 0
scrivi = 0
setbit(INTCON,RBIE) 'abil. int. portb.7
setbit(INTCON,INTE) 'abil. interr. portb.0
setbit(INTCON,T0IE) 'TMR0
setbit(PIE1,EEIE) 'abil. interr. EEprom
setbit(INTCON,PEIE) 'abil. interr. perif.
setbit(INTCON,GIE) 'abil. tutti interrupt
while TRUE
if conta = 200 then
PORTA = not PORTA
conta = 0
end if
if scrivi = 1 then
Eeprom_Write(2, 10)
scrivi = 0
end if
wend
end.
|
Ciclo completo di scrittura su Eeprom
Viene generato un'interrupt settando il bit di flag EEIF di PIR1, appena un programma termina un ciclo normale di memorizzazione su Eeprom. Dopo l'etichetta main, impostiamo PORTA come uscita, PORTB.0 e PORTB.7 come ingressi, il resto come uscite.
Impostiamo a 1 i bit RBIE, INTE, T0IE di INTCON per abilitare gli interrupt visti più sopra.
Impostiamo a 1 anche il bit EEIE di PIE1, abilitando le interruzioni sulla scrittura completata in EEprom.
Impostiamo a 1 anche i bit PEIE e GIE di INTCON per abilitare tutti gli interrupt.
Tutta PORTA sarà impostata a 0. Ogni volta che la variabile conta arriverà a 200, PORTA verrà invertita di stato.
Il risultato sarà che PORTA lampeggerà con cadenza di circa 1 secondo.
Se la variabile scrivi è uguale a 1, si effettuerà la scrittura di un dato in EEprom.
A questo punto, quando verrà generato un'interruzione qualunque, il programma interromperà l'esecuzione e salterà all'indirizzo del vettore di interrupt dove c'è la sub procedura interrupt ed eseguirà il test del bit RBIF di INTCON.
Se questo bit sarà a 1, si eseguirà il test del bit 7 di PORTB.
Se questo bit sarà a 1, viene impostata a 1 la variabile scrivi, che permetterà la scrittura di un dato in EEprom.
Prima di uscire, azzeriamo il bit RBIF di INTCON.
Oppure eseguirà il test del bit INTF di INTCON.
Se questo bit sarà a 1, si accenderà o spegnerà il LED su PORTB.2.
Si spegnerà anche il LED su PORTB.3, acceso dalla gestione interrupt su scrittura EEprom.
Prima di uscire, azzeriamo il bit INTF di INTCON.
Oppure eseguirà il test del bit T0IF di INTCON.
Se questo bit sarà a 1, si eseguiranno le istruzioni predisposte per gestire il Timer0.
Prima di uscire, mettiamo a 0 il bit T0IF di INTCON.
Oppure eseguirà il test del bit EEIF di PIR1.
Se questo bit sarà a 1, significa che l'interrupt è stato generato dalla scrittura completata in EEprom e quindi, verrà acceso il LED su PORTB.3.
Prima di uscire, azzeriamo il bit EEIF di PIR1.
Ora, il programma uscirà dalla sub e riprenderà l'esecuzione da dove era stata interrotta precedentemente. |
Bibliografia:
Manuale mikroBasic
PICmicro MID-RANGE MCU family - section 8. Interrupts
PIC18C Reference Manual - section 10. Interrupts
Datasheet PIC16F628A
Continua nella successiva parte
Ultima modifica
|
|