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

En esta sección aprenderás a realizar diferentes aplicaciones utilizando el Timer0 del microcontrolador PIC, se realizara un generador de señal, una señal PWM, un temporizador de señal y un contador de pulsos.

¿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 0

El Timer0 es un temporizador de 8 bits y 16 bits con un preescalador de 8 bits. Puede ser utilizado para medir el tiempo (Temporizador) o como contador de pulsos (contador). Además, este temporizador está estrechamente relacionado con la operación de los módulos del sistema de comunicación USB y del reloj interno del dispositivo.

Ejemplo 1: Generador de señal

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

Timer 0

Para poder medir el tiempo se debe contemplar lo siguiente:

  • Fosc: La frecuencia del oscilador (clock) del microcontrolador.
  • Preescaler:  Divide la frecuencia del oscilador para disminuirla.
  • Registro 8 o 16 Bits: Determina el valor del tiempo máximo que puede registrar el Timer0.
  • Overflow: El tiempo máximo que puede generar/medir el registro del timer0.
  • TMR0: Valor para establece el tiempo de desbordamiento.
Timer 0 8 bits

Para determina el tiempo máximo que se puede registrar en el timer0 para generar una señal se calcula el «overflow» y para establecer el ancho de pulso de la señal de salida se calcula el «TMR0».

En la instrucción para habilitar el timer0 de 8bits se coloca el prescaler establecido.

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_Prescaler|RTCC_8_BIT); //  Habilita el Timer0 a 8 bits

En la instrucción para establece el ancho de pulso de la señal del timer0 se coloca el valor «TMR0» obtenido.

set_timer0(TMR0);

Se establece el oscilador del microcontrolador utilizado para obtener el «overflow» (Fosc). 

#use delay(crystal = Fosc);

Para los PIC18 se puede utilizar el oscilador interno. 

nota: revisar la hoja de datos para verificar los valores que se pueden establecer.

#use delay(internal = Fosc);

Timer 0 16 bits 

El timer0 a 16 bits solo se puede utilizar en algunos microcontroladores como los PIC18.

Para determina el tiempo máximo que se puede registrar en el timer0 para generar una señal se calcula el «overflow» y para establecer el ancho de pulso de la señal de salida se calcula el «TMR0».

En la instrucción para habilitar el timer0 de 16bits se coloca el prescaler establecido.

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_Prescaler);  // Habilita en timer a 16 bits

En la instrucción para establece el ancho de pulso de la señal del timer0 se coloca el valor «TMR0» obtenido.

set_timer0(TMR0);

Se establece el oscilador del microcontrolador utilizado para obtener el «overflow» (Fosc). 

#use delay(crystal = Fosc);

Para los PIC18 se puede utilizar el oscilador interno. 

nota: revisar la hoja de datos para verificar los valores que se pueden establecer.

#use delay(internal = Fosc);

En el ejemplo siguiente se realizan las las ecuaciones para obtener una señal de salida de 60Hz.

Circuito de conexión

Procedimiento 

Inicialmente se calculan los valores para establecer el preescaler, la frecuencia del oscilador y el valor para establecer la señal de salida utilizando un timer 0 de 8bits.

Nota: Realizar los cálculos con todos los decimales, esto ayudara a obtener los valores más precisos y, por lo tanto, una señal de salida más precisa. 

Se define el pin de salida para la señal generada por el timer0.


#define salida pin_d0

Se habilita el timer0 con el «prescaler» que se estableció al calcular el «overflow»


setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT); //overflow

Se habilita la interrupción por desbordamiento del timer0.


   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER0);

Se inicializa el timer0 con el valor del «TMR0» calculado.


set_timer0(93);//Inicializa el timer0

Cuando el timer0 se desborda, se habilita la interrupción «#int_timer0» y pasa a la subrutina «reset_timer()» donde se resetea el timer0 y se cambia de estado la salida del «pin_d0».


#int_timer0 //interrupcion por desbordamiento del timer0
void reset_timer()
{
   set_timer0(93); //Resetea el timer0
   output_toggle(salida); //cambia el estado del pin_d0 (1/0)    
}
Archivo .h

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


#use delay(crystal=20000000)

Código completo generador de señal


#FUSES NOMCLR

#define salida pin_d0

#int_timer0 //interrupcion por desbordamiento del timer0
void reset_timer()
{
   set_timer0(93); //Resetea el timer0
   output_toggle(salida); //cambia el estado del pin_d0 (1/0)    
}

void main()
{
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT); //overflow
    
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER0);
   
   set_timer0(93);//Inicializa el timer0
    
   while(TRUE)
   {         

   }
}

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.

Se utilizaran los mismos pasos del ejemplo 1.

Circuito de conexión

Procedimiento 

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

Se habilita la conversión analógica digital.


setup_adc(ADC_CLOCK_INTERNAL);

Se habilita el canal ANo y se realiza la lectura para guardar el valor en la variable «POT».


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

Se calcula un delay para controlar el ancho de pulso de la señal multiplicando el valor del «POT» por el «ancho de pulso» calculado 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 generada. 


#int_timer0 //interrupcion por desbordamiento del timer0
void reset_timer()
{
   set_timer0(93); //Resetea el timer0
   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)
}

Código completo señal PWM


#FUSES NOMCLR

#define salida pin_d0

int16 POT;
float tiempo;
 
#int_timer0 //interrupcion por desbordamiento del timer0
void reset_timer()
{
   set_timer0(93); //Resetea el timer0
   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_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT); //overflow
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER0);
   
   set_timer0(93);//Inicializa el timer0
   
   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 utilizara el timer0 como temporizador para obtener la medición del ancho de pulso de una señal del entrada.

Timer  0 8 bits

Para establecer las instrucciones del timer 0 se debe establecer el ancho de pulso máximo que se puede medir con la formula del «overflow».

Timer 0 16 bits

El timer0 a 16 bits solo se puede utilizar en algunos microcontroladores como los PIC18.

Para establecer las instrucciones del timer 0 se debe establecer el ancho de pulso máximo que se puede medir con la formula del «overflow».

Circuito de conexión

Procedimiento 

Se calcula el ancho de pulso máximo que se puede medir «overflow».

Se habilita el timer 0 con la instrucción para establecer el ancho de pulso máximo que se puede medir «overflow».


setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT); //overflow

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 entrada de la 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_timer0()» registra el valor del tiempo y se guarda en la variable «val_timer»


#INT_EXT2
void reset_timer()
{
     set_timer0(0);//Inicializa el timer0
     while(entrada)
     {}
     val_timer = get_timer0();//lectura el timer0
}

Como el valor del timer 0 es registrado en un valor del 8 bits, se calcula el tiempo registrado en milisegundos realizando una regla de 3 con el «overflow». 


tiempo = ((int16)val_timer*13.107)/256;

Finalmente se muestra el 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

int8 val_timer;
float tiempo;

#INT_EXT2
void reset_timer()
{
     set_timer0(0);//Inicializa el timer0
     while(entrada)
     {}
     val_timer = get_timer0();//lectura el timer0
}

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_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT); //overflow
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_EXT2);
   
   OLED_Begin();
   OLED_ClearDisplay();

   while(TRUE)
   {

       tiempo = ((int16)val_timer*13.107)/256;
       
       mostrar();
      //TODO: User Code
   }

}

Ejemplo 4: Contador

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

Se establecen las instrucciones para el timer0 como contador de acuerdo con los parámetros establecidos.

Timer 0 8 bits 

EL valor maximo que puede contar el timer0 es de 256 (8 bits).

Timer 0 16 bits 

El timer0 a 16 bits solo se puede utilizar en algunos microcontroladores como los PIC18.

EL valor máximo que puede contar el timer0 es de 65535 (16 bits).

Pin de entrada del Timer 0

El pin de entrada para el timero como contador es el pin «T0CKI» o en este caso también es el pin «RA4».

Circuito de conexión

Procedimiento 

Se habilita el timer0 como contador, con un prescalador de 1 y por flanco de subida.


   setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_1|RTCC_8_BIT); //Por flanco de subida
   //setup_timer_0(RTCC_EXT_H_TO_L|RTCC_DIV_1|RTCC_8_BIT); //flanco de bajada

Se inicia el contador con un valor inicial de conteo de 246.


set_timer0(246); //inicializa el contador del timer0 (10 pulsos)

Cuando el timer0 termine de contar hasta 256 (timer0 a 8 bits) se habilitara la interrupción «INT_TIMER0»


   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER0);

Se define el LED indicador como salida.


#define salida pin_d0

Cuando se habilita la interrupción por desbordamiento del timer0, inicialmente se encenderá un LED indicando el desbordamiento y después se resetea el contador del timer al valor inicial de conteo.


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

   set_timer0(246); //inicializa el contador del timer0
}

EL valor registrado en el timer0 se puede consultar con «get_timer()» y se guarda en la variable contador.


 contador = get_timer0();

Finalmente se muestra el valor del timer0 en la pantalla OLED.


void mostrar()
{
      char texto[20];

      sprintf(texto,"Valor=%03u", contador);
      OLED_DrawText(1,1,texto,1);

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

NOTA: Se deben considerar los rebotes que puede generar el botón, ya que el contador del «timer0» no genera ningún «delay» al detectar el flanco de subida o bajada del pulso, por lo que esto puede afectar el conteo de los pulsos. Es recomendable colocar un circuito antirrebote con un capacitor.

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

int8 contador;

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

   set_timer0(246); //inicializa el contador del timer0
}

void mostrar()
{
      char texto[20];

      sprintf(texto,"Valor=%03u", contador);
      OLED_DrawText(1,1,texto,1);

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

void main()
{
   setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_1|RTCC_8_BIT); //Por flanco de subida
   //setup_timer_0(RTCC_EXT_H_TO_L|RTCC_DIV_1|RTCC_8_BIT); //flanco de bajada

   set_timer0(246); //inicializa el contador del timer0 (10 pulsos)

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER0);
   
   OLED_Begin();
   OLED_ClearDisplay();

   while(TRUE)
   {
      contador = get_timer0();
      mostrar();        
   }

}
Scroll al inicio