Gestire le interruzioni nel PIC18 - OLD

Questa pagina è stata sostituita da Gestire le interruzioni nel PIC18

L'uso delle informazioni contenute in questa pagina potrebbe causare alcune difficoltà nell'esecuzione del codice presentato, derivanti da quello che ritengo essere un bug (non confermato) di MPLAB, a partire dalla versione 8.83. Con le versioni precedenti (perlomeno con la 8.63, versione che usai al momento della stesura) non ci sono invece problemi se si usa come debugger ICD 3. Problemi sono invece presenti usando come debugger il PicKit 2, anche usando vecchie versioni di MPLAB.

Il problema si manifesta quando si tenta di debuggare il codice relativo all'uso del pin RA3/MCLR/Vpp configurato per generare un interrupt, quindi come input, disattivando la funzione di Master Reset. MPLAB mostra la figura sotto riportata; ICD 3 cannot debug while the following setting are enabled: - MCLR Pin Enable bit

Un bug di MPLAB 8.83? ICD 3 cannot debug while the following setting are enabled: - MCLR Pin Enable bit

Se è vero infatti che, in genere, l'uso di RA3 come ingresso è incompatibile con l'uso di un debugger in-circuit, è altrettanto vero che con PIC18F14K50 è sempre necessario l'uso di un chip PIC18F14K50-ICD che ha due pin di master reset, uno RA3/MCLR/Vpp ad uso del target, uno ICDMCLR/Vpp ad uso del debugger (e infatti non ci sono problemi con le vecchie versioni del software MPLAB!).

Quanto segue è la versione originale, da utilizzare dopo aver ben compreso la premessa. Occorre sottolineare che codice è pienamente funzionante, solo diventa problematico effettuare il debug e ciò non è bello in un contesto didattico. Peccato, entrambe le schede demo di Microchip che possiedo hanno un solo pulsante, collegato proprio a RA3!


In questa pagina verrà mostrato come gestire le interrupt con priorità del PIC18 utilizzando come sorgente un interruttore meccanico oppure un contatore hardware. Se non sapete cosa è una interruzione, potete leggere le prime righe della pagina Gestire le interruzioni con il PIC16.

Emulatore ICD3 con header per PIC18 su schedine demo Microchip

L'hardware utilizzato è costituito da quattro LED connessi alla PORTC del PIC18 ed un interruttore connesso alla PORTA, circuito realizzabile senza problemi anche su breadboard. Nell'immagine è mostrato anche un emulatore ICD3 con relativo header, ma non è necessario utilizzarlo, anche se oggettivamente comodo.

Il PIC 18 utilizza due livelli di interruzione, definiti ad alta e bassa priorità. Per una descrizione dettagliata occorre fare riferimento ai manuali tecnici ma, in breve:

Il codice: interrupt a bassa priorità da un interruttore

Questo programma  permette di spegnere i LED quando viene premuto un interruttore, indipendentemente dall'esecuzione del programma principale che invece li accende in sequenza. Potete scaricare il codice a fondo pagina.

Quando il pulsante è premuto o rilasciato viene attivata una interruzione a bassa priorità (Low Priority Interrupt), vengono salvati alcuni registi e quindi eseguito il codice presente all'indirizzo 0x18 (Low Priority Interrupt Vector). In genere si tratta di una singola istruzione di salto, scritta in assembler perché lo spazio a disposizione è davvero poco. Nessuna preoccupazione: non serve imparare anche questo linguaggio, questa riga di codice è sempre uguale!

Il programma è suddiviso in due blocchi.

#pragma code low_vector = 0x18 // Setup interrupt vector
void interrupt_low (void)
{ _asm GOTO Low_Int _endasm } // Jump to ISR function (in-line assembler)

Il primo blocco, evidenziato dalla direttiva #pragma code low_vector = 0x18 viene posto obbligatoriamente all'inizio del vettore di interruzione, di indirizzo fisso 0x18. In pratica si tratta di una singola istruzione assembler che, eseguita quando viene generato un interrupt, invoca la funzione C Low_Int() che contiene il codice vero e proprio di gestione dell'interruzione.

Tutto il resto del programma viene allocato automaticamente dal compilatore, come specificato dalla seguente direttiva #pragma code.

Sono presenti due funzioni. Il main() come prima cosa imposta le porte di ingresso e uscita e quindi configura i molti registri che gestiscono le interruzioni, purtroppo senza supporto dalle librerie Microchip, riservate a PORTB:

IOCAbits.IOCA3 = 1;    // RA3: Interrupt-on-change enabled
INTCONbits.RABIE = 1;  // RA and RB Port Change Interrupt Enable bit
RCONbits.IPEN = 1;     // Enable priority levels on interrupts
INTCON2bits.RABIP = 0; // Low priority
INTCONbits.GIEL = 1;   // Enables all low priority interrupts
INTCONbits.GIEH = 1;   // Enables all high priority interrupts (required even for LOW priority)

La descrizione dettagliata è presente sui fogli tecnici del PIC18 ma, in breve, occorre:

In seguito il programma non farà altro che accendere i 4 LED in sequenza, in un loop infinito.

La seconda funzione è invocata nel momento in cui è premuto l'interruttore e spegne i quattro LED.

if (INTCONbits.RABIF == 1)
{dummy = PORTA;        // Need to read PORTA to clear interrupt
 PORTC=0;              // Clear LEDs status
 INTCONbits.RABIF = 0; // Clear interrupt status

}

Il codice prima controlla se l'interrupt è stato effettivamente generato dall'interruttore (tutte le periferiche condividono gli stessi interrupt), azzera PORTC,  azzera i flag che hanno segnalato l'interruzione. Si noti in particolare la necessità di leggere il contenuto di PORTA, operazione inutile in questo caso ma necessaria per segnalare alla periferica che il codice dell'interruzione è stato eseguito.

Il fatto che sia una funzione per la gestione delle interruzioni è evidenziato dalla direttiva #pragma interruptlow.

Il codice: interrupt ad alta priorità da un interruttore

Il codice per gestire interruzioni ad alta priorità è, evidentemente, molto simile al precedente.

A fondo pagina potete trovare un esempio praticamente identico al precedente: l'unica cosa da notare è il diverso vettore utilizzato per memorizzare la funzione in assembler ed il fatto che le interruzioni ad alta priorità possono essere eseguite anche quando quelle a bassa priorità sono sospese.

Il codice: interrupt a bassa priorità dal timer

Il terzo esempio, sempre a fondo pagina, mostra come utilizzate Timer0 come sorgente dell'interrupt. In questo caso il segnale di interruzione viene generato internamente al PIC da un modulo hardware indipendente dal processore.

La struttura è molto simile ai precedenti:

Scarica il codice sorgente: interruttore a bassa priorità

Scarica il codice sorgente: interruttore ad alta priorità

Scarica il codice sorgente: Timer0 a bassa priorità

PIC18F14 in C

Licenza "Creative Commons" - Attribuzione-Condividi allo stesso modo 3.0 Unported


Pagina principaleAccessibilitàNote legaliPosta elettronicaXHTML 1.0 StrictCSS 3

Vai in cima