Timer 1 «Temporizador, Contador, PWM», Pic C Compiler

En esta sección aprenderás a realizar diferentes aplicaciones utilizando el Timer1 del microcontrolador PIC, se realizara un generador de señal, una señal PWM, un temporizador de señal, un contador de pulsos y se utilizara el oscilador secundario del PIC para generar señales de reloj de salida.

¿Qué es un timer?

Un temporizador (timer, en inglés) es un componente de hardware en un microcontrolador que puede ser utilizado para medir el tiempo, para generar señales de reloj, para contar de pulsos de reloj, etc. Los timers son comunes en muchos microcontroladores y son útiles en una amplia variedad de aplicaciones.

En términos generales, un temporizador en un microcontrolador consiste en un contador que se puede configurar para contar pulsos externos o pulsos internos de reloj. El temporizador también puede estar conectado a un preescalador, que permite ajustar la velocidad de conteo del temporizador. El temporizador se puede configurar para generar una interrupción cuando se alcanza un valor específico, lo que permite al microcontrolador realizar acciones en función del tiempo transcurrido.

Por ejemplo, un temporizador puede ser utilizado para medir la duración de un pulso de entrada, para controlar la velocidad de un motor mediante señales PWM, para medir la frecuencia de una señal de entrada, o para generar interrupciones en intervalos regulares.

Los microcontroladores modernos suelen tener varios temporizadores integrados, cada uno con características y funcionalidades específicas. La elección del temporizador adecuado dependerá de la aplicación en la que se utilice y de las necesidades del usuario.

El microcontrolador PIC18F4550 tiene tres temporizadores/interrupciones de hardware (Timers), llamados Timer0, Timer1 y Timer2. Cada temporizador tiene sus propias características y funcionalidades específicas.

Timer 1

El Timer1 es un temporizador de 16 bits con un preescalador de 1,2,4 y 8. Puede ser utilizado para medir el tiempo (Temporizador) o como contador de pulsos (contador). El timer1 se puede configurar para utilizar un oscilador secundario de 32.768KHz, esta configuración con un oscilador secundario es útil para diferentes módulos que necesiten una señal de reloj para su funcionamiento.

Ejemplo 1: Generador de señal

El objetivo es generar una señal de salida de una frecuencia deseada.

Formulas

  • Fosc: La frecuencia del oscilador (clock) del microcontrolador.
  • Preescaler:  Divide la frecuencia del oscilador para disminuir el overflow.
  • Registro 16 Bits: Determina el valor del tiempo máximo que puede registrar el Timer1.
  • Overflow: El tiempo máximo que puede generar el registro del timer1.
  • TMR1: Establece el tiempo inicial del timer1 para generar la señal de salida a una frecuencia especifica.

Circuito de conexión

Procedimiento 

Para el siguiente ejemplo, se calculan los valores necesarios para generar una señal de salida con una frecuencia de 60Hz.

Inicialmente se calculan los valores para establecer el preescaler, la frecuencia del oscilador y el valor inicial para establecer la señal de salida.

Inicialmente se habilita el timer1 con el prescaler calculado.


setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

Se habilitan las interrupciones para detectar el desbordamiento del timer1.


   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER1);

Se establece el valor inicial del timer1 de acuerdo con el valor calculado «TMR1».


set_timer1(23870); //Inicializa el timer1

Se define el pin de salida de la señal.


#define salida pin_d0

Cuando el timer1 genera el desbordamiento se habilita la interrupción. La interrupción baja a la subrutina donde se resetea el timer1 al valor calculado (TMR1) y se cambia el estado del pin de salida.


#INT_TIMER1
void reset_timer()
{
   set_timer1(23870); //Resetea el timer1
   output_toggle(salida); //cambia el estado del pin_d0 (1/0) 
}

Archivo .h

En el archivo .h se coloca el oscilador calculado.


#use delay(crystal=20000000)

Código completo generador de señal


#FUSES NOMCLR

#define salida pin_d0

#INT_TIMER1
void reset_timer()
{
   set_timer1(23870); //Resetea el timer1
   output_toggle(salida); //cambia el estado del pin_d0 (1/0) 
}

void main()
{
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER1);

   set_timer1(23870); //Inicializa el timer1
   while(TRUE)
   {

      //TODO: User Code
   }

}

Ejemplo 2: Generador de señal PWM

En el ejemplo siguiente se realizan las las ecuaciones para obtener una señal de salida de una frecuencia deseada y controlar el ancho de pulso de la señal.

Circuito de conexión

Procedimiento 

Para el siguiente ejemplo, se calculan los valores necesarios para generar una señal PWM de salida con una frecuencia de 60Hz.

Véase el ejemplo 1 para generar la señal de salida.

Inicialmente se habilita la conversión analógica digital.


 setup_adc(ADC_CLOCK_INTERNAL);

Se colocan las instrucciones para realizar la lectura del pin analógico AN0, y se guarda el valor en la variable «POT»


      set_adc_channel (0);//Lectura Vout del potenciometro en PIN AN0
      POT = read_adc();// lectura del valor

Se realiza una regla de 3 para generar un «delay» para controlar el ancho de pulso de la señal, multiplicando el valor del «POT» por el «ancho de pulso» en microsegundos y el resultado se divide entre el valor del ADC (10 bits).


tiempo = ((int32)POT*8333)/1023;

Nota: Si la señal se invierte al girar el potenciometro al valor máximo, se debe reducir el ancho de pulso de la formula (algunos microsegundos), esto se debe a que la señal de salida no es precisa.

El valor del «tiempo» genera un «delay_us()» en el pulso negativo para controlar el ancho de pulso positivo de la señal de salida.


   if (input(salida) == 0)
   {
      delay_us((int16)tiempo);//controla el ancho de pulso positivo
   }

Código completo señal PWM


#FUSES NOMCLR

#define salida pin_d0

int16 POT;
float tiempo;

#INT_TIMER1
void reset_timer()
{
   set_timer1(23870); //Resetea el timer1
   if (input(salida) == 0)
   {
      delay_us((int16)tiempo);//controla el ancho de pulso positivo
   }
   output_toggle(salida); //cambia el estado del pin_d0 (1/0) 
}

void main()
{
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER1);

   set_timer1(23870); //Inicializa el timer1
   
   setup_adc(ADC_CLOCK_INTERNAL);
   while(TRUE)
   {
      set_adc_channel (0);//Lectura Vout del potenciometro en PIN AN0
      POT = read_adc();// lectura del valor
      tiempo = ((int32)POT*8333)/1023;
   }

}

Ejemplo 3: Temporizador

Se utilizará el timer1 como temporizador para obtener la medición del ancho de pulso de una señal del entrada.

Formulas

  • Fosc: La frecuencia del oscilador (clock) del microcontrolador.
  • Preescaler:  Divide la frecuencia del oscilador para aumentar el overflow.
  • Registro 16 Bits: Determina el valor del tiempo máximo que puede registrar el Timer1.
  • Overflow: El tiempo máximo que puede medir el registro del timer1.

Circuito de conexión

Procedimiento 

Para el siguiente ejemplo, se calculan los valores necesarios para medir el ancho de pulso de una señal de entrada menor a 13.107 milisegundos.

Inicialmente se calcula el tiempo máximo que puede medir el timer1 (overflow).

Se habilita el timer1 y se establece el prescaler que se estableció en la formula del «overflow».


setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

Se habilita la interrupción externa «INT_EXT2» correspondiente al «pin_b2» para establecer la entrada del pulso de señal.


   enable_interrupts(GLOBAL);
   enable_interrupts(INT_EXT2);

Se define el pin de estrada del pulso de señal.


#define entrada input(pin_b2) //interrupcion externa INT2

Cando se detecta un pulso de entrada (flanco de subida) se habilita la interrupción externa y se inicializa el conteo del tiempo, se espera en el bucle «while(entrada)» hasta que termine de generarse el pulso, cuando se detecta el flanco de bajada la función «get_timer1()» registra el valor del tiempo y se guarda en la variable «val_timer»


#INT_EXT2
void reset_timer()
{
     set_timer1(0);//Inicializa el timer1
     while(entrada)
     {}
     val_timer = get_timer1();//lectura el timer1
}

Como el valor del timer1 es registrado en 16 bits, se convierte el valor de 16 bits en milisegundos con una regla de 3, multiplicando el valor medido (val_timer) por el «overflow» y el resultado se divide entre 65536.


tiempo = ((int32)val_timer*13.107)/65536;

Finalmente se muestra el resultado del tiempo medido en la pantalla OLED.


void mostrar()
{
      char texto[20];

      sprintf(texto,"Valor=%f", tiempo);
      OLED_DrawText(1,1,texto,1);

      OLED_Display();//Muestra la información en pantalla;
}
Archivo .h

Se coloca en el archivo.h el oscilador que se estableció para calcular el «overflow».


#use delay(crystal=20000000)

Código completo Temporizador


#FUSES NOMCLR

#use i2c(Master, Fast, sda=PIN_B0, scl=PIN_B1, force_sw, stream=OLED_stream)//parametros I2C

#define SH1106_128_64 //DEFINE EL MODELO DE LA PANTALLA OLED
//#define SSD1306_128_64

#include "OLED_I2C.c" //libreria oled I2C

#define entrada input(pin_b2) //interrupcion externa INT2

int16 val_timer;
float tiempo;

#INT_EXT2
void reset_timer()
{
     set_timer1(0);//Inicializa el timer1
     while(entrada)
     {}
     val_timer = get_timer1();//lectura el timer1
}

void mostrar()
{
      char texto[20];

      sprintf(texto,"Valor=%f", tiempo);
      OLED_DrawText(1,1,texto,1);

      OLED_Display();//Muestra la información en pantalla;
}

void main()
{

   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_EXT2);

   OLED_Begin();
   OLED_ClearDisplay();

   while(TRUE)
   {
       tiempo = ((int32)val_timer*13.107)/65536;

       mostrar();
   }

}

Ejemplo 4: Contador

Se utilizara el timer1 como contador de pulsos de una señal de entrada.

Funcionamiento

Circuito de conexión

Procedimiento 

Para el siguiente ejemplo, se establecen los parámetros necesarios para contar 10 pulsos de entrada y encender un LED después de recibir los 10 pulsos. 

Se habilita el timer1 como contador, con un prescaler de 1.


setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); // flanco de subida

Se habilita la interrupción del timer1.


   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER1);

Se establece el valor inicial de conteo para el registro del timer1,


set_timer1(65526); //inicializa el contador del timer1 (10 pulsos)

Se define el LED indicador como salida.


#define salida pin_d0

Cuando el registro del timer1 cuente hasta 65536 se desbordará y se habilitará la interrupción del timer1, en la subrutina de  la interrupción se encenderá un led para indicar el desbordamiento y se resetea el registro del timer1 en el valor inicial de conteo.


#INT_TIMER1 //interrupcion por desbordamiento del timer1
void reset_timer ()
{
   output_bit(salida, 1);
   delay_ms(3000);
   output_bit(salida, 0);

   set_timer1(65526); //inicializa el contador del timer1
}

El registro del timer1 se puede leer con la función «get_timer1()».


contador = get_timer1(); //Lectura del timer1

Finalmente se muestra el valor del registro del timer1.


void mostrar()
{
      char texto[20];

      sprintf(texto,"Valor=%05lu", contador);
      OLED_DrawText(1,1,texto,1);

      OLED_Display();//Muestra la información en pantalla;
}

Código completo Contador


#FUSES NOMCLR

#use i2c(Master, Fast, sda=PIN_B0, scl=PIN_B1, force_sw, stream=OLED_stream)//parametros I2C

#define SH1106_128_64 //DEFINE EL MODELO DE LA PANTALLA OLED
//#define SSD1306_128_64

#include "OLED_I2C.c" //libreria oled I2C

#define salida pin_d0

int16 contador;

#INT_TIMER1 //interrupcion por desbordamiento del timer1
void reset_timer ()
{
   output_bit(salida, 1);
   delay_ms(3000);
   output_bit(salida, 0);

   set_timer1(65526); //inicializa el contador del timer1
}

void mostrar()
{
      char texto[20];

      sprintf(texto,"Valor=%05lu", contador);
      OLED_DrawText(1,1,texto,1);

      OLED_Display();//Muestra la información en pantalla;
}

void main()
{  
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); // flanco de subida
   
   set_timer1(65526); //inicializa el contador del timer1 (10 pulsos)

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER1);
   
   OLED_Begin();
   OLED_ClearDisplay();
   
   while(TRUE)
   {
      contador = get_timer1(); //Lectura del timer1
      mostrar();
   }

}

Ejemplo 5: Oscilador secundario, generador se señal

El timer1 cuenta con un oscilador secundario independiente del oscilador principal del microcontrolador. Es utilizado para generar una señal de reloj de baja frecuencia para el funcionamiento de diferentes módulos.

Formulas

Circuito de conexión

Procedimiento 

Para el siguiente ejemplo, se calculan los valores necesarios para generar una señal de reloj de salida con un ancho de pulso de 1 segundo. 

Inicialmente se habilita el timer1 con el prescaler calculado.

   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT); 

Se habilita la interrupción del timer1.


   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER1);

Se inicializa el timer1 con el valor calculador «TMR1»


set_timer1(32768); //Inicializa el timer1

Se define el pin de salida de la señal.


#define salida pin_d0

Cuando el timer1 genera el desbordamiento se habilita la interrupción. La interrupción baja a la subrutina donde se resetea el timer1 al valor calculado (TMR1) y se cambia el estado del pin de salida.


#INT_TIMER1 //interrupcion por desbordamiento del timer1
void reset_timer()
{
   set_timer1(32768); //Resetea el timer1
   output_toggle(salida); //cambia el estado del pin_d0 (1/0)
}

Código completo oscilador secundariogenerador de señal 


#FUSES NOMCLR

#define salida pin_d0

#INT_TIMER1 //interrupcion por desbordamiento del timer1
void reset_timer()
{
   set_timer1(32768); //Resetea el timer1
   output_toggle(salida); //cambia el estado del pin_d0 (1/0)
}

void main()
{
   setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT); 
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER1);
   
   set_timer1(32768); //Inicializa el timer1

   while(TRUE)
   {
      
      //TODO: User Code
   }

}
Scroll al inicio