Il Timer del PIC16F877 e i compilatori CCS

IL TIMER DEL PIC16F877 E I COMPILATORI CCS

La periferica timer è una delle periferiche base messe a disposizione  da  un  microcontrollore. Per i PIC, i compilatori CCS forniscono funzioni per  la  gestione  di  ritardi,  per  monitorare  un tempo trascorso ed altre utilità legate appunto al timer del microcontrollore. Il PIC16F877 dispone di ben tre periferiche timer note come Timer0, Timer1 e Timer2. Questi sono sostanzialmente dei contatori incrementati automaticamente in base alla frequenza del clock secondo un eventuale fattore di scala impostato mediante prescaler. Timer0 è ad 8 bit mentre gli altri sono a 16 bit. Con i compilatori CCS i singoli  timers  possno  essere  abilitati  mediante  le macro set_timer0, set_timer1 e set_timer2 rispettivamente. Ogni qualvolta un timer giunge a fine conteggio,  viene  automaticamente  azzerato e contemporaneamente viene generata una interruzione. Il legame tra il valore corrente del timer ed il tempo trascorso dall’ultimo azzeramento è dato dalla seguente espressione:

Ritardo[ms]=valore x 4 x prescaler x 1000/Clk

Dove valore è il valore corrente assunto dal timer, prescaler è il fattore di scala impostato e Clk è la frequenza del clock.  Usando quindi un clock  a 20MHz ed un prescaler pari a 8, se il valore corrente del timer è di 6250 (decimale) significa che sono trascorsi 6250 x 4 x 8 x 1000/20000000=10ms. Il listato 1 mostra come inizializzare il timer1 ed utilizzarlo per determinare il tempo di esecuzione di un particolare task.

long delay;
/* Imposta il prescaler a 8 per il Timer1 */
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
/* Azzeramento del Timer1. */
set_timer1(0);
/* Task di cui si deve calcolare il tempo di esecuz. */
printf(“Hello, world!”);
/* Calcolo del tempo in ms. */
delay = get_timer1() / 625;
Listato 1.

Ovviamente è necessario che il task non abbia un tempo di esecuzione superiore al massimo misurabile altrimenti la misura risulterebbe incorretta. Usando  ancora il compilatore  CCS, il listato 2 riporta un ulteriore esempio in cui l’esecuzione del programma  viene  sospesa  per un determinato numero di millisecondi.

/* Imposta il prescaler a 8 per il Timer1 */
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
/* Azzeramento del Timer1. */
set_timer1(0);
for ( ; get_timer1() < 3125; )
;3125 è il valore che dovrà raggiungere il timer
/* ritardo introdotto. */
Listato 2.

L’accorgimento  utilizzato in  questo  caso  è  sfruttare  un ciclo for vuoto in cui la condizione di uscita è che Timer1 abbia raggiunto il valore prefissato (e dipendente dal ritardo che si intende introdurre).

#include <16f877.h>
#ORG 0x1F00,0x1FFF {} /* Reserve memory for bootloader for the 8k 16F876/7
*/
#device PIC16F877 *=16 /* Allow RAM to expand beyond 256 bytes */
#device adc=10 /* Make sure that we are sampling on 10 bits. This directive
is required for compiler version 2.7. */
/* Set the clock speed */
#use delay(clock=20000000)
#fuses HS,NOPROTECT,NOWDT,BROWNOUT,PUT,NOLVP

/* Directive for RS-232 interface */
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#include “input.c”
#define VARIABLE_PERIOD 1 // If this symbol is defined, let the user select
the
                            // period and prescaler, otherwise,
                            // if VARIABLE_PERIOD = 0, use fixed values.
main() {
  char selection;
  byte duty, period;
  byte prescale;
  // We use serial input to capture PWM parameters to make
  // an easy demo.
  setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
  setup_ccp2(CCP_PWM); // Configure CCP1 as a PWM
#if VARIABLE_PERIOD // This is default
  for ( ; ; ) {
    // Select value for the period (100% duty cycle)
    printf(“Period (100%% duty cycle): “);
    period = gethex();
    printf(“\r\n”);
    // Set the prescaler
    do {
      // Select prescaler (t2div)
      printf(“\r\nSelect prescaler:\r\n”);
      printf(“ 1: Prescaler = 1\r\n”);
      printf(“ 2: Prescaler = 4\r\n”);
      printf(“ 3: Prescaler = 16\r\n”);
      printf(“Selection: “);
      selection = getc();
      putc(selection);
      printf(“\r\n”);
  } while((selection < ‘1’) || (selection > ‘3’));
  // The cycle time will be (1 / clock) * 4 * t2div * (period + 1)
  // In this program, if period is 0x80 (or 128 decimal), with
  // a clock of 20000000:
  // For the three possible prescaler selections the cycle time is:
  // (1/20000000) * 4 * 1 * 128 = 25.6 us or 39 khz
  // (1/20000000) * 4 * 4 * 128 = 102.4 us or 9.8 khz
  // (1/20000000) * 4 * 16 * 128 = 409.6 us or 2.4 khz
  switch(selection) {
  case ‘1’:
    prescale = 1;
    setup_timer_2(T2_DIV_BY_1, period, 1);
    break;
  case ‘2’:
    prescale = 4;
    setup_timer_2(T2_DIV_BY_4, period, 1);
    break;
  case ‘3’:
    prescale = 16;
    setup_timer_2(T2_DIV_BY_16, period, 1);
    break;
  }
#else
   period = 0x80;
   prescale = 4;
   setup_timer_2(T2_DIV_BY_4, period, 1);
#endif
   printf(“Frequency = %ld kHz\r\n”, 5000 / period / prescale);
   while(TRUE) {
    printf(“Enter duty cycle: “);
    duty = gethex();
    printf(“\r\n”);
    set_pwm1_duty(duty);
    set_pwm2_duty(duty);
  // This sets the time the pulse is
  // high each cycle.
  // If period is 128 (or ‘80’ hex),a value of 64 (or ‘40’ hex) will set
  // the duty cycle to 50%, i.e.
  // the pulse is high 50% of time.
  // WARNING: A value too high or low will prevent the output from
  //          changing. A value too high will make the CCPx high
  //          at all times.
     if (duty == 0x10) {
     // If ‘10’ is entered for duty, exit loop to be able to
       break;
      }
    }
  }
}
Listato 3.
Scarica subito una copia gratis

Una risposta

  1. Maurizio Di Paolo Emilio Maurizio 6 Giugno 2016

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend