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
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.
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:
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 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 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à
Appunti di elettronica
- PIC18F14 in C - OBSOLETO - Versione 1.0 - Ottobre 2014
Copyright 2010-2012, Vincenzo Villa (https://www.vincenzov.net)
Quest'opera stata rilasciata con licenza Creative Commons | Attribuzione-Condividi allo stesso modo 3.0 Unported.