Caricare documenti e articoli online 
INFtub.com è un sito progettato per cercare i documenti in vari tipi di file e il caricamento di articoli online.


 
Non ricordi la password?  ››  Iscriviti gratis
 

I Timer

informatica



I Timer


L'8051 classico dispone di due timer, che possono essere configurati, controllati e letti in maniera indipendente. I timer dell'8051 hanno tre funzioni generali:

  • Tenere traccia del tempo totale trascorso e/o calcolare il tempo trascorso tra due eventi,
  • Contare il numero degli eventi o
  • Generare il baud rate per la porta seriale.

I tre modi di usare un timer verranno discussi separatamente. I primi due saranno affrontati in questo capitolo mentre l'uso del timer come generatore di baud rate verra' discusso nel capitolo relativo alla porta seriale.

Come fa un timer a contare?

Come fa un timer a contare? La risposta e' semplice. Esso conta sempre incrementando il suo valore. Non importra se viene usato come timer o come contatore o come generatore di baud rate. E' sempre incrementato dal microcontrollore.

Suggerimentio per il programmatore: Alcuni derivati dell'8051 consentono al programma di configurare il timer in maniera tale che possa contare sia in avanti che indietro. Cio' e' al di fuori dello scopo di questo corso che e' orientato all'8051 standard. Parliamo di questa possibilita' nel caso in cui foste assolutamente nella necessita' di avere un timer che conta all'indietro e quindi sappiate che esistono dei microcontrollori derivati dall'8051 che sono in grado di 121i84b farlo.



USARE UN TIMER PER MISURARE UN TEMPO

Ovviamente uno degli usi primari dei timer e' quello di misurare il tempo. Parleremo prima di questo uso e poi di quello relativo al conteggio di eventi. Quando un timer e' usato per misurare il tempo e' anche chiamato "interval timer" poiche' esso sta misurando l'intervallo temporale tra due eventi.


Quanto tempo impiega un timer a contare?

Quando il timer e' nel modo "interval timer" ed e' correttamente configurato, esso viene incrementato di uno ogni ciclo macchina, ovvero 12 impulsi di clock.
Percio' un timer attivo sara incrementato:


921.583 volte al secondo. A differenza delle istruzioni che hanno durata variabile, il ciclo di un timer ha durata fissa; uno impulso per ciclo macchina. Se un timer ha contato da 0 a 50.000 possiamo calcolare:


che sono trascorsi 0,0542 secondi .

Ovviamente non e' molto utilie sapere che sono trascorsi 0,0542 secondi. Se voi voleste far partire un evento ogni secondo dovreste aspettare il conteggio del timer da 0 a 50.000 per 18,45 volte. Come si puo' aspettare per un tempo non intero? Non e' possibile. Allora proviamo a fare un calcolo imporatnte.

Supponiamo di voler sapere quante volte il timer viene incrementato ogni 0,05 secondi. Possiamo fare questo semplice calcolo:


Il risultato ci dice che impieghiamo 0,05 secondi (un ventesimo di secondo) per contare da 0 a 46.079. Piu' precisamente il tempo trascorso e' di 0,49999837 secondi, cio' vuol dire che mancano 0,000000163 secondi all'appello, comunque e' abbastanza preciso anche per i lavori commissionati dal governo. Considerate che se costruite un orologio basato sull'8051, con tali ipotesi, ammesso che il quarzo sia perfetto, avrete un secondo in anticipo ogni due mesi. Beh, io credo che cio' sia accurato per la maggior parte delle applicazioni. Magari il mio orologio andasse avanti soltanto di un secondo ogni due mesi!

Una volta stabilito che esso impiega un ventesimo di secondo e vogliamo eseguire un evento ogni secondo sara' sufficiente che il timer conti da 0 a 46.079 per venti volte; a questo punto eseguite le azioni richieste dall'evento, resettate il timer e aspettate che il timer completi di nuovo il conteggio altre venti volte. In questa maniera eseguirete effettivamente il vostro evento una volta al secondo con una precisione al ventesimo di secondo.

Abbiamo ora un sistema capace di misurare il tempo. Quello che ci serve ora e' sapere come controllare il timer e inizializzarlo in maniera che possiamo dargli le informazioni corrette.


I registri Timer SFR

Come precedentemente affermato, l'8051 ha due timer che funzionano ambedue nella stessa maniera. Uno e' chiamato TIMER0 e l'altro TIMER1. I due timer condividono due registri SFR (TCON e TMOD) che servono a controllarli. Ciascun timer pero' dispone di due SFR per loro uso esclusivo (TH0/TL0 e TH1/TL1).

Ai registri SFR abbiamo dato un nome mnemonico per individuarli facilmente, in effetti essi hanno un valore numerico. E' spesso utile conoscere l'indirizzo corrispondente al nome mnemonico del registro SFR. Per quello che riguarda i timer essi sono:


Nome SFR

Descrizione

Indirizzo SFR

TH0

Timer 0 Byte Alto

8Ch

TL0

Timer 0 Byte Basso

8Ah

TH1

Timer 1 Byte Alto

8Dh

TL1

Timer 1 Byte Basso

8Bh

TCON

Timer Control

88h

TMOD

Timer Mode

89h


Quando inserite il nome di un registro SFR nell'assembler, esso viene internamente automaticamente convertito in un indirizzo, Per esempio:

MOV TH0,#25h

carica il valore 25h nel registro TH0, tenuto conto che esso risiede nell'indirizzo 8Ch, sara' convertita in:

MOV 8Ch,#25h

Ora, torniamo a parlare del timer 0. Esso ha due registri TH0 e TL0, che senza complicarci la vita, possiamo ritenere essere il byte piu' e meno significativo del timer stesso. Se il timer 0 ha valore 0, entrambi i suddetti registri avranno valore 0. Quando il timer assume valore 1000 (decimale), TH0 conterra' il valore 3 (decimale) e TL0 il valore 232 (decimale).

Per ricordarvi come funziona la notazione byte basso/alto, ricordatevi di moltiplicare il byte alto per 256 e addizionare il byte basso al risultato ottenuto. Ovvero:

TH0 * 256 + TL0 = 1000

Il timer 1 funziona esattamente nella stessa maniera ma dispone dei registri TH1 e TL1.

Poiche' solo due byte sono usati per ogni timer risulta evidente che il massimo valore che un timer puo' assumere e' 65.535 (decimale). Nel momento in cui viene raggiunto tale valore un ulteriore impulso di clock lo resettera' o per meglio dire lo mandera' in overflow.



Il registro SFR TMOD


Il registro TMOD e' usato per controllare il modo operativo di ambedue i timer. Ogni bit del registro fornisce al microntrollore una specifica informazione che riguarda il funzionamento del timer. I 4 bit piu' significativi (da 4 a 7) sono relativi al timer 1 mentre i 4 bit meno significativi (da 0 a 3) hanno il medesimo significato ma sono relativi al timer 0.







I bit del registro TMOD hanno il seguente significato :

TMOD (89h) SFR

Bit

Nome

Spiegazione della funzione

Timer


GATE1

Quando questo bit e' settato, il timer 1 e' attivo solo quando il pin P3.3 e' nello stato alto. Se tale bit e ' resettato il timer 1 sara' svincolato dallo stato del pin P3.3.



C/T1

Quando questo bit e' settato il timer 1 contera' il numero degli eventi sul pin T1 (P3.5). Se il bit e' resettato il timer 1 verra' incrementato ogni ciclo macchina.



T1M1

Bit 1 di modo del timer 1(vedi sotto)



T1M0

Bit 0 di modo del timer 1(vedi sotto)



GATE0

Quando questo bit e' settato, il timer 0 e' attivo solo quando il pin P3.2 e' nello stato alto. Se tale bit e ' resettato il timer 0 sara' svincolato dallo stato del pin P3.2.



C/T0

Quando questo bit e' settato il timer 0 contera' il numero degli eventi sul pin T1 (P3.5). Se il bit e' resettato il timer 0 verra' incrementato ogni ciclo macchina.



T0M1

Bit 1 di modo del timer 0(vedi sotto)



T0M0

Bit 0 di modo del timer 0(vedi sotto)


Come potete vedere dalla tabella di sopra, quattro bit, due per ciascun timer sono usati per specificare il modo operativo. I modi operativi sono:

TxM1

TxM0

Timer Mode

Descrizione




Timer a 13-bit




Timer a 16-bit




Timer a 8-bit con auto-reload




Timer in splitted mode

Modo a 13-bit (modo 0)

Il modo "0" corrisponde al funzionamento del timer a 13 bit. Questo e' un retaggio del passato che e' stato mantenuto per avere la compatibilita' con il suo predecessore: l'8048.
Generalmente questo modo di funzionamento non viene utilizzato in nuovi sviluppi.

In questa modalita' di funzionamento, TLx contera' da 0 a 31. Quando TLx viene incrementato da 31, esso si resettera' e incrementera' THx. Percio' effettivamente, soltanto 13 bit del timer a 2 byte sono utlizzati: i bit 0-4 di TLx e i bit 0-7 di THx. Questo significa anche in definitiva che il timer puo' contare solo fino ad un valore pari a 8192. Se caricate il timer con il valore 0, esso andra' in overflow e quindi a 0 dopo 8192 cicli macchina.

Modo a 16-bit (modo 1)

Il modo "1" corrisponde al funzionamento del timer a 16 bit. Questo e' un modo molto utilizzato. TLx e' incrementato da 0 a 255. All'overflow di TLx, THx viene incrementato di 1. Tenuto conto che e' un timer a 16 bit, esso puo' assumere 65536 valori distinti. Se caricate il timer con il valore 0, esso andra' in overflow e quindi a 0, dopo 65536 cicli macchina.

Modo a 8-bit (modo 2)

Il modo "2" corrisponde al funzionamento del timer ad 8 bit con auto-reload. Quando il timer e' configurato in modo 2, THx contiene il valore che deve essere caricato in TLx quando va in overflow. TLx inizia a contatore in avanti. Quando raggiunge 255 e viene ulteriormente incrementato invece di tornare a 0 (come nei modi 0 e 1), assume il valore caricato in THx.

Se per esempio TH0 contiene il valore FDh e TL0 il valore FEh il conteggio procedera' nella seguente maniera:


Ciclo Macchina

Valore di TH0

Valore di TL0


FDh

FEh


FDh

FFh


FDh

FDh


FDh

FEh


FDh

FFh


FDh

FDh


FDh

FEh

Notate che il valore di TH0 non cambia mai e TL0 viene incrementato. Una volta raggiunto un valore pari a FFh, al successivo ciclo macchina TL0 assume lo stesso valore di TH0.

Ma qual'e' il vantaggio di usare tale modo di funzionamento? Ipotizziamo che vogliate che il timer assuma dei valori compresi tra 200 e 255. Nel modo 0 e 1 siete costretti a verificare da programma quando il timer va in overflow e quindi settarlo al valore 200. Questo lavoro richiede tempo prezioso e non vi garantisce un elevata accuratezza a meno che non vogliate rimanere a controllare solo lo stato del timer. Quando usate il modo 2, non dovete preoccuparvi di tutto questo, poiche' l'hardware del microcontrollore lo fara' automaticamente per voi.

Il modo 2 e' usato molto spesso per generare il baud rate. Ne parleremo piu' approfondidamente nel capitolo dedicato alla Comunicazione Seriale.

Modo Split (modo 3)

Il modo "3" e' il cosidetto modo a timer separati. Quando il timer 0 e' configurato per lavorare in questa modalita', si trasforma in due timer a 8 bit separati. Per capirci meglio, il timer 0 diventa TL0 e il timer 1 diventa TH0. Ambedue i timer contano da 0 a 255 e dopo l'overflow tornano a 0. Tutti i bit relativi al Timer 1 vengono assegnati a TH0.

Una volta che il Timer 0 e' configurato in modo split, il vero Timer 1 (cioe' TH1 e TL1) puo' essere configurato nei modi 0, 1, 2 come sempre, ma non puo' essere abilitato/disabilitato poiche' i suoi bit di controllo sono assegnati a TH0. Allora, il vero Timer 1 funzionera' in maniera libera e si incrementera' ad ogni ciclo macchina senza condizioni.

L'unico vero uso di questa modalita' e' quello per cui sia necessario avere due timer separati e, in aggiunta, un generatore di baud rate. In questo caso il Timer 1 viene utilizzato come baud generator e i due registri TH0 e TL0 come se fossero due timer separati.

Il registro TCON

Come ultimo c'e' un altro registro SFR che controlla i due timer e fornisce importanti informazioni sul loro funzionamento. Il registro TCON ha la seguente struttura:

TCON (88h) SFR

Bit

Nome

Indirizzo a Bit

Spiegazione della funzione

Timer


TF1

8Fh

Timer 1 Overflow Questo bit e'settato quando il timer 1 e' andato in overflow



TR1

8Eh

Timer 1 Run Quando questo bit viene settato il timer 1 e' abilitato, altrimenti e' fermo.



TF0

8Dh

Timer 0 Overflow.Questo bit e'settato quando il timer 0 e' andato in overflow



TR0

8Ch

Timer 0 Run Quando questo bit viene settato il timer 0 e' abilitato, altrimenti e' fermo.


Come potete notare, abbiamo definito solo 4 degli 8 bit. Cio' e' dovuto al fatto che gli altri 4 bit del registro TCON non hanno nulla a che vedere con i timer. Essi sono relativi agli interrupt e quindi ne discuteremo nel capitolo dedicato a questo argomento.

Nella tabella precedente, c'e' un ulteriore colonna che riguarda l'indirizzo a bit. E' stata riportata perche' tale registro puo' essere indirizzato a bit, cio' vuol dire che, se vogliamo settare il bit TF1, che e' il bit piu' significativo di TCON, potremmo eseguire la seguente istruzione:

MOV TCON, #80h

oppure, visto che il registro e' indirizzabile a bit, potremo piu' semplicemente eseguire quest'altra istruzione:

SETB TF1

In quest'ultimo caso abbiamo il vantaggio di settare il bit piu' significativo di TCON senza cambiare il valore degli altri bit del registro. Generalmente infatti, quando si abilita o disabilita un timer, non si vuole modificare il valore degli altri bit di TCON, allora e' possibile sfruttare il fatto che tale registro e' indirizzabile a bit.

Inizializzare un timer

Ora che conoscaiamo tutti i registri SFR relativi ai timer, siamo in grado di scrivere il codice per inizializzare un timer e farlo partire.

Come vi ricordate, bisogna per prima cosa decidere in quale modalita' il timer verra' utilizzato. In questo caso scegliamo un modo a 16 bit che non ha alcuna dipendenza da pin esterni.

Dobbiamo per prima cosa, inizializzare il registro TMOD. Se lavoriamo con il timer 0 useremo i 4 bit meno significativi di TMOD. I primi due bit GATE0 e C/T0 vanno ambedue posti a 0 poiche' vogliamo che il timer sia indipendendente da pin esterni. Il modo a 16-bit corrisponde al modo "1" e quindi dobbiamo: resettare T0M1 e settare T0M0. In breve l'unico bit da settare e' il bit 0 di TMOD. Per inizializzare il timer eseguiremo la seguente istruzione:

MOV TMOD,#01h

Il timer 0 e' ora configurato per funzionare a 16 bit, ma e' disabilitato. Per attivarlo dobbiamo settare il bit TR0. Cio' puo' essere fatto mediante la seguente istruzione:

SETB TR0

Non appena verranno eseguite le precedenti due istruzioni, il timer 0 iniziera' a contare in avanti incrementando il suo valore ad ogni ciclo macchina (ogni 12 impulsi di clock).

Leggere lo stato di un Timer

Ci sono due maniere per leggere lo stato di un timer a 16-bit in funzione della specifica applicazione. Voi potete o leggere il valore attuale a 16 bit oppure stabilire soltanto se il timer e' andato in overflow.

Legger il valore del timer

Se il timer e' configurato nel modo ad 8 bit, sia nel modo con auto-reload che in split mode, la lettura del valore e' effettuata semplicemente leggendo il byte corrispondente al timer che state usando.

Quando pero' state usando il modo a 13 o 16 bit la lettura e' leggermente piu' complessa. Cio' e' dovuto al fatto che mentre state leggendo il valore del byte meno significativo del timer e questo valore e' pari a 255, potreste leggere un valore errato del byte piu' significativo che, in quel momento si sta incrementando. Per esempio se lo stato del timer e' 14/255 (byte alto = 14, byte basso = 255), potremmo leggere il valore 15/255 nel momento in cui il timer sta cambiando di stato al valore 15/0.

Quale potrebbe essere la soluzione? In verita' essa non e' molto complessa. Dovreste leggere prima il byte alto, poi quello basso e rileggere nuovamente il byte alto confrontandolo con il valore letto precedentemente. Sei i due valori coincidono, il timer non ha cambiato stato durante la lettura e quindi il valore letto e' utile, altrimenti va ripetuto il ciclo precedente. Il codice sara' del tipo:





REPEAT:

MOV A,TH0


MOV R0,TL0


CJNE A,TH0,REPEAT



Un altra maniera piu' semplice e' quella di congelare momentaneamente il timer (es. CLR TR0), leggere il valore del timer, e riabilitare subito il timer fermato (es. SETB TR0). In questo caso, essendo il timer fermo durante la lettura, non servono particolari precauzioni nella lettura. Ovviamente questo implica che il timer perdera' alcuni colpi di ciclo macchina. Dipende allora dalla specifica applicazione se cio' sia o meno tollerabile.

Rivelare l'Overflow di un timer

In alcuni casi e' sufficiente conoscere soltanto se il timer e' stato resettato o meno. Questo quando non interessa conoscere il valore del timer ma solo sapere se il timer ha raggiunto il massimo del conteggio (overflow). Una volta che il timer raggiunge il valore di 255, il microcontrollore lo riporta automaticamente a zero e setta il bit TFx corrispondente nel registro TCON. Per cui quando il bit TF0 e' settato vuol dire che il timer 0 ha raggiunto l'overflow e alla stessa maniera se TF1 e' settato vuol dire che il timer 1 e' tornato a zero.

Possiamo usare questo approccio per costringere il programma ad eseguire delle operazioni ad intervalli di tempo prestabiliti. Riprendiamo pure l'esempio precedente nel quale era richiesto il conteggio da 0 a 46.079 per un periodo di un ventesimo di secondo. Se vogliamo impostare un tempo pari a quello indicato, tenuto conto che il timer segnala l'overflow quando passa per lo zero, dobbiamo settare il timer ad un valore pari a 65.536 meno 46.079, cioe' 19.457. Quindi per eseguire una pausa di un ventesimo di secondo usiamo il seguente frammento di codice:

MOV TH0,#76; Byte alto di 19.457 (76 * 256 = 19.456)
MOV TL0,#01; Byte basso di 19.457 (19.456 + 1 = 19.457)
MOV TMOD,#01; Configura il Timer 0 nel modo a 16-bit
SETB TR0; Abilita il conteggio del timer Timer 0
JNB TF0,$; Se il flag TF0 non e' settato rimane nella medesima istruzione.

Il simbolo "$" viene usato nella maggior parte degli assembler per indicare l'indirizzo dell'istruzione in corso. Per cui, finche' il flag TF0 non e' settato e quindi il timer non e' andato in overflow, il programma rimane in loop nell'istruzione in corso. Al termine del ventesimo di secondo, il timer tornera' a zero settando il flag e a quel punto il programma uscira' fuori dal loop.

Misurare la durata di un evento

L'8051 dispone di un altro utile modo che puo' essere usato per misurare la durata di un evento.

Facciamo un esempio: vogliamo risparmiare energia in un ufficio e vogliamo conoscere quanto tempo una lampada rimane accesa durante la giornata. Quando la lampada e' accesa vogliamo conteggiare il tempo. Quando la lampada e' spento fermiamo il conteggio. Una possibile soluzione e' quella di collegare lo stato dell'interruttore ad un pin del micro. A questo punto il programma deve continuamente monitorare lo stato del pin utilizzato e attivare o disattivare il timer in funzione dello stato del pin stesso. Anche se il sistema funziona correttamente, In realta', l'8051 fornisce un metodo piu' semplice di quello appena prospettato.

Se diamo un'occhiata al registro TMOD, c'e' un bit chiamato GATE0. Finora abbiamo lasciato sempre il bit a zero perche' volevano che il timer continuasse a girare indipendentemente dallo stato dei fili esterni. Adesso pero', tale capacita' ci torna utile. Tutto quello che serve e' di collegare lo stato dell'interruttore al pin INT0 (P3.2) dell'8051 e settare il bit GATE0. A questo punto, il timer eseguira' il conteggio solo quando il pin P3.2 si trovera' nello stato alto (interruttore on, luce accesa). Quando il pin P3.2 si trovera' nello stato basso (interruttore off, luce spenta) il timer si blocchera' automaticamente.

USARE I TIMER COME CONTATORI DI EVENTI

Finora abbiamo discusso di come un timer possa tener traccia del tempo trascorso, ma l'8051 ci permette di usare il timer come contatore di eventi.

Quando puo' essere utile questa funzione? Supponiamo di avere un sensore nel mezzo di una strada che invia un impulso ogni volta che passa un'auto. Questo potrebbe essere utilizzato per misurare l'intensita' del traffico su quella strada. Potremmo allora collegare il sensore ad un pin di I/O dell'8051 e monitorare lo stato del pin per contare il numero degli impulsi. Fare questo non e' eccessivamente difficile, ma richiede l'utilizzo di un po' di codice. Supponiamo per esempio di aver collegato il sensore al pin P1.0; il codice che conta il numero di auto che passano sara' del tipo:

JNB P1.0,$

; Aspetta che un'auto attivi la linea.

JB P1.0,$

; La linea e' ora attiva, la macchina sta passando.

INC COUNTER

; La linea e' bassa, quindi la macchina e' passata, possiamo contare l'evento.

Come potete osservare servono soltanto tre linee di codice. Ma che succede se dobbiamo fare qualche altra cosa nello stesso tempo, visto che il programma rimane quasi sempre fermo in loop sull'istruzione JNB? Certamente e' possibile trovare una soluzione, ma questa renderebbe il codice grande, complesso e poco elegante.

Fortunamente l'8051 ci fornisce un'alternativa per usare il timer come contatore di eventi senza doverci preoccupare di come realizzarlo in software. E' estremamente semplice e indolore: basta configurare un bit addizionale.

Per esempio vogliamo utilizzare il Timer 0 per conteggiare il numero delle auto che transitano. Allora, se diamo uno sguardo al registri TCON possiamo notare la presenza di un bit chiamato C/T0, bit 2 di TCON (TCON.2). Se tale bit e' settato, il timer 0, invece di incrementare se stesso ad ogni ciclo macchina, effettuera' il monitoring della linea P3.4. In questa maniera incrementera' se stesso ogni volta che la linea passa dal valore alto a quello basso. A questo punto e' sufficiente collegare il sensore sulla linea P3.4 e configurare il registro TCON opportunamente.

E' importante pero' notare che l'8051 controlla lo stato della linea P3.4 una volta per ciclo macchina. Questo significa che, se la frequenza con la quale cambia lo stato del pin e' troppo elevata, l'8051 non riuscira' piu' a contare il numero di eventi in maniera corretta. Piu' precisamente, l'8051 riesce a contare un numero di eventi ad un massimo di un ventiquattresimo della frequenza di clock. Cio' vuol dire che, se per esempio usiamo un quarzo che oscilla a 12 MHz, esso riesce a conteggiare fino a 500.000 eventi al secondo (12 MHz * 1/24 = 500.000).





Privacy




Articolo informazione


Hits: 1806
Apprezzato: scheda appunto

Commentare questo articolo:

Non sei registrato
Devi essere registrato per commentare

ISCRIVITI



Copiare il codice

nella pagina web del tuo sito.


Copyright InfTub.com 2024