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:
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.
|