Tutorials - PIC peripherals

 

TIMER0

 


Il registro di conteggio - TMR0

Il conteggio a 8 bit TMR0 determina il periodo di overflow del timer.  Questo registro può essere letto e scritto da programma.

Partendo da 0, incrementa ad ogni impulso di clock fino a raggiungere il massimo valore (FFh). 

Utilizzando il clock interno, il contatore avanza ad ogni FOSC/4, che è il periodo di una istruzione.
Senza l' uso del prescaler si avrà quindi:

TIMER0_Overflow = ciclo_istruzione * 256

Ad esempio, con un clock di 8 MHz, il ciclo di una istruzione è dato da:

ciclo istruzione = 1 / (Fosc / 4) = 1 / (874) = 500 ns

Quindi, il massimo periodo, senza prescaler, è:

TIMER0_Overflow = ciclo_istruzione * 256 = 500 ns * 256 = 128 us

Se è richiesto un tempo maggiore, occorrerà utilizzare il prescaler, che riduce la frequenza di ingresso:

TIMER0_Overflow = ciclo_istruzione * 256 * prescaler

Ad esempio, con il prescaler programmato per un rapporto 1:4 si avrà:

TIMER0_Overflow = ciclo_istruzione * 256 * prescaler = 500 ns * 256 * 4 = 512 us

Il periodo massimo con il prescaler al rapporto maggiore sarà:

TIMER0_Overflow massimo = ciclo_istruzione * 256 * prescaler = 500 ns * 256 * 256 = 32760 us

Se occorrono tempi di intervento differenti entro questo range, la tecnica consiste nel pre caricare il registro TMR0 con un valore tale da generare l' overflow voluto. 
Questo è dovuto al fatto che il contatore avanza ad ogni impulso di clock a partire dal valore presente nel registro di conteggio TMR0. Se il valore è 0, occorreranno 256 impulsi per ottenere l' overflow; se viene caricato un valore diverso, l' overflow richiederà:

impulsi overflow = 256 - valore_precaricato_in_TMR0

In pratica, ad esempio, caricando 100 in TMR0, il conteggio partirà da questo valore e l' overflow sarà raggiunto dopo un numero di impulsi pari a:

impulsi overflow = 256 - valore_precaricato_in_TMR0 = 256 - 100 = 156 impulsi

Se utilizziamo il prescaler, ad esempio1:256, il periodo dell' overflow è:

TIMER0 Overflow = ciclo_istruzione * (256 - 100) * prescaler = 500 ns * 156 * 256 = 19968 us

Variando il valore caricato nel pre load del contatore e il rapporto del prescaler sarà possibile ottenere una gamma di tempi che vanno dal minimo al massimo possibile per quel dato clock. 


Pre carica di TMR0

Nel generare intervalli di tempo, l' operazione di pre carica di un valore su TMR0 è la prassi di uso del TIMER0. 
Se occorre una singola temporizzazione, TMR0 va caricato una sola volta. Però, comunemente, il timer viene usato per determinare cadenze ripetitive, quindi l' operazione di ricarica di TMR0 deve essere effettuata dopo ogni overflow. Infatti, nei PIC, il reload di TMR0 per un valore definito non è automatico; così, il conteggio riprende sempre da 0. Volendo partire da un valore specifico, occorrerà che sia il programma a provvedere.

Se è richiesta una elevata precisione nel conteggio del clock interno, ad esempio per determinare cadenze di tempo ben determinate e costanti, occorre considerare alcuni punti:

  • l' operazione di ricarica di TMR0 fa perdere 2 cicli di conteggio
     

  • inoltre, dal momento dell' overflow al momento in cui si ricarica il valore di offset in TMR0 trascorre un numero più o meno grande di cicli di istruzione. Questo accade perchè il timer, dopo l' overflow, non si arresta, ma riprende a contare da 00. 

Il fatto che l'operazione di ricarica del timer faccia perdere due cicli di conteggio, ovvero dia origine ad una temporizzazione 2 cicli più lunga, è poco importante se si tratta di ottenere una cadenza di tempo costante, ma non specificamente precisa. Ad esempi, il timing di refresh per un display a 7 segmenti, il lampeggio di un LED, il campionamento di un segnale generico, ecc. In questo caso, il periodo non sarà preciso, ma sarà costante e il suo errore trascurabile.
Invece, nel caso in cui il periodo ottenuto serva come base tempi ad un campionamento di eventi preciso, ad esempio la misura di una frequenza, è evidente che la precisione del timer diventa essenziale. Occorre che il periodo sia esattamente della durata richiesta ad ogni evento e questo dipende sia dalla precisone del clock conteggiato, sia dalla precisione di intervento del timer.
Un altro caso riguarda il conteggio del tempo (RTC, orologi, temporizzatori, ecc): qui ci si trova con la sommatoria dei singoli errori del periodo che influisce gravemente sull' errore generale del conteggio e che dipende certamente dalla precisione del clock, ma ancora di più dalla precisione di ogni singolo periodo.
Analogamente per quanto riguarda i cicli che intercorrono tra l' overflow e la ricarica del registro di conteggio.

Una prima soluzione è quella di usare il contatore free-running, ovvero evitare la pre carica del registro di conteggio, in modo che il timer conti tutti i 256 impulsi di clock per l' overflow. Questo metodo, però, è inadeguato per gran parte dei casi, a meno di utilizzare un oscillatore il cui valore di clock diviso per 256 e per l' eventuale prescaler origini un periodo utile per l'applicazione.

E' possibile, però, aggirare il problema con una semplice aggiunta di una costante pari ai cicli persi. 

preload_TMR0 = 256 -  costante

dove la  è pari al valore di preload a cui sono sottratti due cicli persi per la ricarica e un numero di cicli pari a quelli impiegati tra l' overflow e la ricarica stessa.
Vari Timer Calculator disponibili in rete permetto di modificare il preload con una quantità desiderata di impulsi.

Nel caso in cui si conti un clock esterno, valgono analoghe considerazioni, tenendo presente che, se il numero di impulsi del clock interno è determinabile con precisione, il numero degli impulsi esterni che possono arrivare dopo l' overflow può non essere facilmente quantificabile.

Inoltre va considerato che l' uso del prescaler può ridurre la precisione complessiva del conteggio. Infatti:


La scrittura del registro di conteggio cancella il contenuto del prescaler. 
Nel caso siano richiesti tempi o conteggi di precisione, l' uso del prescaler è, quindi, poco consigliabile (il contenuto del prescaler non è accessibile da programma nè in lettura, nè in scrittura).

Anche l' operazione di scambiare il precaler con il WDT ne cancella il contenuto.


Quale periodo è possibile con Timer0?

Come abbiamo visto, le possibilità di temporizzazione di TIMER0 dipendono:

  • dal clock del sistema, Fosc

  • dalle dimensioni di TMR0 (8 o 16 bit)

Vediamo alcune tabelle indicative che riportano i possibili periodi ottenibili con TIMER0 al variare del clock e dell' ampiezza del TMR0.

Fosc = 4 MHz  , tcyc = 1 us  -  tempi in  us se non diversamente indicato
Prescaler 1:1 1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256
8 bit 256 512 1024 2048 4096  8192  16384 32768 65536
16 bit 65536 131072 262144 524288 1,048576 s 2,092152 s 4,194304 s 8,388608 s 16,77216 s

Fosc = 8 MHz , tcyc = 500 ns  -  tempi in  us se non diversamente indicato
Prescaler 1:1 1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256
8 bit 128 256 500 1024 2048 4096 8192 16384 32768
16 bit

32768

65536

131072

262144 524288 1,048576 s 2,092152 s 4,194304 s 8,388608 s

Fosc = 16 MHz , tcyc = 250 ns  -  tempi in  us se non diversamente indicato
Prescaler 1:1 1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256
8 bit 64 128 256 500 1024 2048 4096 8192 16384
16 bit 16384

32768

65536

131072

262144 524288 1,048576 s 2,092152 s 4,194304 s

Fosc = 20 MHz , tcyc = 200 ns  -  tempi in  us se non diversamente indicato
Prescaler 1:1 1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256
8 bit 51,2 102,4 204,8 409,6 819,20 16384,4 3276,8 6553,6 13107,2
16 bit 13107,2 26214,4 52428,8 104857,6 209715,2 419430,4 838860,8 1.677216 s 3.3554432 s

Fosc = 40 MHz , tcyc = 100 ns  -  tempi in  us se non diversamente indicato
Prescaler 1:1 1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256
8 bit 25,1 51,2 102,4 204,8 409,6 819,20 16384,4 3276,8 6553,6
16 bit 6553,6 13107,2 26214,4 52428,8 104857,6 209715,2 419430,4 838860,8 1.677216 s

Se utilizziamo quarzi multipli di 2, otteniamo valori interi in varie condizioni:

Fosc = 32768 Hz , tcyc = 976,56 us

Prescaler 1:1 1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256
8 bit 31,25 ms 62,5 ms 125 ms 250 ms 500 ms 1 s 2 s 4 s 8 s
16 bit 8 s 16 s 32 s 64 s 128 s 256 s 512 s 1024 s 2048 s

Fosc = 4,096 MHz , tcyc = 1024 ns   - 
tempi in  us se non diversamente indicato
Prescaler 1:1 1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256
8 bit 250 500 1000 2000 4000 8000 16000 32000 64000
16 bit 64 ms 128 ms 256 ms 512 ms 1,024 s 2,048 s 4,096 s 8,192 s 16,384 s

Fosc = 32,768 MHz , tcyc = 156,3 ns  -  tempi in  us se non diversamente indicato
Prescaler 1:1 1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256
8 bit 31,25 62,5 125 256 500 1000 2000 4000 8000
16 bit 8000 16000 32000 64000 0,128 s 0,256 s 0,512 s 1,024 s 2,048 s

Queste tabelle possono essere utili per avere una idea di quali tempi sono ottenibili con TIMER0.
Così, con un clock da 4MHz e TMR0 a 8 bit, sarà possibile ottenere un tempo massimo di 65 ms, usando il prescaler 1:256. Se abbiamo a disposizione una versione di TIMER0 a 16 bit, il periodo sarà esteso a 16 s.

Qualsiasi valore intermedio si potrà ottenere con una pre carica del TMR0.

Invece, per ottenere tempi maggiori, si eseguiranno un sufficiente numero di cicli di durata minore. Ad esempio, 1s si potrà ottenere conteggiando 20 volte un ciclo da 50ms.

Conteggi di elevata precisione si possono ottenere con metodi più o meno complicati, come l' algoritmo Bresenham.


Va comunque ricordato che 

la precisione ottenibile non può evidentemente superare quella dell' oscillatore e che è funzione della precisione dei componenti impiegati e della temperatura ambiente.

In questo senso, un oscillatore quarzato sarà preferibile all' oscillatore RC interno nelle applicazioni in cui la precisione delle temporizzazioni è determinante, mentre potrà essere irrilevante in applicazioni in cui la precisione non è determinante per il funzionamento..


Un esempio di calcolo

Vogliamo ottenere un overflow ogni 10 ms con un oscillatore a 4MHz.

Il ciclo di istruzione, per un clock a 4 MHz, è :

ciclo_istruzione = 1 / (FOSC/4) =  1 us

Se dividiamo il clock con un prescaler 1:64, otteniamo un periodo di:

 periodo = ciclo_istruzione * 64 =  64 us

Se vogliamo ottenere 10 ms di overflow occorre un conteggio di:

  10ms / 128 us = 156,25 impulsi

Dobbiamo scegliere un valore intero, quindi 156.  Ovvero occorrerà una pre carica in TMR0 di 256 - 156 = 100.

In effetti:

TIMER0 Overflow = 1uss * (256 - 156) * 64 = 1 us * 100 * 64 = 9,984

che equivalgono a 10 ms con l' approssimazione dell' 0.16 %. 

 

Una formula generale sarà:

TIMER0_Overflow = ciclo_istruzione * (256 - TMR0) * prescaler 

oppure:

TIMER0_Overflow = ( (256 - TMR0) * prescaler ) / (FOSC / 4)


Se occorrono tempi precisi, sarà necessario utilizzare un quarzo con frequenza multipla di 2 (dato che il prescaler divide per potenze di 2).
Ad esempio, con un oscillatore a 4096000 Hz (FOSC/4 = 1,024 MHz), con un pre load di 96, sempre con prescaler 1:64, il tempo di overflow sarà:

TIMER0_Overflow = ciclo_istruzione * (256 - 96) * prescaler = (1/1024) * 160 * 64 = 10 ms

Volendo identificare la frequenza di overflow del timer, il calcolo è semplice:

foverflow = 1 / TIMER0_Overflow

Così, per un periodo di 10 ms, la frequenza corrispondente è 100 Hz.

Non è assolutamente necessario effettuare questi conteggi a mano, dato che in rete sono disponibili numerosi calcolatori, sia on line che downloadabili, per effettuare calcoli precisi, considerando anche numerose opzioni. 


 

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 09/04/13.