Programmare in mikroBasic
 
  Box
Uso dell'interrupt
(parte 1)

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.

Che cos'è un'interrupt (interruzione)?

Vediamo queste 2 situazioni.

Caso 1

Tempo fa, ho ordinato dei componenti elettronici via internet.

Dopo qualche giorno, seguendo il percorso della spedizione dal sito del corriere, ho visto che il pacchetto, era stato caricato, alle ore 8, su un veicolo per la consegna.

Da quel momento in poi, ogni 10 minuti ed ogni volta che sentivo il rumore del motore di un veicolo, andavo alla finestra, a vedere se era arrivato il pacchetto.

Ho fatto così per quasi 3 ore, quando finalmente il pacchetto è arrivato.

Questo modo di fare (controllo continuo cadenzato), si può paragonare a quello che, nel mondo della programmazione, si chiama polling.

Caso 2

Ieri, mentre stavo facendo il sugo alla amatriciana, mi suonano alla porta.

Era il portalettere con una raccomandata da consegnare e voleva la firma di consegna.

Ho messo "in sicurezza" il sugo e quindi ho spento il gas.

Sono sceso a firmare e, quindi, ritirare la raccomandata.

Ritornato su, ho ripristinato la condizione precedente, riaccendendo il gas ed ho continuato a fare il sugo.

Questo modo di fare può essere paragonato ad un interrupt.

Delle 2 situazioni qual'è la meno laboriosa? Di sicuro il caso 2 perchè non c'è il "lavoro" di andare a vedere ogni 10 minuti se il pacco è arrivato.
Nel caso 2, si può dire che c'è una situazione di controllo su interruzione, mentre nel caso 1 c'è una situazione di controllo continuo, detto polling.
Nel caso 1 avrei potuto anche attendere, tranquillo, che il corriere mi suonasse alla porta, senza fare tutto quel "lavoro" di controllo.
Nel caso 2, invece, non sapendo dell'arrivo della raccomandata, non avrebbe senso fare come nel caso 1, perchè si rischierebbe di fare un controllo infinito.

Riportando tutto questo nel mondo dei microcontrollori PIC, le cose funzionano più o meno nella stessa maniera.

Modalità polling

Nell'esempio dobbiamo controllare il livello di una vasca che sta ricevendo dell'acqua.

1) Avviamo una pompa per 1 minuto per svuotare la vasca e poi fermiamo la pompa per 10 minuti.

2) Controlliamo se il livello è al massimo e, se questo è vero,

3) avviamo la pompa 2 e torniamo al punto 1.

4) Altrimenti controlliamo se il livello è sotto il minimo.

5) Se la risposta è negativa torniamo al punto 1

6) altrimenti, il programma termina.

Questa è la modalità detta polling.

program pompa_Polling
' 16F84A - 8MHz
sub procedure pausa_minuti(dim minuti as byte)
    while minuti > 0
        delay_ms(25000)         '25 secondi
        delay_ms(25000)
        delay_ms(10000)         '10 secondi
        dec(minuti)
    wend
end sub

main:
    portB = 0
    trisb = %00000011
    do
        portB.7 = 1             'avvio pompa1
        pausa_minuti(1)
        portB.7 = 0             'fermo pompa1
        pausa_minuti(10)
        if portB.0 = 1 then     'livello massimo
            portB.6 = 1         'avvio pompa2
        end if
    'ripeti se è sopra al livello minimo
    loop until portB.1 = 1
    portB.6 = 0                 'fermo pompa2 
End.

Polling in mikrobasic

Pausa_minuti è una sub procedura che genera un ritardo massimo di 255 minuti, dipendente dal parametro minuti di tipo byte.

Dentro al ciclo While-Wend viene generato un ritardo di 25+25+10 secondi (vedi delay_ms), per il numero di volte impostato da minuti.

PortB.7 è collegato al relè che comanda la pompa1
PortB.6 è collegato al relè che comanda la pompa2
PortB.0 è collegato al livello massimo
PortB.1 è collegato al livello minimo

Dentro al ciclo do-loop until viene avviata e fermata la pompa1.
Alla fine del ritardo di 10 minuti viene controllato il livello massimo ed, eventualmente, avviata la pompa2.
Se il livello massimo viene raggiunto prima che siano passati i 10 minuti, la pompa2 non verrà avviata subito ed il liquido traboccherà dalla vasca.
Questo ciclo verrà ripetuto finchè il livello è sopra al minimo, altrimenti (se portB.1 = 1) il programma termina.

Modalità interrupt

1) Avviamo una pompa per 1 minuto per svuotare la vasca e poi fermiamo la pompa per 10 minuti.

2) Controlliamo se il livello è sotto il minimo.

3) Se la risposta è negativa torniamo al punto 1

4) altrimenti, il programma termina.

Durante tutto il funzionamento del programma, viene controllato se il livello è al massimo e, se questo è vero,

5) avviamo la pompa 2 e continuiamo quello che si stava facendo prima.

Questa è la modalità detta interrupt.

program pompa_Interrupt
' 16F84A - 8MHz
sub procedure pausa_minuti(dim minuti as byte)
    while minuti > 0
        delay_ms(25000)         '25 secondi
        delay_ms(25000)
        delay_ms(10000)         '10 secondi
        dec(minuti)
    wend
end sub

sub procedure interrupt
    if testbit(INTCON,INTF) then  'portb.0 int
        portB.6 = 1               'avvio pompa2
        clearbit(INTCON,INTF)
    end if
end sub

main:
    portB = 0
    trisb = %00000011
    setbit(INTCON,INTE) 'abilita interr. portb.0
    setbit(INTCON,GIE)  'abilita tutti interrupt
    do
        portB.7 = 1     'avvio pompa1
        pausa_minuti(1)
        portB.7 = 0     'fermo pompa1
        pausa_minuti(10)
    'ripeti se è sopra al livello minimo
    loop until portB.1 = 1
    portB.6 = 0         'fermo pompa2
End.

Interrupt in mikrobasic

Pausa_minuti è una sub procedura che genera un ritardo massimo di 255 minuti, dipendente dal parametro minuti di tipo byte (vedi delay_ms).

Interrupt è la sub procedura che viene eseguita quando è generato un'interrupt da portB.0 se viene raggiunto il livello massimo.
In questo caso verrà avviata la pompa2.

PortB.7 è collegato al relè che comanda la pompa1
PortB.6 è collegato al relè che comanda la pompa2
PortB.0 è collegato al livello massimo
PortB.1 è collegato al livello minimo

Dopo l'etichetta main abilitiamo le interruzioni per portB.0.

Dentro al ciclo do-loop until, viene avviata e fermata la pompa1.
Se il livello massimo viene raggiunto in qualunque punto siamo nel programma, la pompa2 verrà avviata subito ed il liquido non traboccherà dalla vasca.
Questo ciclo verrà ripetuto finchè il livello è sopra al minimo, altrimenti (se portB.1 = 1) il programma termina.

Le interruzioni sono uno strumento molto potente, per mezzo del quale, il programmatore riesce a gestire varie operazioni senza sprecare tempo utile.
Un'interruzione è un evento che interrompe la normale esecuzione di un programma.
Gli eventi tipici sono quelli che vengono generati dai moduli di periferica interni, come per esempio i timer, le linee su PORTB (o anche il convertitore A/D, l'USART e altro ancora).
Questi tipi d'interruzione, fanno continuare il programma ad un'indirizzo specifico, che viene detto vettore d'interrupt.

Vettore di reset e vettore d'interrupt

Nella memoria programma dei PIC, sono stati predisposti dei vettori, che deviano l'esecuzione del programma ad un indirizzo fisso, a seconda dell'evento avvenuto.
Quando il pin MCLR viene portato a livello logico basso (generalmente a massa) avviene il reset (azzeramento, ripristino) del pic.

Il vettore di reset è l'indirizzo dove il programma salterà dopo un reset del pic ed è posizionato, di solito, all'indirizzo 0x0000 ma, per alcuni pic non è così (ad esempio il pic16F54, controllare il datasheet). Tuttavia, questo particolare, in mikroBasic non ha molta importanza, ma se programmiamo anche in assembly, dobbiamo tenerne conto.

Il vettore di interrupt è l'indirizzo dove il programma salterà quando viene generato un'interrupt da parte del pic.
Questo indirizzo, per i pic delle serie PIC12 e PIC16 (almeno per quelli che conosco io), è posizionato all'indirizzo 0x0004.
Alcuni pic sono privi del vettore d'interrupt e, quindi, privi anche dei registri associati.
I pic della serie PIC18 hanno 2 vettori d'interrupt (di alta e bassa priorità). Il vettore ad alta priorità è posizionato all'indirizzo 0x0008 ed il vettore a bassa priorità è posizionato all'indirizzo 0x0018.

Quando avviene un'interruzione da parte delle periferiche, prima di saltare al vettore d'interruzione, il PIC salverà tutte le informazioni necessarie nello stack, per poter riprendere dal punto in cui il programma è stato interrotto, una volta eseguite le operazioni necessarie per gestire l'interruzione.

Sorgenti d'interrupt, registri e bit specifici

Alcune caratteristiche del PIC16F84A

Pin Flash RAM Eeprom I/O Timer Clock
interno
CCP ADC Comp Usart LVP Costo
18 1k 68 64 13 1 No No No No No No € 4,2

Vediamo, come esempio, gli interrupt che possono essere gestiti dal PIC16F84A, il più famoso e conosciuto (ma anche vecchiotto ed, ormai, obsoleto).

Sorgente di Interrupt
(16F84A)
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  
Scrittura EEPROM completata INTCON, EECON1 EEIE EEIF Bit di Flag in EECON1

I primi 2 sono eventi di tipo esterno, i secondi 2 invece, sono eventi di tipo interno.

In ogni PIC, che implementi l'interrupt, ci possono essere varie sorgenti di interruzione.
Queste sorgenti, di solito, comprendono una sorgente di interrupt per ogni modulo di periferica, anche se, alcuni moduli, possono generare interrupt multipli (ad es. il modulo Usart).
Ci sarà almeno un registro dedicato alla gestione delle interruzioni: il registro INTCON.

Se il pic contiene moduli di periferica (A/D, Usart, CCP, PSP, ecc.) saranno presenti ulteriori registri PIEx per l'abilitazione dell'interrupt (PIE1, PIE2, ecc.) e PIRx per i Flag di segnalazione (PIR1, PIR2, ecc.).

Per i PIC della serie PIC18 ci saranno anche i registri IPRx, per impostare la priorità (alta o bassa) di ogni interruzione (IPR1, IPR2, ecc.). Troveremo anche il registro RCON, con il bit per le priorità.

Controllare sempre il datasheet, perchè la funzione e la posizione dei bit dei registri INTCON, PIEx, PIRx, IPRx non è uguale per tutti i PIC.

Il PIC16F84A non contiene moduli di periferica, quindi è presente solo il registro INTCON, che permette la gestione degli interrupt tramite l'impostazione di alcuni bit specifici.

   

Per ogni interrupt da gestire sono presenti:

Il bit di Enable (Abilitazione/disabilitazione) distinguibile, di solito, da una E finale nel nome del bit.
Se tale bit è impostato a 1, l'interrupt che gestisce l'evento viene abilitato.
Viceversa, se è impostato a 0, non viene abilitato e si dice, così, che l'interrupt, per quel bit, è mascherato.
Nel nostro esempio, i bit sono RBIE, INTE, T0IE, EEIE.

Il bit di Flag (Segnalazione dell'evento accaduto) distinguibile, di solito, da una F finale nel nome del bit.
Questo bit viene impostato a 1 quando si è verificato l'evento specifico ed è stato generato l'interrupt.
Viceversa, se è impostato a 0, significa che l'evento non si è verificato.
Nel nostro esempio, i bit sono RBIF, INTF, T0IF.
Nota: Il bit di flag EEIF, in questo caso, si trova nel registro EECON1.

Esiste sempre, poi, il bit speciale GIE, il quale serve per bloccare o sbloccare tutte le interruzioni abilitate.

Se immaginiamo i vari bit come interruttori aperti (quando sono impostati a 0) o chiusi (quando sono impostati a 1), possiamo farci un'idea di come sarà generata in'interruzione.

Per gestire una sorgente d'interrupt dobbiamo impostare a 1, prima di tutto, il bit di abilitazione specifico per quella sorgente e poi impostare a 1 il bit GIE per abilitare tutti gli interrupt.

Quando si verificherà un'evento da una sorgente d'interrupt, il microcontrollore imposterà ad 1 il Flag corrispondente e, se l'interrupt per quella sorgente è abilitato (non è, perciò, mascherato), verrà generata l'interruzione.

A questo punto, il PIC interromperà quello che stava facendo, metterà a 0 il bit GIE per bloccare ogni ulteriore interruzione, salverà nello stack l'indirizzo di programma attuale ed eseguirà un salto all'indirizzo del vettore di interrupt.

ISR (Interrupt Service Routine)

Per controllare e gestire le interruzioni che vengono generate, dobbiamo creare una sub procedura specifica, detta ISR (Interrupt Service Routine), collocata all'indirizzo del vettore d'interrupt.
In mikroBasic, questa è una sub procedura speciale, alla quale, obbligatoriamente, si deve assegnare il nome "interrupt", riservato specificamente a questo scopo.
Quando il compilatore trova la procedura col nome "interrupt", la colloca automaticamente all'indirizzo del vettore d'interrupt, senza che noi ci preoccupiamo di farlo.
Non dobbiamo preoccuparci, neanche, di salvare la situazione dei registri principali (W, STATUS, FSR e PCLATH), perchè verrà fatto autonomamente dal compilatore a livello assembly, così come il ripristino degli stessi, prima dell'uscita dalla sub.

Per la serie PIC18, come vedremo più avanti, la sub procedure interrupt, sarà collocata , dal compilatore, all'indirizzo del vettore d'interrupt ad alta priorità e gestirà le interruzioni ad alta priorità, mentre (a partire dalla vers. 6.0 di mikroB) per le interruzioni a bassa priorità, la sub procedura dovrà essere nominata "interrupt_low" e sarà collocata, dal compilatore, all'indirizzo del vettore d'interrupt a bassa priorità.

Nella sub procedura interrupt, metteremo le istruzioni per controllare i bit di Flag, per verificare quale evento d'interruzione sia avvenuto e, di conseguenza, inseriremo le istruzioni per gestire quell'evento.
Prima di uscire dalla sub procedura dobbiamo, però, ricordarci di impostare a 0 il bit del Flag che ha generato l'interruzione. Se non lo facciamo, la sub procedura interrupt, potrebbe venire rieseguita all'infinito.
Il PIC ripristinerà il bit GIE, mettendolo a 1, permettendo lo scatenarsi di altri interrupt, anche quelli eventualmente bloccati durante l'esecuzione della ISR.

Interrupt nel PIC16F84A

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
' 16F84A - 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:
    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
' 16F84A - 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:
    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. Si tratta di un'interrupt interno.
Questo interrupt non risveglia il PIC dallo stato SLEEP perchè, in quel caso, il Timer0 viene spento.

program prova_Int_3
' 16F84A - 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:
    TRISB = 0
    PORTB = %11111111
    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 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 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.

Ciclo completo di scrittura su Eeprom
Viene generato un'interrupt appena un programma termina un ciclo normale di memorizzazione su Eeprom. Anche in questo caso si tratta di un evento interno.
Diversamente dalle precedenti sorgenti d'interrupt, il bit di Flag EEIF, di segnalazione evento avvenuto, in questo caso, si trova nel registro EECON1.

   

Questa volta vedremo come si possono gestire più interrupt nell'unica sub procedura permessa.

program prova_Int_4
' 16F84A - 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(EECON1,EEIF) then
                    setbit(PORTB,3)
                    clearbit(EECON1,EEIF)
                end if
            end if
        end if
    end if
end sub

main:
    PORTA = 0
    PORTB = 0
    TRISA = 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(INTCON,EEIE) 'abil. interr. EEprom
    setbit(INTCON,GIE)  'abilita 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.

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 prima.
Impostiamo a 1 anche il bit EEIE di INTCON, abilitando le interruzioni sulla scrittura completata in EEprom.

Impostiamo a 1 il bit 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 EECON1.
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 EECON1.

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 PIC16F84A

Continua nella parte successiva

Ultima modifica  

 
Privacy Policy Cookie Policy