|
|
TIMER DI BASE CLOCK 4000000 Hz usando TMR0 |
|
| Per realizzare un programma per i PIC micro in grado di simulare un orologio è necessario conteggiare i secondi, i minuti e le ore e visualizzare il tutto in un display LCD | ||||||||||||||||||||||||||||
| Per poter far ciò è necessario utilizzare l'INTERRUPT del micro | ||||||||||||||||||||||||||||
| PIC Genius gestisce graficamente l'interrupt . Vediamo come : | ||||||||||||||||||||||||||||
| Nella schermata dell'editor scegliere la voce INTERRUPT nel menù a tendina che si aprirà premendo il pulsante PROGETTO | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Spuntare le voci TOIE (interrupt del TMR0) e GIE (interrupt generale) | ||||||||||||||||||||||||||||
| Il TMR0 è un timer interno del PIC a 8 bit (da 0 a 255 decimale) il cui clock può essere dato dall'interno o dall'esterno del PIC | ||||||||||||||||||||||||||||
| Per utilizzare il clock interno e necessario porre a 0 il bit TOCS del registro INTCON. Dopo un tempo pari a 4 cicli macchina il contenuto del TMR0 viene incrementato di 1. Quando si supera il valore 255 si ha un overflow , il registro viene azzerato e ricomincia il conteggio. | ||||||||||||||||||||||||||||
| Con un quarzo da 4 MHZ si avranno 4.000.000 di cicli macchina al secondo e quindi il TMR0 subirà 1.000.000 di conteggi al secondo. | ||||||||||||||||||||||||||||
| Quando si ha un overflow il PIC abbandona l'esecuzione del programma annotando la riga di codice successiva da eseguire nello stack e salta ad eseguire la routine di INTERRUPT terminata la quale continua ad eseguire il codice dalla riga annotata nello stack. | ||||||||||||||||||||||||||||
| Facciamo un pò di conti : ( calcolo relativo ad un secondo ) | ||||||||||||||||||||||||||||
| 1000000 / 256 = 3906,25 | ||||||||||||||||||||||||||||
| 1000000 = conteggi del timer | ||||||||||||||||||||||||||||
| 256 = conteggi per overflow timer | ||||||||||||||||||||||||||||
| 3906,25 = volte che si ha un overflow e che viene eseguita la routine di interrupt in un secondo | ||||||||||||||||||||||||||||
| 1000000 / 3906,25 = 256 (sembra una formula inversa ma in realtà non lo è) | ||||||||||||||||||||||||||||
| 1000000 = microsecondi in un secondo | ||||||||||||||||||||||||||||
| 3906,25 = volte che si ha un overflow e che viene eseguita la routine di interrupt | ||||||||||||||||||||||||||||
| 256 = overflow ogni microsecondi | ||||||||||||||||||||||||||||
| Attivando quindi il timer si avrebbe un accesso alla routine di interrupt ogni 256 microsecondi e se la sua lunghezza eccede le 256 istruzioni si avrebbe un loop ricorsivo (ERRORE) . In pratica non si uscirebbe mai dalla routine. | ||||||||||||||||||||||||||||
| Per poter scrivere routines più lunghe e per diminuire la quantità di accessi poichè si rallenterebbe il loop principale del programma di solito si fà uso del prescaler interno del PIC. | ||||||||||||||||||||||||||||
| Il prescaler è un divisore interno che può essere configurato in diversi modi : | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
| I dati della tabella sono relativi a 256 conteggi del tmr0. Tale registro può essere modificato a piacere dal programmatore per ottenere tante tipologie di tempi. | ||||||||||||||||||||||||||||
| PIC Genius permette di far ciò molto facilmente tramite la schermata relativa ai settaggi del Timer 0 agendo sul controllo evidenziato dalla freccia nella figura sottostante | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Inserendo il valore 6 nel registro TMR0 è possibile notare che alla riga 5 della tabella per un valore di divisione uguale a 32 si avrebbe una frequenza di 31250 Hz e si avrebbe un accesso alla routine di interrupt di 125 volte in un secondo | ||||||||||||||||||||||||||||
| In teoria decrementando una variabile il cui valore iniziale è uguale a 125, quando questà avrà valore 0 (zero) dovrebbe essere passato un secondo pari a 125*8000 (microsecondi) = 1000000 di microsecondi. (1 secondo) | ||||||||||||||||||||||||||||
| Nella realtà tutto questo non avviene poichè vi sono perdite di tempo che è necessario conteggiare per realizzare un timer molto preciso. | ||||||||||||||||||||||||||||
| Di questo problema ce ne occuperemo comunque più avanti. Cominciamo intanto a scrivere il codice. Inseriamo la spunta nella riga 5 della schermata indicando che vogliamo usare il divisore per 32 e chiudiamo la finestra. | ||||||||||||||||||||||||||||
| Si ritornerà nella finestra principale dell'editor dove si dovrà scrivere il codice per gestire il nostro TIMER | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
Nella colonna di sinistra si evidenzia che sono stati attivati i BIT GIE e T0IE del registro INTCON (interrupt). Nella colonna a destra dove vi è l'elenco delle routines, PIC Genius ne ha generato due automatiche riferite ai due BIT di prima : INTERRUPT_T0IE e INTERRUPT_GIE. Cliccando su ciascuna delle due si avrà la possibilità di scrivere del codice. |
||||||||||||||||||||||||||||
| Codice da
scrivere nella routine INTERRUPT_T0IE
if conta=0 then ; ogni 125 volte è passato un secondo conta=125 ; ripristina il valore iniziale della variabile a 125 inc (secondi)
; incrementa la variabile secondi endif dec(conta) |
||||||||||||||||||||||||||||
| Codice da scrivere nella routine INTERRUPT_GIE | ||||||||||||||||||||||||||||
|
TMR0=6 ; inizializza la variabile del TIMER0 |
||||||||||||||||||||||||||||
|
In pratica ogni qual volta si ha un overflow si ha accesso alla routine INTERRUPT_GIE all'interno della quale, il codice generato da PIC Genius è in grado di discriminare il tipo di INTERRUPT generato e di saltare alla routine corrispondente. Nel nostro esempio si salterà alla routine INTERRUPT_T0IE |
||||||||||||||||||||||||||||
| Le variabili da dichiarare per questo progetto saranno quindi : conta - secondi - minuti - ore. La variabile conta dovrà essere inizializzata al valore 125 | ||||||||||||||||||||||||||||
| Vediamo ora il codice da inserire nel MAINLOOP | ||||||||||||||||||||||||||||
|
;------------------------------------------------------------------ ; MAINLOOP ; ;------------------------------------------------------------------ conta=125 ; parte da 125 e viene decrementata ogni volta che entra nell'interrupt secondi=0 ; azzera la variabile secondi minuti=0 ; azzera la variabile minuti ore=0 ; azzera la variabile ore TMR0=6
; inizializza il tmr0 per ottenere i tempi esatti |
||||||||||||||||||||||||||||
| Bene il codice del timer è quasi teminato. Possiamo già provarlo direttamente con PIC Genius anche perchè non essendo stato collegato nessun display o utenza che ne legga il valore sarebbe molto difficile verificarne il funzionamento direttamente su scheda hardware. Lo si potrebbe testare con un altro simulatore, ma bisognerebbe inserire determinati breakpoint, attendere che la simulazione si fermi e verificare il contenuto delle variabili. | ||||||||||||||||||||||||||||
| Vediamo invece come provarlo con PIC Genius. | ||||||||||||||||||||||||||||
| Per prima cosa dobbiamo inserire un componente in almeno una delle porte del PIC perchè PIC Genius non permetterà altrimenti la compilazione del codice. | ||||||||||||||||||||||||||||
| Io ho inserito un semplice LED nella PORTB0 del micro | ||||||||||||||||||||||||||||
Avviare la compilazione tramite il
pulsante
o
tramite il pulsante
. |
||||||||||||||||||||||||||||
| Il primo pulsante avvia la procedura di compilazione e genera il codice ASM il quale potrà essere visionato nella realtiva finestra. | ||||||||||||||||||||||||||||
| Il secondo pulsante è molto più veloce perchè dopo la compilazione viene avviato direttamente il simulatore. | ||||||||||||||||||||||||||||
| Come dicevo prima, senza nessuna periferica di visualizzazione risulta impossibile verificare se il codice scritto aggiorna le variabili del tempo. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| La finestra del simulatore reale di PIC GENIUS mostra il corretto aggiornamento della variabile secondi tramite il MONITOR dei REGISTRI. Tramite questa funzionalità sarà possibile verificare il valore di tutti i registri (variabili comprese) del microcontrollore durante la simulazione ad alta velocità con aggioramento del dato ogni secondo. | ||||||||||||||||||||||||||||
| Per migliorare la funzionalità del codice, proviamo adesso ad inserire un semplice display LCD in modo da monitorare i valori in diretta. | ||||||||||||||||||||||||||||
| Inseriamo un display LCD utilizzando le seguenti porte : (l'uso è casuale e può essere modificato dal programmatore) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
Bene, adesso si dovrà scrivere il codice per visualizzare i dati delle variabili nel formato orario voluto.(le parti in verde si riferiscono alle istruzioni da inserire) |
||||||||||||||||||||||||||||
|
;------------------------------------------------------------------ ; MAINLOOP ; ;------------------------------------------------------------------ conta=125 secondi=0 minuti=0 ore=0 TMR0=6 ; inizializza il contatore del timer timer0_on ; attiva il timer0 interrupt_on ; attiva l'interrupt
clear_lcd
; cancella il display LCD |
||||||||||||||||||||||||||||
| Dopo aver inserito questo codice nel mainloop sarà possibile vedere finalmente girare il timer con il simulatore di PIC GENIUS |
|
|||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Ed ecco il funzionamento reale del circuito. In questo progetto è stato utilizzato un PIC 16F876, ma va benissimo anche il classico PIC 16F84. Il microcontrollore è montato su una demoboard autocostruita | ||||||||||||||||||||||||||||
| Usando un linguaggio ad alto livello non vi sarà mai una precisione assoluta dei tempi. Questo è dovuto al fatto che le istruzioni ad alto livello generano una o più istruzioni ASM per cui non è possibile conteggiare esattamente i tempi. PIC GENIUS permette però di calcolare esattamente i microsecondi di particolari eventi e di scrivere il codice tenendo conto di questi errori. In riferimento al nostro esempio ogni 1000000 di microsecondi teorici in realtà ne passano 1001765 circa. Per verificare quanto detto si dovrà agire in questo modo: | ||||||||||||||||||||||||||||
| Nella schermata del debugger inserire un breakpoint alla riga di programma 007A come nella figura sottostante | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Avviare la simulazione tramite il pulsante RUN (in alto a sinistra nella finestra). La simulazione si arresterà sulla linea dove è stato inserito il breakpoint (007A). Il contatore cicli visualizzerà ora il numero di cicli effettuati dall'inizio della simulazione. Questo valore non è da utilizzare per effettuare i nostri calcoli di aggiustamento perchè contiene un numero maggiore di istruzioni. | ||||||||||||||||||||||||||||
| E' necessario dare un altro colpo di RUN in modo che il contatore cicli conteggi i cicli effettuati tra un secondo (unità di tempo) ed un altro. | ||||||||||||||||||||||||||||
| La figura mostra che invece di 1000000 di cicli ne sono passati 1001765. Questo valore subisce alcune variazioni non significative se si continuasse il conteggio di secondo in secondo. | ||||||||||||||||||||||||||||
| Se dividiamo 1675/125 otteniamo il valore arrotondato 13. In pratica ogni volta che vi è una chiamata ad interrupt (ve ne sono 125 al minuto) vi è un ritardo di circa 13 istruzioni che bisognerebbe recuperare (13 microsecondi con clock a 4Mhz) Questo capita perchè è opportuno salvare alcuni registri fondamentali prima di eseguire la routine di interrupt. | ||||||||||||||||||||||||||||
| Determinato il ritardo da recuperare è necessario ora integrare il codice in modo da far pareggiare i conti. In partica si dovrà aggiungere un secondo ogni 9 minuti e 27 secondi passati. Vediamo come si sono ottenuti questi valori. Impostiamo la seguente equazione 1 : 1765 = x : 1000000. (se in un secondo sono passati 1765 microsecondi, quanti secondi occorrono affinchè si raggiunge un milione di microsecondi ovvero il secondo da aggiungere ?). Il risultato dell'equazione è pari a 566,57 secondi ovvero 9 minuti e 26,57 secondi arrotondati a 26. | ||||||||||||||||||||||||||||
| Vi sono diverse modalità per correggere tramite il software questo ritardo. Io ho adottato la seguente : | ||||||||||||||||||||||||||||
|
nuove variabili dichiarate : secondi1,minuti1,aggiusta |
||||||||||||||||||||||||||||
| ;------------------------------------------------------------------ ; INTERRUPT_T0IE ; ;------------------------------------------------------------------ if conta=0 then conta=125 inc(secondi) inc(secondi1) if secondi1=60 then secondi1=0 inc(minuti1) endif if minuti1=9 then if secondi=27 then inc(aggiusta) secondi1=0 minuti1=0 endif endif if secondi=60 then secondi=aggiusta
aggiusta=0 |
||||||||||||||||||||||||||||
| Le istruzioni in verde sono quelle relative al recupero del ritardo del tempo e sono state aggiunte nella routine del timer 0. | ||||||||||||||||||||||||||||
| Anche nel Mainloop si dovranno aggiungere alcune righe di codice : | ||||||||||||||||||||||||||||
|
;------------------------------------------------------------------ ; MAINLOOP ; ;------------------------------------------------------------------ conta=125 secondi=0 minuti=0 ore=0 stato=0 aggiusta=0 secondi1=0 minuti1=0 TMR0=6 ; inizializza il contatore del timer timer0_on ; attiva il timer0 interrupt_on ; attiva l'interrupt clear_lcd main: if stato=0 then write_string_xy_lcd(7,1,":") write_string_xy_lcd(10,1,":") else write_string_xy_lcd(7,1," ") write_string_xy_lcd(10,1," ") endif write_byte_xy_lcd(5,1,ore,2,2) write_byte_xy_lcd(8,1,minuti,2,2) write_byte_xy_lcd(11,1,secondi,2,2) delay_ms(600) goto main |
||||||||||||||||||||||||||||
|
Nonostante queste correzioni vi sarà la perdita di un ridotto numero di secondi nell'arco delle 24 ore (circa 7/8 secondi). L'unico modo per calcolare esattamente questo scarto è quello dinamico. In pratica si dovrà inserire un breakpoint nel momento in cui si attiva il timer0 ( PC = 003B) ed un breakpoint nella istruzione successiva all'incremento della variabile ore nella routine del INTERRUPT_TMR0. Avviare l'elaborazione ad altissima velocità e dopo aver superato il primo breakpoint attendere (1 ora se la simulazione è reale) che la simulazione si fermi al secondo breakpoint (è passata una ora). Calcolatrice alla mano si calcolerà che l'elaborazione è più lenta di 353072 microsecondi. Questo significa che ogni 3 ore circa si dovrà integrare ancora un secondo via software. |
||||||||||||||||||||||||||||
| Da ulteriori calcoli dovranno passare più di due giorni per integrare nuovamente un secondo non conteggiato. | ||||||||||||||||||||||||||||
| Questo codice si presta facilmente ad essere modificato per realizzare i più svariati progetti. Si possono inserire infatti dei pulsanti per modificare le variabili del tempo in modo da realizzare dei timer molto validi e precisi. | ||||||||||||||||||||||||||||
| Per poter simulare correttamente questo codice è necessario installare la versione 3.1 o superiore di PIC GENIUS | ||||||||||||||||||||||||||||
|
ATTENZIONE : tutte queste funzionalità sono operative nella versione registrata di PIC GENIUS. Il file HEX generato da PIC GENIUS invece risulta totalmente funzionante se inserito all'interno di un microcontrollore |
||||||||||||||||||||||||||||
|
[ HOME ] [ PROJECTS ] [ DOWNLOAD ] [ NEWS ] [ CONTACT ] [ LINKS ] |
||||||||||||||||||||||||||||