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 :  
 

TABELLA DEL TIMER0

       
   

DIVISORE

FREQUENZA

VOLTE

2 1000000 / 2 = 500000 1953,13
4 1000000 / 4 = 250000 976,56
8 1000000 / 8 = 125000 488,28
16 1000000 / 16 = 62500 244,14
32 1000000 / 32 = 31250 122,07
64 1000000 / 64 = 15625 61,04
128 1000000 / 128 = 7812 30,52
256 1000000 / 256 = 3906 15,26
 
       
   

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

 
 

LA GESTIONE GRAFICA DEL TIMER0

       
   

 
       
    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  
 

LA FINESTRA DELL' EDITOR

   

 

 
   

 
       
    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
  if secondi=60 then      ; se sono passati 60 secondi.....
    secondi=0
    inc (minuti)          ; incrementa i minuti
    if minuti=60 then     ; se sono passati 60 minuti.......
      minuti=0
      inc (ore)           ; incrementa le ore
      if ore=24 then     
        ore=0
        
      endif
    endif
  endif

endif

dec(conta)

 
       
       
       
    Codice da scrivere nella routine INTERRUPT_GIE

TMR0=6 ; inizializza la variabile del TIMER0

 
       
    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
timer0_on
interrupt_on


main:





goto main

 
       
    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 ASM  o tramite il pulsante SIMULATORE (funzionante solo nella versione completa di PIC Genius) .  
   

Il primo pulsante avvia la procedura di compilazione e genera il codice ASM il quale potrà essere visionato nella relativa finestra dalla quale si potrà poi avviare il simulatore. Questa procedura è obbligata utilizzando la versione FREEWARE di PIC Genius

 
   

Il secondo pulsante è molto più veloce perchè effettua la compilazione internamente e subito dopo avvia 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 DI SIMULAZIONE

       
   

 
       
   

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 aggiornamento 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)  
 

LA FINESTRA DI SETUP DEL DISPLAY LCD

       
   

 
       
   

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
write_string_xy_lcd(7,1,":")
write_string_xy_lcd(10,1,":")


main:


write_byte_xy_lcd(5,1,ore,2,2)     ; stampa la variabile ore
write_byte_xy_lcd(8,1,minuti,2,2)  ; stampa la variabile minuti
write_byte_xy_lcd(11,1,secondi,2,2); stampa la variabile secondi

delay_ms(600)                      ; ritardo per evitare un aggiornamento continuo del display LCD in fase di simulazione






goto main
 

 
 

LA SIMULAZIONE DEL CODICE

   

Dopo aver inserito questo codice nel mainloop sarà possibile vedere finalmente girare il timer con il simulatore di PIC GENIUS

   
       
 

LA PROVA DEL CODICE SU BREADBOARD

       
   

 
       
    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 1001875 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  
 

LA FINESTRA DEL DEBUGGER

       
   

 
       
    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 1001875. Questo valore subisce alcune variazioni non significative se si continuasse il conteggio di secondo in secondo.  
    Se dividiamo 1875/125 otteniamo il valore arrotondato 15. In pratica ogni volta che vi è una chiamata ad interrupt (ve ne sono 125 al minuto) vi è un ritardo di circa 15 istruzioni che bisognerebbe recuperare (15 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 pratica si dovrà aggiungere un secondo ogni 9 minuti e 27 secondi passati. Vediamo come si sono ottenuti questi valori. Impostiamo la seguente equazione  1 : 1875 = x : 1000000. (se in un secondo sono passati 1875 microsecondi, quanti secondi occorrono affinchè si raggiunge un milione di microsecondi  ovvero il secondo da aggiungere ?). Il risultato dell'equazione è pari a 533,3 secondi ovvero 8 minuti e 53 secondi. Possiamo benissimo arrotondare a 9 minuti.  
    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)
  if secondi=60 then
    secondi=0
    inc(minuti)
    inc(minuti1)
    if minuti1=9 then
      inc(secondi)
      if secondi>59 then
        secondi=secondi-60
      endif
      minuti1=0
    endif

    if minuti=60 then
      minuti=0
      inc(ore)
      if ore=24 then
        ore=0
      endif
    endif
  endif
endif

dec(conta)
 
       
    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
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
 
       
    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 4.5 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 ]   [ RIVISTE ][ PROGETTI ]   [ DOWNLOAD ]   [ VIDEO ]   [ CONTATTI ]   [ LINKS ]