Questo sito utilizza cookie, anche di terze parti, per migliorare la tua esperienza e offrire servizi in linea con le tue preferenze. Chiudendo questo banner, scorrendo questa pagina o cliccando qualunque suo elemento acconsenti all’uso dei cookie. Se vuoi saperne di più o negare il consenso a tutti o ad alcuni cookie vai alla sezioneCookie Policy

Interrupt con Tmr0 e prescaler

Ultimo aggiornamento: 31/07/2015

In un altro articolo si è visto, in un modo molto semplice, come settare i registri interessati dal timer tmr0 per generare un interrupt (Link) periodico. Un importante aspetto di questo timer è il corretto settaggio del prescaler. Gli Interrupt generati dai timers sono una importante peculiarità comune alla maggioranza dei microcontrollori e sono largamente utilizzati dove il fattore 'tempo' è importante.

E' necessario subito chiarire cosa un prescaler rappresenti: è semplicemente un divisore di frequenza. Il timer tmr0 è un timer ad 8 bit che normalmente incrementa il suo valore ogni (fosc/4) impulsi di clock per generare un interrupt nel momento in cui il conteggio supera il valore di 255 (FF) e ricominciare da capo da zero (interrupt su overflow). E' normale che questa velocita' sia considerata troppo alta, la generazione di un interrupt ogni fosc/4/256 rappresenterebbe un carico molto pesante per il programma al punto tale da rallentare troppo il picmicro.

Picmicro prescaler

dove clock = Fosc/4 ed il prescaler settato a 1/8

Se il clock del picmicro è di  4mhz ed il prescaler settato ad 1/8 il timer tmr0 agirà con un clock di 125Khz.

Per un essere umano ragionare in termini di clock a 125khz avrebbe poco significato e talvolta anche controproducente. Siamo soliti pensare in termini di millesimi di secondo, secondi, di ore e quindi, al fine di poter operare con termini piu' consoni alla nostra mente si deve trovare un modo per convertire e per adeguare i settaggi del timer con lo scopo di ottenere temporizzazioni piu' consone al nostro programma ed a noi piu' comprensibili.

La funzione del prescaler è proprio questa, quella di dividere il clock del timer in modo da fargli effettuare 'x' interrupt in un determinato periodo di tempo. Talvolta l'operazione non è cosi semplice o precisa. Sappiamo che il periodo è l'inverso della frequenza e quindi 125khz = 1/125000 = 8microS. In questo caso esemplificativo verrà generato un interrut ogni 8*256uS = 2,048mS ... per una mente umana un risultato quasi senza senso ed inoltre abbiamo bisogno spesso di temporizzazioni piu' precise. 

prescaler registro picmicro prescaler

La domanda ora è: come ottenere un interrupt ogni 'x' esatti periodi di tempo?

Innanzitutto si deve tenere presente che noi possiamo variare il numero di impulsi necessari at ottenere l'overflow del timer0. Abbiamo detto, infatti, che la variabile tmr0 inizia il conteggio da zero sino a 255 generando un interrupt e ripartendo nuovamente il contegio da zero.

Per variare questo comportamento noi possiamo precaricare un valore alla variabile/timer tmr0 in modo da ridurre il numero di impulsi necessari ad ottenere l'overflow (se poniamo la variabile tmr0=10 ogni inizio di conteggio, ad esempio, saranno necessario solo 246 impulsi).

A questo punto per calcolare tutti i valori sia di prescaler che di offset della variabile tmr0 abbiamo due possibilità: la prima è quella di utilizzare uno dei tanti calcolatori presenti su internet :-) http://eng-serve.com/pic/pic_timer.html ad esempio, oppure possiamo calcolare manualmente i valori sulla base della seguente formula:

freq = (fosc/4)  /  (256-tmr0value) * Prescaler

in questo caso qualora si desideri un interrupt ogni 1ms con un cristallo di 4 mhz ed un prescale settato ad 1/4 il valore offset da assegnare alla variabile tmr0 dovrebbe essere 6.

Sempre, prima di lasciare la routine interrupt() dovremo ricordare di:

  • resettare la variabile tmr0 al valore di offset;
  • riabilitare l'interrupt (INTE=1)
  • pulire il flag (INTF = 0)

 

 

void interrupt()
{
  if (INTCON.INTF ==1)                    // timer 0 interrupt flag
     {
      PORTB.F0 = ~PORTB.F0;           // inverte portb bit0 
      INTCON.INTF = 0;                      // pulisce flag
      INTCON.INTE = 1;                      // riabilita l' interrupt
      TMR0 = 6;                                      // resetta il tmr0
   }
}

void main()
{
  TRISB = 0x00;                                
  PORTB = 0;                                   
  OPTION_REG.T0CS = 0;             // Tmr0 clock interno
  OPTION_REG.T0SE = 0;             // TMR0 edge in salita
  OPTION_REG.PSA = 0;              // Assegna il Prescaler al Timer0
  OPTION_REG.PS2 = 0;              // Setta il Prescaler ad 1/4
  OPTION_REG.PS1 = 0;
  OPTION_REG.PS0 = 1;
  TMR0 = 6;                                  // valore di offset 
  INTCON = 0;                              // pulisce il registro di controllo dell'interrupt
  INTCON.INTE = 1;                     // abilita il TMR0 
  INTCON.INTF = 0;                     // bit2 pulisce il flag del timer0
  INTCON.GIE = 1;                      // bit7 abilita gli interrupts

do
  {
  } while(1) ;
}

In molti casi l'uso dei temporizzatori interni al picmicro rappresenta una soluzione ottima per la soluzione di molti problemi di programmazione (vedremo poi anche gli altri timers di cui si dotano molti picmicro); purtroppo pero' in molte altre situazioni, dove occorrono temporizzazioni precise (come in un orologio digitale, ad esempio), l'uso di questi timers non è consigliabile. E' preferibile, infatti, affidarsi a precisi generatori esterni di clock come il Dallas DS1307 o equivalenti.

Diritti riservati Cuteminds.com 2008-2015. Tutti i marchi riportati sono detenuti dai legittimi proprietari. Tutto il materiale e` liberamente utilizzabile ma non per scopi commerciali. Non si assume alcuna responsabilita` sul materiale pubblicato per eventuali danni diretti o indiretti che possano derivare dall`utilizzo di schemi, progetti o altro materiale presente nel sito. Inviare una mail a: remove-admin@cuteminds.com (contenuti) remove-webmaster@cuteminds.com (webserver) per domande e/o suggerimenti.