Tutorial → PIC18 → Assembly
→ Timer0

Questa pagina descrive l'uso di Timer0, uno dei numerosi contatori
hardware presenti all'interno del PIC18. Timer0 semplicemente conta quanti sono i fronti
del segnale applicato al suo ingresso, senza l'intervento del processore.
per chi ha studiato un poco di elettronica digitale, nulla cambia rispetto
ad un contatore up presettabile, cioè nel quale è possibile impostare il
valore iniziale.
Qualche esempio di possibile utilizzo:
- Conoscere quanti giri ha fatto una ruota: in questo caso
è sufficiente contare gli impulsi generati da un finecorsa
collegato direttamente in ingresso a Timer0
- Misurare la velocità di una ruota: in questo caso è sufficiente
contare gli impulsi per un secondo
- Misurare il passare del tempo, se si conosce la frequenza del
segnale di ingresso
- Impostare la velocità di rotazione di un motore pass-passo
La struttura di Timer0
Il modo più semplice per comprenderne il funzionamento di Timer0 è leggere
il suo schema, presente sui fogli tecnici e qui riportato in una versione
semplificata

Qualche osservazione sulla struttura di Timer0:
- Può utilizzare, in alternativa, un clock esterno oppure un clock
derivato da quello del processore (Fosc/4). Nel primo caso si comporta
da contatore (il suo contenuto conta il numero di impulsi in
ingresso), nel secondo da timer (il suo contenuto è
proporzionale al passare del tempo). Il processore può leggere e scrivere il valore interno del contatore
attraverso i due registri
TMR0L e TMR0H
- Può funzionare sia a 8 che a 16 bit (lo schema è relativo alla
modalità a 16 bit)
- É associato ad un prescaler (cioè un divisore di frequenza).
Questo permette di generare intervalli
di tempo anche molto lunghi, dividendo la frequenza del clock
- Al termine del conteggio (passaggio da 0xFFFF a 0) può
generare un'interruzione, settando il flag TMR0IF (TiMeR0
Interrupt Flag)
Facciamo lampeggiare un LED
L'esempio che trovate a fondo pagina utilizza Timer0 in modalità 16 bit per generare un'interruzione
in compatibility mode ad intervalli regolari. All'interno della ISR viene cambiato ad ogni esecuzione lo stato di un LED, facendolo
di conseguenza
lampeggiare.
L'hardware è costituito semplicemente da un LED (e relativa
resistenza in serie) connesso tra RC0 e massa
Esaminiamo il codice:
Per accendere il LED è necessario configurare PORTC come uscita:
clrf TRISC ; PORTC come uscita, tutti gli 8 pin
Più complessa la configurazione di Timer0, fatta utilizzando alcuni dei
flag del registro T0CON (Timer0 CONtrol register). Occorre infatti:
- Impostare il funzionamento a 16 bit (conteggio da 0 a 65 535)
- Scegliere il clock di ingresso. Nell'esempio è stato utilizzato il
clock del processore Fosc / 4 (quindi: 1 MHz / 4 = 250 kHz)
- Disattivare il prescaler, per collegare direttamente il clock
all'ingresso del contatore
- Impostare Timer0 per generare una interruzione al termine del
conteggio (nota 1)
- E, ovviamente, completata la configurazione, accenderlo.
Il codice di configurazione di Timer0:
bcf T0CON, T08BIT ; Configura Timer0 per funzionare a
16 bit
bcf T0CON, T0CS ; Configura il clock di Timer0 interno (250 kHz)
bsf T0CON, PSA ; Disattivo il prescaler
bsf INTCON, TMR0IE ; Abilito Timer0 a generare interruzioni
bsf T0CON, TMR0ON ; "Accendo" Timer0
Infine occorre abilitare globalmente le interruzioni:
bsf INTCON, GIE ; Abilito la CPU a ricevere interruzioni
Il loop principale, come spesso succede, non fa nulla:
repeat
nop ; non fa nulla (No OPeration), per sempre
nop
bra repeat
La ISR è semplice: dopo aver verificato attraverso l'apposito flag che
l'interruzione è stata effettivamente generata da Timer0, cambia lo stato del LED:
ISR CODE 0x0008
btfsc INTCON, TMR0IF ; Interruzione da Timer0 ?
bra GestioneTimer0 ; Esegue il codice corrispondente
retfie FAST ; Nessuna interrupt riconosciuta... Indizio di un errore?
GestioneTimer0 ; Interrupt da Timer0
btg LATC, 0 ; Fa lampeggiare il LED, invertendone lo stato
bcf INTCON, TMR0IF ; Azzera il flag che segnala l'interrupt generato da
Timer0
retfie FAST ; Torna ad eseguire il codice principale
Quanto vale la frequenza di lampeggio del LED?
- la frequenza del clock di Timer0 è pari ad un quarto della frequenza
base del PIC18, in questo esempio f = 1 MHz / 4 = 250 kHz. Un
impulso di clock ha quindi durata 4 µs
- Il contatore conta da 0 fino a 65 535
(216 - 1), per un totale di 65 536 impulsi
Quindi viene generato un interrupt ogni 4 µs · 65 535 ≈ 0,262 s;
di conseguenza il LED rimane circa ¼ di secondo accesso ed ¼ di
secondo spento, lampeggiando con una frequenza di poco più di 2 Hz
Un altro esempio: un motore passo-passo
Questo codice, come sempre disponibile a fondo pagina, è molto simile
al precedente. Esso è stato scritto pensando al pilotaggio di un
motore passo-passo, collegato al
PIC18 attraverso un driver che in ingresso accetta due segnali:
- STEP: ogni impulso fa avanzare il motore di un passo, per esempio
1/200 di giro
- DIR: imposta il verso di rotazione
Non è rilevante il tipo di driver utilizzato. Nella foto di apertura
è mostrato un DRV8825 disponibile per pochissimi Euro su molti siti di
commercio elettronico; esso è collegato ad un piccolo motore bipolare
di recupero.
ATTENZIONE - Un motore richiede tensioni
elevate per funzionare (nota 3), distruttive per quasi tutti i componenti
elettronici. Quindi:
- Prima di procedere, scollegare l'alimentazione del motore (non
semplicemente spegnere l'alimentatore)
- Realizzare tutti i collegamenti elettrici con il massimo ordine
(colori!)
- Nel caso di dubbi, anche piccoli, fermare l'attività, chiedere e chiarire le
idee
- Controllare e ricontrollare i collegamenti prima di procedere al
collegamento dell'alimentazione
- Mai staccare il motore con alimentazione collegata
Lo schema dettagliato è per esempio
disponibile su questo sito.
Due le differenze significative nel codice rispetto al precedente:
- Il contatore inizia a contare non da 0, ma da un valore predefinito
(0xF63C nell'esempio, cioè 63 029). Questo significa che
l'interruzione è generata dopo un tempo più breve (sempre nell'esempio:
circa 10 ms, cioè circa 2500 colpi di clock). Per calcolare questo
numero sono disponibili numerosi calcolatori on-line (cercate qualcosa
tipo pic timer0 calculator) oppure si può provare per
tentativi. Questo è l'oggetto del secondo esercizio
- Dopo un certo numero di interruzioni, 100 nell'esempio, Timer0
viene "spento" e quindi il motore si ferma
Il codice
Esercizi
- Il prescaler permette di ridurre la frequenza del clock di 2, 4,
8..., 256 volte. Scrivere il codice per ridurre la frequenza di
lampeggio del LED attraverso una modifica del prescaler (suggerimento:
leggere il significato dei quattro bit meno significativi di REGISTER
12-1: T0CON: TIMER0 CONTROL REGISTER
- Il valore di inizio del conteggio può essere impostato dal PIC18
scrivendo un numero a 16 bit nei due registri a 8 bit
TMR0L e TMR0H. Di fatto questo riduce
il tempo necessario a Timer0 per generare un interrupt. Modificare il
codice della ISR per raddoppiare la frequenza di lampeggio del LED,
iniziando il conteggio da 0x7FFF anziché, automaticamente, da 0x0000 (nota
2)
- Timer0 permette di impostare la priorità delle interruzioni. Scrivere il codice corrispondente dopo aver individuato sui
fogli tecnici il flag corrispondente (suggerimento: REGISTER 9-2:
INTCON2: INTERRUPT CONTROL 2 REGISTER)
- Come tutti i contatori binari, raggiunto il valore massimo, il
conteggio ricomincia automaticamente da zero
- Per garantire il corretto funzionamento di Timer0 è necessario prima
scrivere TMR0H e
successivamente TMR0L
- Un motore può generare tensioni molto più elevate di quella di
alimentazione, anche centinaia di volt (comunque non pericolose per le
persone se il motore è di piccole dimensioni)
Data di creazione di questa pagina: maggio 2016
Ultima modifica: 25 aprile 2018