; abilitazione e attivazione interrupt a priorità bassa
bsf RCON,
IPEN ;selezionare
interrupt a priorità
bcf INTCON2,
TMR0IP ;selezionare
priorità bassa
bcf INTCON,T0IF
;clear flag per sicurezza
bsf INTCON,T0IE
;abilita interrupt di Timer0
bsf INTCON,GIEH
;attiva l' interrupt generale H
bsf INTCON,GIEL
;attiva l' interrupt generale L
TIMER0 con clock esterno
La sorgente del clock di conteggio può essere interna o
esterna; questo dipende dal valore del bit T0CS
nel registro T0CON. Portando questo
bit a 1 la sorgente del clock diventa il pin T0CKI, solitamente collegato
con RA4.
Se non viene utilizzato il prescaler, la sincronizzazione
tra l' ingresso T0CKI end il clock interno è possibile rispettando alcuni
limiti nel segnale di ingresso ( foglio dati par 13.1).
Se si utilizza il prescaler , il clock esterno è diviso dal prescaler
stesso, che ha una uscita simmetrica; il clock, diviso dal prescaler, è necessario
abbia un periodo di almeno 4 TSCLK diviso per il valore
impostato del prescaler.(parametri 40,41 e 42)
TIPS & TRICKS
Le tabelle seguenti riportano i limiti di tempo in funzione
del clock, del prescaler e della modalità a 8 o a 16 bit. Se non
diversamente indicato i tempi sono in millisecondi.
Xtal 4MHz - Tcyc 1 us
|
Prescaler
|
no
|
1:2
|
1:4
|
1:8
|
1:16
|
1:32
|
1:64
|
1:128
|
1:256
|
Bit
mode
|
8
|
0.255
|
0.512
|
1
|
2
|
4
|
8
|
16
|
32
|
64
|
16
|
65
|
131
|
262
|
524
|
1 s
|
2 s
|
4 s
|
8 s
|
16 s
|
Xtal 8 Mhz - Tcyc 500 ns
|
Prescaler
|
no
|
1:2
|
1:4
|
1:8
|
1:16
|
1:32
|
1:64
|
1:128
|
1:256
|
Bit
mode
|
8
|
0.127
|
0.255
|
0.512
|
1
|
2
|
4
|
8
|
16
|
32
|
16
|
32
|
65
|
131
|
262
|
524
|
1 s
|
2 s
|
4 s
|
8 s
|
Xtal 10 Mhz - Tcyc 400 ns
|
Prescaler
|
no
|
1:2
|
1:4
|
1:8
|
1:16
|
1:32
|
1:64
|
1:128
|
1:256
|
Bit
mode
|
8
|
0.102
|
0.204
|
0.409
|
0.819
|
1.6
|
3.2
|
6.5
|
13
|
26
|
16
|
26
|
52
|
105
|
209
|
419
|
839
|
1.6 s
|
3.3 s
|
6.7 s
|
Xtal 16 MHz - Tcyc
|
Prescaler
|
no
|
1:2
|
1:4
|
1:8
|
1:16
|
1:32
|
1:64
|
1:128
|
1:256
|
Bit
mode
|
8
|
0.064
|
0.127
|
0.255
|
0.512
|
1
|
2
|
4
|
8
|
16
|
16
|
16
|
32
|
65
|
131
|
262
|
524
|
1 s
|
2 s
|
4 s
|
Xtal 20 MHz - Tcyc 200 ns
|
Prescaler
|
no
|
1:2
|
1:4
|
1:8
|
1:16
|
1:32
|
1:64
|
1:128
|
1:256
|
Bit
mode
|
8
|
0.051
|
0.102
|
0.204
|
0.409
|
0.819
|
1.6
|
3.3
|
6.5
|
13
|
16
|
13
|
26
|
52
|
105
|
209
|
419
|
839
|
1.6 s
|
3.3 s
|
Xtal 40 MHz - Tcyc 100 ns
|
Prescaler
|
no
|
1:2
|
1:4
|
1:8
|
1:16
|
1:32
|
1:64
|
1:128
|
1:256
|
Bit
mode
|
8
|
0.025
|
0.051
|
0.102
|
0.204
|
0.409
|
0.819
|
1.6
|
3.3
|
6.5
|
16
|
6.5
|
13
|
26
|
52
|
105
|
209
|
419
|
839
|
1.6 s
|
I valori indicati sono approssimati. Lo scopo delle tabelle
non è quello di calcolare con precisione il tempo, ma quello di permettere
di valutare rapidamente le possibilità del timer ad un certo clock.
Ad esempio, volendo ottenere ritardi di 10 ms con un quarzo da 20MHz, è
possibile usare il Timer 0 in modalità a 8 bit con un prescaler di 256
oppure in modalità a 16 bit senza prescaler.
Ancora, volendo tempi di 1,8 secondi con il clock di 40MHz, se ne nota l'
impossibilità, in quanto il massimo ottenibile è 1,6 secondi.
La scelta del timer a 8 o a 16 bit, quando possibile in
entrambi i modi in relazione al tempo desiderato, va a preferenza sulla
modalità a 8 bit, dove è necessario ricaricare un solo registro. La
modalità a 16 bit, a parte la diversa estensione di tempo possibile,
permette una maggior raffinatezza sul valore ottenuto, ma richiede il
caricamento di due registri.
Il calcolo del tempo in secondi per la modalità ad 8 bit può
essere effettuato con la seguente espressione:
Time = (256 - InitTMR0 *
prescaler) / (XtalFreq/4)
Oppure, volendo il valore da inserire nei registri del timer
per ottenere un determinato tempo :
InitTMR0 = 256 - ( Time *
XtalFreq ) / ( 4* Prescaler)
Per la modalità a 16 bit, le formule diventano :
Time = (65535 - InitTMR0 *
Prescaler) / (XtalFreq/4)
InitTMR0 = 65535 - ( Time * XtalFreq ) / ( 4* Prescaler)
Alcuni esempi pratici
Su un PIC18F2321, operante a 8Mhz ,
si desidera generare cadenze a 1/10/100/1000 ms.
Dalle tabelle sopra la cosa risulta possibile attraverso l' uso del
prescaler e la modalità a 16 bit.
#define XTAL_FREQ 8000000
;crystal frequency
#define CLK (XTAL_FREQ / 4)
;crystal divided by four
#define T0PS 128
;selected prescaler
#define T0CS (CLK/T0PS)
;clock to timer 0
InitT0_1s = 65535 - ( 1 * CLK / T0PS)
InitT0_100ms = 65535 - ( 0.1 * CLK / T0PS)
InitT0_10ms = 65535 - ( 0.01 * CLK / T0PS)
InitT0_1ms = 65535 - ( 0.001 * CLK / T0PS)
A 8MHz di clock, il clock delle istruzioni CLK è 8 / 4 = 2
MHz, ovvero 500 ns per istruzione.
Con un prescaler di 128, il clock T0CS è 2000000 / 128 = 15625 Hz, ovvero
64 us per impulso.
Per ottenere il tempo di 1 secondo occorrono 1000000 / 64 = 15625 impulsi.
Con un conteggio a 16 bit, il numero massimo conteggiabile è 65535. La
predisposizione del valore da caricare nei registri del timer sarà 65535 -
15625 = 49910.
Infatti il timer conta a salire, per cui , per arrivare all' overflow a
partire dal valore pre caricato di 49910 saranno necessari proprio 15625
impulsi.
Un modo ragionevole per indicare all' Assembler i valori da caricare nei due
registri può essere il seguente :
t_1ms_h equ InitT0_1ms/256
t_1ms_l equ InitT0_1ms % 256
t_10ms_h equ InitT0_10ms/256
t_10ms_l equ InitT0_10ms % 256
t_100ms_h equ InitT0_100ms/256
t_100ms_l equ InitT0_100ms % 256
t_1sec_h equ InitT0_1s/256
t_1sec_l equ InitT0_1s % 256
Il caricamento dei registri :
t_1_ms movlw t_1ms_h
movwf TMR0H
movlw t_1ms_l
bra t_end
t_10_ms movlw t_10ms_h
movwf TMR0H
movlw t_10ms_l
bra t_end
t_100_ms movlw t_100ms_h
movwf TMR0H
movlw t_100ms_l
bra t_end
t_1_sec movlw t_1sec_h
movwf TMR0H
movlw t_1sec_l
t_end movwf TMR0L
e per l' inizializzazione e l' uso del timer :
movlw b'00000110'
; 1:128 prescale, internal clock, 16 bit mode, timer off
movwf T0CON
bcf INTCON,TMR0IF
; clear the overflow
bit
nop
btfsc INTCON,TMR0IF
bra $-2
; make sure overflow bit is clear
bsf T0CON,TMR0ON
; enable timer
return
Temporizzazioni di precisione
Nella gestione del tempo, nei casi in cui sia richiesta una
elevata precisione, occorre considerare che l' operazione di ricarica dei
registri di conteggio arresta il timer per due cicli e che una gestione
anche minima richiede alcune istruzioni dal momento in cui viene
intercettato l' overflow del contatore a quando vengono ricaricati i
registri. Quindi va tenuto conto anche di queste variabili.
In generale un timer viene spesso usato in continuo, ovvero
una volta raggiunto l' overflow, i registri di conteggio vengono ricaricati
e così via,
Un primo problema è quello relativo a questa manovra : i registri vengono
ricaricati dopo l' overflow, quindi, per una precisa cadenza, occorre
tenere conto dei cicli impiegati in questa fase.
Infatti il timer non si arresta mai se non viene stoppato con l' apposito
bit di T0CON , quindi va caricato non con un valore teorico, ma con un
esatto valore che compensi il tempo trascorso tra l' overflow e la ricarica
dei registri.
A questo va aggiunto che il Timer0 a seguito della ricarica
dei registri, si arresta per 3 cicli se non viene usato il prescaler e per 4
se viene usato. Inoltre , usando il prescaler, il suo contenuto viene
azzerato alla scrittura dei registri di TMR0 (attenzione a non fare
confusione : viene azzerato il contenuto già conteggiato, non il valore
impostato come fattore di predivisione).
La compensazione di questi tempi può essere difficoltosa
nel caso in cui si acceda al timer in polling, mentre se si utilizza l'
interrupt, la valutazione è più precisa. Anche in questo caso, però, è
opportuno prendere alcune precauzioni :
-
La gestione dell' interrupt di TMR0 dovrebbe
essere prioritaria sulle altre, in modo da semplificare la valutazione
delle istruzioni spese prima della ricarica dei registri. Questo può
essere ottenuto facilmente attribuendo la priorità alta al solo Timer0. Dovendo
attribuire priorità uguali anche ad altre sorgenti di interrupt, il
calcolo del tempo di latenza dell' overflow di TMR0 può diventare
difficile.
-
Non si deve disabilitare l' interrupt generale azzerando
GIE/GIEH=0 se è richiesta una valutazione precisa del tempo. Infatti,
se è necessario disattivare l'interrupt per scrivere in EEPROM, non è
possibile determinare esattamente il tempo in cui l'interrupt
resta disabilitato.
-
Ovviamente il tempo massimo di accesso e svolgimento
delle routine di interrupt deve essere sufficientemente minore del ciclo
dei timer, altrimenti si perde un overflow.
-
Inoltre, se si manda il processore in sleep, TMR0 viene
spento !!
Una possibile proposta per avere una cadenza di elevata
precisione è quella di arrestare il timer, caricare il valore calcolato e
poi riavviarlo.
Ad esempio, per un conteggio a 16 bit in cui la cadenza deve essere di 10000
istruzioni :
;aggiusta_T0 = ... ;numero di
ricarica del timer tenendo conto di tutte
;le variabili
Init_T0 ; = D'65536'-D'10000' + aggiusta_T0
bcf T0CON,TMR0ON
; timer stop
movlw high(Init_T0)
; carica valore calcolato
movwf TMR0H
; nel buffer alto
movlw low(Init_T0)
; scrive registro basso
movwf TMR0L
; e trasferisce anche TMR0H
bsf T0CON,TMR0ON
; restart timer
Sul WEB sono disponibili diversi programmi che permettono di
calcolare in modo automatico il valore corretto da caricare nei registri in
funzione del numero di cicli da compensare.