Danilo B (ildani) LAMPEGGIO LED TRAMITE TIMER INTERRUPT - PARTE 4 15 January 2013 Introduzione Questa è la quarta ed ultima parte dell'articolo Lampeggio led tramite Timer Interrupt. Non lampeggia Come ho scritto nell'ultima frase della terza parte dell'articolo, mi trovavo di fronte ad un led semiacceso, eppure mi sembrava di avere scritto correttamente il codice! In MPLAB X IDE apro le proprietà del progetto, e nella configurazione seleziono in Hardware Tools la voce Simulator anzichè PICkit3 per provare a simulare il funzionamento del programma. Metto alcuni breakpoint nel codice per far fermare l'esecuzione del programma e dare un'occhiata alle variabili e ai registri prima di ripartire: il codice funziona bene. Cosa c'è allora che non fa funzionare il circuito nella pratica? La soluzione Il giorno seguente, mentre sistemo un po' le finestre in Firefox dove tengo aperti i siti che sto consultando per imparare la programmazione dei PIC, la mia attenzione viene catturata da un Webinar (abbreviazione di Web Seminar, seminario on-line) della Microchip intitolato "Flash, Damned LED! Flash I say!" (lampeggia, dannato led! Lampeggia ho detto!). Faccio partire il video ed il relatore Jeff O'Keefe spiega che affronterà i comuni errori commessi dai principianti per far lampeggiare un led. Non ero molto fiducioso di incontrare la soluzione al mio problema, e invece... LAMPEGGIO LED TRAMITE TIMER INTERRUPT - PARTE 4 1
Chi controlla il pin Il video arriva alla quarta slide che richiama dei concetti che già conoscevo, ma che non avevo a quanto pare ben assimilato. Anche in questo caso il problema e la relativa soluzione erano banali! Non mi ero ricordato che i pin spesso svolgono più di una funzione e sono condivisi da più periferiche, sono multiplexati. In particolare il pin RA0 scelto da me per collegare il led, svolge sia la funzione di ingresso/uscita digitale RA0, sia la funzione di ingresso/uscita analogico AN0. Per configurare correttamente questo pin dovevo agire su un secondo registro, oltre che sul noto TRIS: si tratta del registro ADCON1, ossia uno dei due registri usati per configurare il convertitore analogico/digitale. Come suggerisce la slide del seminario, con l'istruzione ADCON1 = 0b00000110; si impostano tutti i pin disponibili per il convertitore A/D come ingressi/uscite digitali. Aggiungo in fretta quest'istruzione al mio codice, reimposto il programmatore PicKit3 e carico il programma sul mio PIC16F87. Ed ecco il led che lampeggia! Poi provo a cambiare il valore del TempoLampeggio e noto che funziona bene, il led lampeggia più o meno brevemente a seconda del valore. Finalmente ho realizzato quello che volevo. LAMPEGGIO LED TRAMITE TIMER INTERRUPT - PARTE 4 2
Codice finale #include <xc.h> //DEFINE #define TempoLampeggio 500 #define Led PORTAbits.RA0 // CONFIG #pragma config FOSC = XT #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config CP = OFF #pragma config BOREN = OFF #pragma config LVP = OFF #pragma config CPD = OFF #pragma config WRT = ON // Oscillator Selection bits (XT oscillator) // Watchdog Timer Enable bit (WDT disabled) // Power-up Timer Enable bit (PWRT disabled) // FLASH Program Memory Code Protection bits (Code prot // Brown-out Reset Enable bit (BOR disabled) // Low Voltage In-Circuit Serial Programming Enable bit // Data EE Memory Code Protection (Code Protection off) // FLASH Program Memory Write Enable (Unprotected progr //VARIABILI unsigned int Tempo = 0; void main(void) { //IMPOSTAZIONE PORTE INPUT/OUTPUT //PORTA is a 6-bit wide, bi-directional port. TRISA = 0; TRISB = 0; TRISC = 0; //IMPOSTAZIONE PORTE: TUTTE DIGITALI ADCON1 = 0b00000110; //ACCENSIONE Led Led = 1; //IMPOSTARE PRESCALER // Generato da PicTimer 1.0.1.0 // Bernardo Giovanni - www.settorezero.com // Codice valido per Hitec-C // Fosc :4MHz // Timer0 preload :6 // Prescaler :4 // Interrupt time :1,0000mS LAMPEGGIO LED TRAMITE TIMER INTERRUPT - PARTE 4 3
// OPTION // bit 0 -> PS0 Prescaler Rate Select bit 0 // bit 1 -> PS1 Prescaler Rate Select bit 1 // bit 2 -> PS2 Prescaler Rate Select bit 2 // bit 3 -> PSA Prescaler assegnato a Timer0 (1=Watchdog Timer) // bit 4 -> T0SE Timer0 Signal Edge: 0=low->high 1=high->low // bit 5 -> T0CS Timer0 Clock Select: internal clock (1=T0CKI transition) // bit 6 -> INTEDG INTerrupt Edge (1=raise 0=fall) // bit 7 -> RBPU PortB PullUp (0=off 1=on) OPTION_REG = 0b00000001; //IMPOSTARE INTERRUPT // INTCON // bit 0 -> RBIF PortB Interrupt Flag // bit 1 -> INTF RB0/INT Interrupt Flag // bit 2 -> T0IF Timer0 Interrupt Flag // bit 3 -> RBIE PortB Interrupt Enable (off) // bit 4 -> INTE INT Interrupt Enable (off) // bit 5 -> TMR0IE Timer0 Interrupt Enable (on) // bit 6 -> PEIE PEripheral Interrupt Enable (off) // bit 7 -> GIE Global Interrupt Enable (on) INTCON = 0b10100000; //PRECARICARE IL TIMER // Preload Timer0 // TMR0=8; // valore con correzione TMR0 = 8; // con correzione while (1) { //ROUTINE DI INTERRUPT void interrupt isr(void) { //CONTROLLO SORGENTE INTERRUPT TIMER0 OVERFLOW if (T0IF) { //REIMPOSTAZIONE DEL PRECARIMENTO TIMER0 LAMPEGGIO LED TRAMITE TIMER INTERRUPT - PARTE 4 4
TMR0 = 8; //INCREMENTO VARIABILE TEMPO E CONTROLLO VALORE //CON INVERSIONE STATO LED ED AZZERAMENTO TEMPO Tempo++; if (Tempo >= TempoLampeggio) { Led =!Led; Tempo = 0; //AZZERAMENTO TIMER0 OVERFLOW T0IF = 0; Conclusioni In questo articolo ho cercato di massimizzare il coinvolgimento del lettore condividendo il ragionamento, frammentando al massimo i passaggi teorici sperando che il lettore possa comprendere, e fare suo, il metodo di studio e soluzione. Estratto da "http://www.electroyou.it/mediawiki/ index.php?title=userspages:ildani:parte-4" LAMPEGGIO LED TRAMITE TIMER INTERRUPT - PARTE 4 5