ELEMANIA
PIC16F690 - Timer0
Timer0

Timer0 è un timer ad 8 bit (conta cioè da 0 a 255), con prescaler a 8 bit (condiviso col Watchdog Timer). A Timer0 corrisponde il registro speciale TMR0, il cui contenuto mostra il valore corrente del conteggio.

La tabella seguente mostra in sintesi i registri associati al Timer0 e i relativi bit:

Registri di Timer0

 

OPTION_REG

Le principali impostazioni di controllo di Timer0 dipendono dal registro OPTION_REG:

I bit 6 e 7 non sono utilizzati per il timer e dunque al momento non ci interessano. Per quanto riguarda gli altri, il significato è il seguente:

  1. T0CS seleziona la sorgente degli impulsi da contare:
    • 1: un segnale generato da un circuito esterno può essere applicato al pin T0CKI
    • 0: segnale proveniente dal clock del PIC con frequenza divisa per 4 (Fosc/4)

    Se si desidera contare degli eventi (passaggio di oggetti, pressioni di un pulsante, segnali di allarme, ecc.) l'ingresso del timer va configurato come esterno (TOCS=1). Se, invece, desideriamo avere una base dei tempi per cui, dopo un certo numero di millisecondi, dobbiamo fare una certa cosa, allora il modulo Timer0 va selezionato per l'incremento automatico legato al ciclo di clock del microcontroller (TOCS=0). Per sapere il numero dei conteggi, in entrambi i casi, basta leggere il contenuto del registro TMR0.


  2. T0SE determina se l'incremento di TMR0 debba avvenire sul fronte di discesa (1) o di salita (0), dell'impulso proveniente dal pin T0CKI;

  3. PSA assegna il prescaler al Timer0 (1) oppure al Watchdog timer (0);

  4. PS2,PS1, PS0 selezionano il rapporto di divisione del prescaler (assegnando il prescaler al WDT, faremo in modo che, il segnale che andrà ad incrementare il TMR0, non venga diviso, cioè in pratica equivale a impostare un prescaler 1:1).

NOTA:

All'avvio del PIC o dopo un reset, il registro OPTION_REG sarà impostato con tutti i bit a 1.
Con questa impostazione, il Timer0 è abilitato come contatore ed il registro TMR0 verrà incrementato dagli impulsi che arrivano sul pin T0CKI, su fronte di discesa, senza prescaler (1:1), il quale sarà assegnato al WDT, con rapporto 1:128.

Prescaler

Il prescaler di Timer0 non è leggibile o scrivibile e, come abbiamo visto,  può anche essere destinato al Watch Dog Timer (WDT): essendo in comune tra i due, dovremo scegliere noi la sua assegnazione, impostando il bit PSA nel registro OPTION_REG. Un'altra cosa molto importante da sapere è che, qualsiasi istruzione che si riferisce al registro TMR0 o al WDT, azzera il conteggio contenuto nel prescaler, che ripartirà a contare da zero. Per questo motivo, si deve prestare attenzione quando, nel corso del programma, si vuole assegnare il prescaler da una all'altra periferica e viceversa.

La tabella seguente mostra come i bit PS2, PS1 e PS0 determinano il rapporto di divisione del prescaler (i rapporti impostati per il Watch Dog Timer sono differenti):

 PS(2:0) (Prescaler rate Select)
 PS2 PS1 PS0    TMR0 
  0   0   0  =  1:2   
  0   0   1  =  1:4    
  0   1   0  =  1:8 
  0   1   1  =  1:16 
  1   0   0  =  1:32
  1   0   1  =  1:64
  1   1   0  =  1:128
  1   1   1  =  1:256 

Facciamo un esempio pratico: supponiamo di usare come sorgente il clock del PIC (TOCS=0) con frequenza Fosc = 4MHz, di aver assegnato il Prescaler al Timer0 (PSA=1) e di aver impostato il prescaler a 32 (valore binario 100 sui bit PSx).

In generale la frequenza con cui il Timer0 si incrementa è pari a:

dove FOSC è la frequenza di clock del sistema e PS è il valore del prescaler, cioè nel nostro caso abbiamo (4MHz/4)/32 = 31250 Hz. Si osservi che la frequenza utilizzata è quella del clock (Fosc) divisa per 4, poiché il timer viene incrementato ad ogni ciclo di istruzione, cioè ogni 4 periodi del clock.

Alla frequenza di incremento precedente corrisponde un periodo (1/f = 1/31250) pari a 32 µs.

 

Scelta del valore del prescaler

Quando il registro TIMER0 va a 0 (ovvero passa da 255 a 0 andando in overflow e ricominciando il conteggio daccapo), viene settato il bit T0IF nel registro INTCON, generando un interrupt (se abilitato con il bit T0IE).

Consideriamo di nuovo l'esempio precedente di un timer con frequenza di clock 4MHz e prescaler 32. Il conteggio si azzera ogni 256 periodi, cioè ogni 256*32 µs = 8,192 ms.

Supponiamo di aver bisogno di generare un interrupt ogni 3 ms. In teoria potremmo agire sulla frequenza di clock del sistema, ma in questo modo cambieremmo la velocità di esecuzione di tutte le istruzioni del PIC (certo non una buona scelta). In alternativa potremmo cambiare il prescaler PS in modo da cercare di ottenere un azzeramento del contatore ogni 3 ms. E' facile vedere però che non esiste nessuna frequenza di prescaler che (con il clock a 4 MHz dato) permette di avere un interrupt ogni 3 ms.

Infatti essendo FOSC la frequenza di oscillazione del sistema e PS il valore del prescaler, abbiamo:

Tfine conteggio = 256 * Periodo = 256 * PS/(Fosc/4)

da cui posso ricavare il valore del prescaler PS

PS = Tfine conteggio /256 * (Fosc/4)

cioè nel nostro caso

PS =  3ms / 256 * (4MHz/4) = 11,72

E' evidente che questo valore di prescaler non è disponibile.

Possiamo allora ricorrere a un piccolo "trucco". Basta semplicemente fare in modo che Timer0 non inizi il suo conteggio da zero, ma da un valore che andiamo a determinare. Calcoliamoci anzitutto quanti cicli di conteggio sono necessari, con il clock dato a 4MHz, per generare 3ms. Poiché 256 conteggi avvengono in 8,192 ms, usando una semplice proporzione, abbiamo molto rapidamente che:

x : 3 ms = 256 : 8,192ms da cui x = 3/8,192 * 256 =  93,8

Arrotondiamo il valore precedente all'intero più vicino (94) e abbiamo che, per ottenere un interrupt da Timer0 ogni 3ms, è necessario precaricare il contatore col valore 256-94 = 162. Una volta generato l’interrupt reimposteremo di nuovo il Timer0 a 94, e così ogni volta, ad ogni interrupt.

Per semplificare i calcoli consigliamo il software gratuito PicTimer il quale effettua il calcolo del valore migliore da assegnare al Prescaler ed al Timer0 (8 bit) in maniera tale da ottenere o avvicinarsi al tempo di interrupt scelto, in base alla frequenza dell’oscillatore.

Un'altra tecnica consiste nel fissare un valore di prescaler e un valore totale di conteggio "ragionevoli" e quindi contare un certo numero di interrupt fino ad ottenere il valore di tempo desiderato. Supponiamo per esempio di voler ottenere un tempo di 2 secondi. Si tratta di un valore piuttosto elevato e, usando un clock FOSC = 4 MHz non esiste certamente nessun valore di prescaler PS che permette di ottenerlo.

Possiamo allora procedere nel seguente modo. Fissiamo ad esempio il prescaler a 32 (PS = 32) e facciamo eseguire il conteggio 250 volte invece di 256 (la ragione per cui abbiamo scelto questo valore sarà più chiara fra poco). In questo modo viene generato un interrupt ogni:

Tfine conteggio =  250 * 32/(4MHz/4) = 8 ms

Dunque il nostro timer genera un interrupt ogni 8ms. Poiché noi vogliamo invece un tempo di 2s, sarà sufficiente contare (all'interno della routine di servizio dell'interrupt) 2/8m = 250 volte. In pratica basta una variabile contatore che viene incrementata a ogni interrupt: quando questa variabile raggiunge il valore 250 (nel nostro esempio), si potrà azzerare la variabile stessa ed eseguire le operazioni che si vogliono compiere ogni 2 secondi.

Come si può notare è stato scelto di contare fino a 250 (invece di 256) in modo da ottenere un valore esatto (senza virgola) nel risultato finale.

 

precedente - successiva

Sito realizzato in base al template offerto da

http://www.graphixmania.it