Guida alla Programmazione in C del PIC, 9° Parte

NE555   Nella Nona Parte della Guida si Parlerà dei Timer Counter del PIC18f252, in questo caso, e delle Modalità Capture e Compare. Saranno presenti 3 Esempi…


 
 
 
 




 

INTRO

Il PIC 18f252 dispone di 4 timer counter, uno a 8 bit, due a 8/16bit e uno a 16 bit. I timer possono essere usati per contare impulsi, contare il tempo tra due eventi, o altre applicazioni di questo tipo. La modalità capture permette di catturare il valore del timer counter 0 o timer counter 3 quando avviene un evento su un determinato evento sui pin di I/O. La modalità compare crea un evento verso l’esterno quando il valore in un registro è uguale al valore del timer counter 0 o timer counter 3. Inoltre alcuni timer possono usare come segnale di clock un segnale esterno, permettendo quindi di svolgere operazioni su un segnale esterno o in base ad un segnale esterno.

 




 

TIMER COUNTER 0

Il timer counter 0 può essere a 8 o a 16 bit, ha un prescaler a 8 bit, può avere il clock dall’interno o dall’esterno con selezione del fronte di salita o discesa e inoltre ha l’interrupt di over flow. Questo è lo schema a blocchi del timer counter 0:  

NE555   Il clock esterno può essere inviato tramite il pin T0CKI (pin 5) , poi il prescaler può essere selezionato o no e infine si può selezionare anche la dimensione del timer counter, se 8 0 16 bit. Il registro dove è presente il dato è TMR0L per il LSB e TMR0H per i MSB del valore del conteggio. Il registro di controllo è chiamato T0CON ed è il seguente:

NE555

  • T0PS0:T0PS2: è il valore del prescaler, ovvero il valore che indica di quanto viene divisa la frequenza che giunge al timer counter. Questo valore può andare da 2(000) a 256(111), questo vuol dire che se la frequenza del quarzo dell’oscillatore è 4MHz (quindi la frequenza è 1MHz), se uso il valore diviso 2 il timer counter lavora con una frequenza di 500KHz, se uso un prescaler di 256 si avrà una frequenza di circa 4KHz.
  • PSA: questo bit serve per selezionare o meno un prescaler, se 1 non vi è prescaler, se invece 0 vi è il prescaler selezionato dai 3 bit precedenti.
  • T0SE: serve per selezionare il fronte di salita o discesa del segnale sul pin T0CKI, se 0 si usa il fronte di discesa, se uno quello di salita.
  • T0CS: serve a selezionare la fonte di clock, 1 clock proveniente dal pin T0CKI 0 clock proveniente dal clock del microcontrollore.
  • T08BIT: se si scrive 0 in questo registro si utilizza questo timer counter in modalità 16bit, altrimenti in caso contrario si utilizza in modalità 8 bit.
  • TMR0ON: serve per attivare e disattivare il timer counter.

Con questo timer counter può essere generato un interrupt quando viene raggiunto il massimo conteggio, ovvero l’over flow. Anche se Il registro contenente il conteggio è TMR0 diviso in TMR0L e TMR0H, questo registro può essere sia letto che scritto.

 

TIMER COUNTER 1, 2 e 3

Gli altri timer counter differiscono leggermente dal precedente, partiamo dal timer counter 1.

Questo timer counter può essere a 8 o 16 bit con un prescaler fino a 8, e la possibilità di sincronizzare il clock interno e esterno. Inoltre permette di generare un clock diverso da quello interno grazie ad un altro cristallo di quarzo inserito tra i pin T1OSO (pin 11) e il pin T1OSI (pin 12). In questo modo ho tre possibili fonti di clock per questo timer counter, una dall’interno, una da un segnale esterno e una generata grazie a componenti esterni.

Il timer counter 2 è ad 8 bit e viene usato principalmente per generare il segnale PWM.

Il timer 3 è identico al timer counter 0, con l’eccezione che dispone del sistema di oscillazione per generare il clock con dei componenti esterni oltre che riceverlo dall’esterno e dall’interno.

Nel registro di controllo del timer counter 3 si può selezionare quale contatore usare nella modalità capture o compare, inoltre si può selezionare il prescaler attivare questo counter o meno. Anche questo timer è a 8 o 16 bit.

 




 

MODALITA’ CAPTURE

Nella modalità capture i registri CCPR1H e CCPR1L catturano il valore presente nel timer counter 1 o 3 quando si verifica un evento. Un evento può essere un fronte di salita sul pin CCP1 o CCP2 o un fronte di discesa o il quarto o il sedicesimo fronte di salita. Lo schema a blocchi di questa struttura è:

NE555   Oltre ai registri dei timer counter, da settare come si vuole, bisogna anche settare il registro di controllo del modulo compare e capture, in particolare visto che i moduli sono due vi saranno due registri identici. Il registro di controllo contiene i seguenti campi di controllo:

NE555   I bit DCxB1 e DCxB0 non sono utilizzati per questa modalità e nemmeno per la modalità compare.

  • CCPxM3:CCPxM0 (0000): modalità capture e compare disabilitate
  • CCPxM3:CCPxM0 (0100): modalità capture, ogni fronte di discesa.
  • CCPxM3:CCPxM0 (0101): modalità capture, ogni fronte di salita.
  • CCPxM3:CCPxM0 (0110): modalità capture, ogni 4 fronti di salita.
  • CCPxM3:CCPxM0 (0111): modalità capture, ogni 16 fronti di salita.

Inoltre è possibile settando il bit per l’abilitazione dell’interrupt, generare un interrupt ogni fronte di salita o discesa o ogni quattro o sedici fronti di salita. Se non si setta l’interrupt in ogni caso vi è un flag settato quando si va a catturare il dato dal timer, questo flag si trova nel registro PIR1 e si chiama CCP1IF. Se si sceglie di non sincronizzare il clock interno con quello del timer counter, qualcosa si utilizzasse un clock esterno, la modalità capture potrebbe non funzionare. Per selezionare quale timer associare ai moduli bisogna configurare il registro di controllo del timer counter 3 ovvero T3CON, e in particolare i bit T3CCP2 e T3CCP1. Se 1x allora il timer 3 sarà la sorgente per i due moduli, se 01 allora il timer counter 3 è associato al modulo CCP2 e il timer counter 1 al modulo CCP1, altrimenti, se questi due bit sono 00 allora, il timer counter 1 è la fonte per tutti e due i moduli compare capture.

 

MODALITA’ COMPARE

In questa modalità, quando il valore nel timer counter è uguale al valore nel registro CCPR1 o CCPR2, a seconda di quale modulo si abilita, si verifica un evento sul pin di uscita CCP1 (pin 13) o su CCP2 (pin 12).

Inoltre quando la comparazione da un valore positivo, ovvero i valori nel registro e nel timer sono uguali, si può attivare anche un interrupt, in modo tale da attivare un sottoprogramma.

Bisogna ricordare che i registri CCPR1 e CCPR2 sono divisi in parte alta e parte bassa, quindi, CCPR1L e CCPR1H. lo schema a blocchi di questo modulo è:

NE555   Il registro di controllo è sempre CCP1CON e CCP2CON, ma in questo caso le modalità di funzionamento saranno:

  • CCPxM3:CCPxM0 (0000): modalità capture e compare disabilitate
  • CCPxM3:CCPxM0 (1000): modalità compare, inizialmente il pin è a livello 0 e poi quando si ha l’uguaglianza dei registri viene forzato a 1, inoltre l’interrupt è settato .
  • CCPxM3:CCPxM0 (0010): modalità compare, il pin di uscita viene invertito, se è a livello alto va a livello basso o viceversa quando si ha l’uguaglianza, inoltre l’interrupt è settato .
  • CCPxM3:CCPxM0 (1010): modalità compare, si genera un interrupt quando si ha l’uguaglianza ma il pin d’uscita non varia.
  • CCPxM3:CCPxM0 (1011): modalità compare, si genera un interrupt quando si ha l’uguaglianza ma il pin d’uscita non varia.

 

ESEMPIO UTILIZZO TIMER COUNTER

Supponiamo di voler contare i fronti di salita di un segnale esterno, ci sono 3 soluzioni, la prima è usare l’interrupt e incrementare una variabile ad ogni fronte, la seconda è fare una complicatissima routine con due if a controllare i livelli del segnale e incrementare una variabile, la terza soluzione è utilizzare un timer counter. Quest’ultima è la soluzione più ovvia, rapida e semplice.

Supponiamo di voler contare i fronti di salita di un segnale esterno (quindi non serve un prescaler) e di volerne contare solo 200 (quindi basta un contatore a 8 bit o usare solo 8 bit) e di voler visualizzare su dei led il valore del conteggi; il codice sarà il seguente:

unsigned int count;           //variabile che contiene il conteggio

void main() {

  trisb = 0x00;               //portb tutte uscite
  
  trisa.rb4 = 1;              //T0CKI pin input

  T0CON = 0b11101000;         //timer counter 0 on, configurato a 8bit
                              //clock esterno, sensibilità al fronte di salita
                              //no prescaler

  while(1){                   //ciclo infinito
  
    if( count < 201) count = TMR0L;      //se conteggio < 201 continua a contare

    else T0CON = 0b01100000;             //altrimenti spegni il timer counter

    portb = count;                       //visualizza su portb il conteggio
  }
}

Prima di tutto inizializzo una variabile che contiene il valore del conteggio, poi attivo come uscite tutte le PORTB mentre il pin RA4 come ingresso visto che è l’ingresso del clock. Dopo di che abilito il timer counter 1 con dimensione a 8 bit, senza prescaler e con sensibilità al fronte di salita.

Nel ciclo infinito controllo se il valore del conteggio è minore di 201, se si allora trasferisco il conteggio nella variabile count e la visualizzo sull’esterno, se il valore di count ha raggiunto invece il valore 200 spengo il timer counter. Lo schema è il seguente:

NE555

 

 

ESEMPIO UTILIZZO MODULO CAPTURE

Supponiamo di avere un segnale esterno con periodo che può variare tra 100ms e 500ms e voglio conoscere il valore del periodo. Per fare ciò devo conoscere il tempo fra due fronti di salita ad esempio. Posso utilizzare quindi il modulo capture per catturare il valore del timer counter quando si ha un fronte di salita e conoscendo la frequenza del timer counter, quindi il tempo tra i conteggi, e moltiplicando per il valore del conteggio, posso conoscere il tempo tra i fronti.

Utilizziamo il timer counter 3 con prescaler di 8 e sapendo che la frequenza dell’oscillatore a quarzo è 4 MHz, quindi si ha un clock di un MHz, il timer counter si incrementa ogni 1/(1*10^6) quindi ogni 1uS ma per via del prescaler si incrementa ogni 8uS, quindi quando si ha il valore di 500ms si avrà un conteggio di 62500, un numero a 8bit arriva massimo a 256, quindi si usa un numero a 16bit, visto che il valore massimo contabile è 65535.

Il codice sarà quindi:

#define Hi(param) ((char *)&param)[1]       //definizione funzione Hi
#define Lo(param) ((char *)&param)[0]       //definizione funzione Lo



unsigned int count = 0x0000;      //variabile a 16bit

void main() {

  CCP1CON = 0b00000101;           //capture ogni fronte di salita

  TRISB = 0;                      //portb uscite

  TRISC.B2 = 1;                   //ccp1 pin ingresso

  T3CON = 0b11111001;             //timer a 16bit, prescaler 8
                                  //clock interno, timer 3 con modulo CCP2 E  CCP1

  while(1){                       //ciclo infinito

    if(pir1.ccp1if == 1){         //se si ha il fronte di salita
      tmr3l = 0;                  //reset timer 3
      tmr3h = 0;                  //reset timer 3
      pir1.ccp1if = 0;            //reset flag
    }

  Lo(count) = ccpr1l;             //unisci ccpr1l alla variabile
  Hi(count) = ccpr1h;             //unisci ccpr1h alla variabile

  portb = ccpr1h;                 //visualizza la parte alta del registro ccpr1

  }
}

Per prima cosa si va a inizializzare la funzione per concatenare i due valori a 8 bit in una unica variabile a 16bit chiamata count che viene inizializzata al valore 0. Per questo si definisce la funzione Hi e Lo. Dopo di che si inizializza la variabile e nel programma principale si inizializza il modulo CCP in modalità capture ad ogni fronte di salita. Poi si inizializzano le porte di I/O e il timer counter 3 con clock interno, con prescaler 8, a 16bit e si attiva questo timer counter.

Nel ciclo infinito si va a controllare il flag “pir1.ccp1if” che indica quando avviene un evento di capture. Se avviene questo evento si va a resettare il timer counter 3 visto che quando avviene un evento di capture non si resetta da solo il timer counter, inoltre viene resettato questo flag.

Quando si ha il fronte di salita il valore del timer counter viene catturato e posto nel registro ccpr1l e ccpr1h, questi due dati a 8 bit vengono uniti nella variabile count, dopo di che la parte alta viene posta in uscita per avere una visualizzazione e conferma di funzionamento.

Lo schema è il seguente:

NE555   Se si utilizza un onda quadra con frequenza 2Hz, si ha un periodo di 500mS e si ottiene, se si va a controllare il valore di uscita, 62500 che era il valore atteso.

 

ESEMPIO UTILIZZO MODULO COMPARE

Il modulo compare può essere usato facilmente per generare un evento quando un valore da noi impostato nel registro CCPR1 o CCPR2 uguaglia il valore di uno dei timer.

Supponiamo di voler toglare l’uscita del modulo CCP1 ogni 10uS, quindi ottenere in uscita una frequenza  di 50Hz. Questo è possibile perché se toglo l’uscita ogni 10uS ottengo una variazione 1-0 ogni 20uS, quindi un periodo di 20 uS, quindi una frequenza di 50Hz.

Supponiamo di avere una frequenza del quarzo di 4MHz, quindi un clock interno di 1MHz, se utilizzo un timer counter senza prescaler avrò un conteggio ogni nS, per ottenere 10us devo quindi attendere 10000 conteggio visto che 1uS=1000nS. quindi il numero da comparare sarà 10000 se non uso il prescaler. Devo usare quindi un timer a 16bit (ad esempio timer counter 1) e il numero da comparare in binario sarà 0b0010011100010000.

Il codice sarà:

void main() {

T3CON.T3CCP2 = 0;          //timer 3 asegnato al modulo ccp2
T3CON.T3CCP1 = 1;          //timer 1 asegnato al modulo ccp1

T1CON = 0b10000001;        //timer 1 attivo a 16bit no prescaler clock interno

CCP1CON = 0b00000010;      //compare mode, togle on match

TRISC.RB2 = 0;             //cpp1 pin uscita

CCPR1H = 0b00100111;       //valore 10000 inserito nel registro
CCPR1L = 0b00010000;       //di comparazione

  while(1){

    if (PIR1.CCP1IF == 1){      //se si ha l'ugualianza
      TMR1L = 0;                //resetta il timer
      TMR1H = 0;
      PIR1.CCP1IF = 0;          //resetta il flag
    }
  }
}

Prima di tutto si va ad assegnare al modulo CCP1 il timer counter , poi si setta il timer counter come timer a 16bit e con clock interno senza prescaler e si setta anche il modulo CCP1 in modalità compare con funzione togle ad ogni uguaglianza.

Infine si setta il pin CCP1 come uscita e si inizializza il valore voluto nel registro CCP1, facendo attenzione ad inserire gli 8 MSB nel registro CCPR1H e 8 LSB nel registro CCPR1L.

Nel ciclo infinito si va a controllare il flag CCP1IF nel registro PIR1. Questo flag indica che vi è l’uguaglianza, e se ciò avviene bisogna resettare il timer counter 1 e il flag. Queste iscrizioni, compreso l’if stesso, possono essere sostituite da una subroutine di interrupt che quando riceve l’interrupt va a resettare il timer counter 3 e lo stesso flag.

Lo schema e il risultato ottenuto con questo schema sono i seguenti:

NE555

 

DOWNLOAD

Potete scaricare tutti i codici degli esempi e i file per le simulazioni dal seguente LINK!!!





 

3985 Visite totali 12 Visite di oggi
Guida alla Programmazione in C del PIC, 9° Parte ultima modifica: 2016-05-10T16:46:51+00:00 da ne555

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *