El Timer 1 como Contador/Temporizador

Buenos dias ! tengo una consulta, estoy aprendiendo a programar el timer 1 del pic16f1826 como un contador. Por lo que vi, debo manipular los registros para habilitar un pin especifico (T1CKI) y enviarle pulsos de manera que incremente el contador del timer 1. Mi consulta es, como calculo cuantas unidades aumenta el timer durante la duracion del pulso?? Generalmente uso frecuencia de 4Mhz y prescalador en 1 para trabajar.
 
El contador solo aumenta en 1 durante el pulso (el temporizador está funcionando en modo contador):
When enabled to count, Timer1 is incremented on the rising edge of the external clock input T1CKI or the capacitive sensing oscillator signal.
Si necesitas una medida de tiempo (por ejemplo, un segundo), puedes probar a usar el temporizador 0 para que obtenga el valor del temporizador 1 pasado un segundo de tiempo, y luego lo ponga a 0 para el siguiente periodo. Es una manera de contar pulsos externos usando periodos concretos de tiempo.
 
El temporizador tiene cuatro fuentes de reloj distintas. Una de ellas es igual a la velocidad del sistema (Fosc) y otra es la cuarta parte de ese valor (Fosc/4). Entonces, si está funcionando a 4 Mhz, con un reloj Fosc, tenemos: 1 s/4×10⁶ = 0,25 µs

Entonces, 20 000 * 0,25 µs = 5 ms

Necesitas 4 veces más.

O usar la frecuencia de reloj Fosc/4, con lo que entonces ya tienes 1 µs
 
Los temporizadores cuentan por si solos en función del reloj escogido. Si ese reloj es externo, lo que hace es contar pulsos externos. Lo que nunca hace es incrementar n unidades por pulso. Si quieres contar pulsos externos, tal y como lo planteas en el primer mensaje (definir el reloj como externo en la patilla T1CKI), pues entonces ya los estás contando. El problema es ahora que necesitas otra base de tiempos (interna o externa al microcontrolador) que diga que ha pasado 1 segundo, y así leer el número de pulsos contados en el temporizador 1.

Hay otra opción. Este microcontrolador también puede funcionar en como Capture. En este modo, el temporizador 1 está contando por sí solo, y cuando se produce un evento, el valor del temporizador se copia a los registros CCPRx. Puedes indicar que se active la interrupción CCPxIF y de esa manera reiniciar el temporizador 1, para la siguiente vez que se produzca el evento.

De esta manera, el temporizador 1 está "contando" el tiempo que pasa entre cada par de eventos externos en los pines CCPx.
 
No, no se incrementa en 8000. Ya te hemos dicho que los temporizadores en modo contador siempre van de uno en uno.

El montaje propuesto que nos has enlazado es muy curioso: para mostrar cómo usar el temporizador 1 en modo contador, usa un LED externo para provocar la señal cuadrada que entra en T1CKI.

El funcionamiento es así:
· Se pone el temporizador en modo contador y se entra en el bucle sin fin.
· Dentro del bucle, se mira qué valor tiene el temporizador. Si coincide con alguno de los valores del switch-case, se iluminan los LED externos.
· Y luego, se invierte el valor de RD1, provocando el apagado/encendido del LED puesto encima de la LDR, que a su vez provoca el flanco de subida/bajada en T1CKI.
· Finalmente, una espera de 20 ms antes de repetir el bucle.

Tenemos entonces un bucle que se repite cada 20 ms, generando una señal cuadrada en RD1, que provoca otra señal cuadrada en T1CKI, y eso es lo que cuenta TMR1. El resultado será que TMR1 se incrementa cada 40 ms. Y si el primer LED de PORTB se enciende al llegar a 8000, eso significa que lo hará en 8000 * 40 ms = 320 s. Y sabiendo que TMR1 desborda a los 65535, los LED se apagan al volver a 0 (al cabo de casi 44 minutos).
 
Perfecto, gracias por sus respuestas, me han sacado las dudas que tenia con el mismo, intentare hacer un codigo en XC8 para probar el mismo y comprobare el resultado!
 
Hola a todos, estoy experimentando para hacer un temporizador al que se le pueda programar el tiempo de temporizado y el tiempo de encendido y apagado del dispositivo acoplado al microcontrolador. Estoy usando un 16f886, no tengo experiencia en el uso de los timer y evidentemente no me esta funcionado bien el programex, seguramente he obviado algunas cosas. Paso el programa por acá y adjuntos los archivos del compilador PCW y el esquema de proteus. Desde ya gracias por su ayuda y saludos a todos. cuando funcione y pula un poco el programa a Counter y a BLLCD los voy a usar para apagar el backlight del lcd.

Código:
#include <16F886.h>

#device adc=8

#fuses INTRC_IO,WDT,PUT,MCLR,NOPROTECT,NOCPD,NOBROWNOUT

#fuses NOIESO,NOFCMEN,NOWRT,NODEBUG,NOLVP

#use delay(clock=4M)

#define use_portb_lcd TRUE

#include <lcd.c>

#define SW1 PIN_A1 //PORTA RA1

#define SW2 PIN_A2 //PORTA RA2

#define SW3 PIN_A3 //PORTA RA3

#define SW4 PIN_A4 //PORTA RA4

#define SW5 PIN_A5 //PORTA RA5

#define bomba PIN_C4 //PORTA RC4

#define BLLCD PIN_C3 //luz backlight

#use fast_io(A)   // Configuración rápida del puerto A

#use fast_io(B)  // Configuración rápida del puerto B

#use fast_io(C) // Configuración rápida del puerto C



//******* Variables *******//

  int min=0, seg=0, tempo=10, onoff=10,suma=0, cont=0, counter=0;

    

#int_TIMER1

void temp1s(void)

{

  cont++;

  if (cont==2)

  {

  seg++;

  cont=0;

  }

  set_timer1 (3036);

  if (seg==59)

  {

  seg=0;

  min++;

  }

}





// ************** Programa Principal ************** //

void main()

{



   tempo=10;

   onoff=10;

   suma=0;

   set_tris_a(0x3E);

   set_tris_b(0x00);

   set_tris_c(0x00);

 

   setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8);

   set_timer1 (3036);

   enable_interrupts(INT_TIMER1);

   enable_interrupts(global);

   lcd_init (); // Inicializa la libreria para manejar el LCD.

   output_high(BLLCD);

   printf ( LCD_PUTC, "\f" ); // Limpia la LCD.

   lcd_gotoxy(1,1);

   printf(lcd_putc,"Config Inicial");

   delay_ms(500);

            

   while(true){

   lcd_gotoxy(1,2);

   printf(lcd_putc,"TEMPO:%d",tempo);

   lcd_gotoxy(9,2);          //Acomoda cursor LCD

   printf(lcd_putc,"onoff:%d",onoff);

   if(!input(SW1)){

   tempo--;

   output_high(BLLCD);

   counter=0;

   }

   if(!input(SW2)){

   delay_ms(1);

   tempo++;

   output_high(BLLCD);

   counter=0;

   }

   if(!input(SW3))

   {

   delay_ms(1);

   onoff--;

   output_high(BLLCD);

   counter=0;

   }

   if(!input(SW4))

   {

   delay_ms(1);

   onoff++;

   output_high(BLLCD);

   counter=0;

   }

   if(!input(SW5))

   break;

   }

 

   while(true)

   {

   lcd_gotoxy(1,2);

   printf(lcd_putc,"Tempo:%d",tempo);

   lcd_gotoxy(9,2);

   printf(lcd_putc,"off:%d:",onoff);

   lcd_gotoxy(1,1);

   printf(lcd_putc,"min:%d:",min);



   if (min==tempo)

   {

   output_high(bomba);

   suma= min+onoff;

   lcd_gotoxy(8,1);

   printf(lcd_putc,"Bomba on");

   lcd_gotoxy(1,1);

   printf(lcd_putc,"min:%d          ",min);

   } 

   if (min==suma)

   {

   output_low(bomba);

   lcd_gotoxy(8,1);

   printf(lcd_putc,"Bomba off ",);

   lcd_gotoxy(1,1);

   printf(lcd_putc,"min:%d:",min);

   min = 0;

   }   

   delay_ms(200);

   counter++;

   }

}
 

Adjuntos

  • Temporizador.rar
    4.9 MB · Visitas: 30
Última edición por un moderador:
Hola amigos, tengo algunas dudas hacer el TMR1 en modo contador sincrono.
Estoy usando el pic16f877A. Cable aclarar que solo es una duda pues no tengo problemas en algún circuito en espesiífico.

Alguien me podría aclarar en que momentos deberia usar el bit TYSINC del egistro T1CON o como logra y para que sirve la sincronización ?

Datos que conozco:
- Segun la hoja de datos e información de la red se usa para sincronizar el reloj externo puesto en los pines T1OSO Y T1OSI o en el pin T1CKI.
- Se usa en caso se quiera usar el TMR1 como contador sincrono.

La mayor información de la red dice esto:
TYSINC: con esto le digo al compilador que la señal de reloj externa se sincronice con la señal de reloj principal. Como se ve en el diagrama de bloques la sincronización se produce después del preescaler, por lo que hasta después del preescaler la señal sigue siendo asíncrona.

Esa definición no me es suficiente

Gracias!!
 
Seguramente te debes referir al registro T1SYNC, porque TYSINC no existe.
La hoja de datos lo describe muy claro.

T1SYNC: Timer1 External Clock Input Synchronization Control bit
When TMR1CS = 1:
Cuando TMR1CS = 1:
1 = Do not synchronize external clock input
1 = No sincronizar la entrada del reloj externo
0 = Synchronize external clock input
0 = Sincronizar la entrada del reloj externo
When TMR1CS = 0:
Cuando TMR1CS = 0:
This bit is ignored. Timer1 uses the internal clock when TMR1CS = 0
Este bit es ignorado. El Timer1 usará el reloj interno cuando TMR1CS = 0

Así que prácticamente se menciona que el Timer 1 se sincronizará con un reloj externo cuando el bit TMR1CS sea 1
De otra forma, o sea, con TMR1CS = 0, el Timer 1 se sincronizará con el reloj interno.

TMR1CS: Timer1 Clock Source Select bit
1 = External clock from pin RC0/T1OSO/T1CKI (on the rising edge)
1 = Reloj externo del pin RC0/T1OSO/T1CKI (en el flanco ascendente)
0 = Internal clock (FOSC/4)
0 = Reloj interno (Frecuencia de oscilación / 4)

Por lo tanto, si se selecciona la sincronización externa para el Timer 1, se podrá usar otra frecuencia de reloj.
Esto se usa, por ejemplo, para sincronizar el Timer 1 con un cristal de 32768 Hz en los pines T1OSO, T1OSI y obtener un desborde de 1 Hz.
Algo bastante usado para realizar un reloj en tiempo real (RTC)

T1OSC.png
 
En realidad si que influye el cristal en la capacidad de conteo de los contadores, pero ya es un tema rebuscado, hay que leer el datasheet, seguramente en un Pic de 4MHz lo máximo que se puede contar es 1MHz ya que internamente divide por 4. Para frecuencias "normales" no tiene que haber problemas.
En su día lo miré para los 8052 y creo recordar que allí era 1/12 de la frecuencia del cristal lo máximo contable.
La verdad es que nunca he usado los contadores aunque los veo útiles para encoders y cosas semejantes que ocuparían mucha CPU si se hace por programa y con el contador sencillamente van solos.

Algunos derivados disponen de unidades de comparación captura, que encuentro mucho más interesante que permiten leer anchos de pulsos y cosas muy curiosas.
 
Buenas
Veo varios problemas en tu código:
1 - El Fuse WDT esta activado lo que hace que tu programa se reinicie cada 2 segundos, lo mejor seria que los cambies por NOWDT para desactivarlo
2 - te falta anti rebotes para tus botones
3- al iniciar tu programa ya se activa el timer1, lo que hace que cuando pulses el botón para iniciar el temporizador ya estaría con varios segundos , lo mejor seria que lo activaras el timer1 cuando pulses el botón inicio.(eso se hace con cambiar el enable_interrupts(INT_TIMER1 ); a la rutina de botón de inicio).
En cuanto al configuración del timer1 esta bien, se podría mejorar la estructura de tu código creando subfunciones. Pero eso te lo dejo para que lo analices.
 
1000 gracias Roberto. Me quedó mucho más clara la utilización del timer1.
Ya está funcionando, y lo necesito así, un ciclo repetitivo de encendido/corte, ahora lo mejoro con un par de funciones.
Lo único que tengo dudas es que según tengo entendido a esta velocidad de micro y con el TMR1 a 3036 me estaría dando 500 ms de desbordamiento.
O sea que la opción if (cont==2) dentro de la interrupción, ¿estaría bien para que alcance el segundo?
Saludos y gracias.
C:
#include <16F886.h>

#device adc=8

#fuses INTRC_IO,NOWDT,PUT,MCLR,NOPROTECT,NOCPD,NOBROWNOUT

#fuses NOIESO,NOFCMEN,NOWRT,NODEBUG,NOLVP

#use delay(clock=4M)

#define use_portb_lcd TRUE

#include <main.h>

#include <lcd.c>

#define SW1 PIN_A1 //PORTA RA1

#define SW2 PIN_A2 //PORTA RA2

#define SW3 PIN_A3 //PORTA RA3

#define SW4 PIN_A4 //PORTA RA4

#define SW5 PIN_A5 //PORTA RA5

#define bomba PIN_C4 //PORTA RC4

#define BLLCD PIN_C3 //luz backlight

#use fast_io(A)   // Configuración rápida del puerto A

#use fast_io(B)  // Configuración rápida del puerto B

#use fast_io(C) // Configuración rápida del puerto C


//******* Variables *******//

  int min=0, seg=0, tempo=10, onoff=10,suma=0, cont=0;


#int_TIMER1

void temp1s(void)

{

  cont++;

  if (cont==2)

  {

  seg++;

  cont=0;

  }

  set_timer1 (3036);

  if (seg==59)

  {

  seg=0;

  min++;

  }

}


// ************** Programa Principal ************** //

void main()

{


   set_tris_a(0x3E);

   set_tris_b(0x00);

   set_tris_c(0x00);

 

   setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8);

   set_timer1 (3036);

   enable_interrupts(global);

   lcd_init (); // Inicializa la libreria para manejar el LCD.

   output_high(BLLCD);

   printf ( LCD_PUTC, "\f" ); // Limpia la LCD.

    lcd_gotoxy(1,1);

   printf(lcd_putc,"Config Inicial");

   delay_ms(500);

            

   while(true){

 

  if(tempo<10){

  lcd_gotoxy(1,2);

  printf(lcd_putc,"Time:%d ",tempo);}

  else{

  lcd_gotoxy(1,2);

  printf(lcd_putc,"Time:%d",tempo);}

  if(onoff<10){

  lcd_gotoxy(9,2);

  printf(lcd_putc,"onoff:%d ",onoff);}

  else{

  lcd_gotoxy(9,2);

  printf(lcd_putc,"onoff:%d",onoff);}


   if(!input(SW1)){

   delay_ms(300);

   tempo--;

   output_high(BLLCD);

   }

   if(!input(SW2)){

   delay_ms(300);                           

   tempo++;

   output_high(BLLCD);

   }

   if(!input(SW3))

   {

   delay_ms(300);                               

   onoff--;

   output_high(BLLCD);

   }

   if(!input(SW4))

   {

   delay_ms(300);                               

   onoff++;

   output_high(BLLCD);

   }

   if(!input(SW5)){

   delay_ms(300);

   enable_interrupts(INT_TIMER1);

   break;

   }

   }

    

   while(true)

   {

   lcd_gotoxy(1,2);

   printf(lcd_putc,"Time:%d",tempo);

   lcd_gotoxy(9,2);

   printf(lcd_putc,"onoff:%d",onoff);

   lcd_gotoxy(1,1);

   printf(lcd_putc,"min:%d ",min);

   suma= tempo+onoff;

    if(min==1){

   output_low(BLLCD);

   }

 

   if (min==tempo && min<=suma)

   {

   if(min==1){

   output_low(BLLCD);

   }

   output_high(bomba);

   lcd_gotoxy(8,1);

   printf(lcd_putc,"Bomba on ");

   lcd_gotoxy(1,1);

   printf(lcd_putc,"min:%d ",min);

   } 

   if (min==suma)

   {

   output_low(bomba);

   lcd_gotoxy(8,1);

   printf(lcd_putc,"Bomba off");

   lcd_gotoxy(1,1);

   printf(lcd_putc,"min:%d ",min);

   min = 0;

   }   

   delay_ms(200);

   }

}

Y acá uno también cíclico con funciones que se puede configurar cuando uno quiera. Para que sea de un solo temporizado solo hay que agregarle un break al ultimo if.


#include <main.h>

#include <lcd.c>

#define SW1 PIN_A1 //PORTA RA1

#define SW2 PIN_A2 //PORTA RA2

#define SW3 PIN_A3 //PORTA RA3

#define SW4 PIN_A4 //PORTA RA4

#define SW5 PIN_A5 //PORTA RA5

#define bomba PIN_C4 //PORTA RC4

#define BLLCD PIN_C3 //luz backlight

#use fast_io(A)   // Configuración rápida del puerto A

#use fast_io(B)  // Configuración rápida del puerto B

#use fast_io(C) // Configuración rápida del puerto C


//******* Variables *******//

int min=0, seg=0, tempo=10, onoff=10,suma=0, cont=0;

void ajustes (void);

void pausa (void);

#int_TIMER1

void temp1s(void)

{

  cont++;

  if (cont==2)

  {

  seg++;

  cont=0;

  }

  set_timer1 (3036);

  if (seg==59)

  {

  seg=0;

  min++;

  }

}


void pausa (void){

while(1){

delay_ms(100);

if(!input(SW5)){

ajustes();

return;

}}}


void ajustes (void){

   printf ( LCD_PUTC, "\f" );

   lcd_gotoxy(1,1);

   printf(lcd_putc,"Configuracion");

   delay_ms(500);

            

   while(true){

 

  if(tempo<10){

  lcd_gotoxy(1,2);

  printf(lcd_putc,"Time:%d ",tempo);}

  else{

  lcd_gotoxy(1,2);

  printf(lcd_putc,"Time:%d",tempo);}

  if(onoff<10){

  lcd_gotoxy(9,2);

  printf(lcd_putc,"onoff:%d ",onoff);}

  else{

  lcd_gotoxy(9,2);

  printf(lcd_putc,"onoff:%d",onoff);}


   if(!input(SW1)){

   delay_ms(400);

   tempo--;

   output_high(BLLCD);

   }

   if(!input(SW2)){

   delay_ms(400);                           

   tempo++;

   output_high(BLLCD);

   }

   if(!input(SW3))

   {

   delay_ms(400);                               

   onoff--;

   output_high(BLLCD);

   }

   if(!input(SW4))

   {

   delay_ms(400);                               

   onoff++;

   output_high(BLLCD);

   }

   if(!input(SW5)){

   delay_ms(400);

   enable_interrupts(INT_TIMER1);

   return;

   }

   }

}





// ************** Programa Principal ************** //

void main()

{


   set_tris_a(0x3E);

   set_tris_b(0x00);

   set_tris_c(0x00);

 

   setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8);

   set_timer1 (3036);

   enable_interrupts(global);

   lcd_init (); // Inicializa la libreria para manejar el LCD.

   output_high(BLLCD);

   printf ( LCD_PUTC, "\f" ); // Limpia la LCD.

   printf ( LCD_PUTC, "Press Start" );

   Pausa();

    

   while(true)

   {

   lcd_gotoxy(1,2);

   printf(lcd_putc,"Time:%d",tempo);

   lcd_gotoxy(9,2);

   printf(lcd_putc,"onoff:%d",onoff);

   lcd_gotoxy(1,1);

   printf(lcd_putc,"min:%d ",min);

   suma= tempo+onoff;

    if(!input(SW5)){

    Pausa();

    }

    if(min==1){

   output_low(BLLCD);

   }

 

   if (min==tempo && min<=suma)

   {

   if(min==1){

   output_low(BLLCD);

   }

   output_high(bomba);

   lcd_gotoxy(8,1);

   printf(lcd_putc,"Bomba on ");

   lcd_gotoxy(1,1);

   printf(lcd_putc,"min:%d ",min);

   } 

   if (min==suma)

   {

   output_low(bomba);

   lcd_gotoxy(8,1);

   printf(lcd_putc,"Bomba off");

   lcd_gotoxy(1,1);

   printf(lcd_putc,"min:%d ",min);

   min = 0;

   }   

   delay_ms(200);

   }

}
 
Asi es, con la precarga del timer1 con (3036) se desborda cada 500ms a 4Mhz de reloj del pic, lo que (cont==2) te daria el segundo
Código:
#int_TIMER1
void temp1s(void)
{
  cont++;
   output_toggle(pin_c7); //Parpadeo de led cada 500ms por el pin c7
    set_timer1 (3036);
  if (cont==2) 
  {
  seg++;
  cont=0;
 
  }
 
  if (seg>59)
  {
  seg=0;
  min++;
  }
}
Un consejo, cuando uses timer, evita usar delays en tu código, el delay lo que hace es detener por completo el micro, lo que afectaría a tus timers, en ajustes puedes utilizar este código para los anti rebotes de tu botones:
Código:
 if(!input(SW1)){
          while(!input(sw1)){}
   tempo--;
   output_high(BLLCD);
   counter=0;
   }
 
Seguramente te debes referir al registro T1SYNC, porque TYSINC no existe.
La hoja de datos lo describe muy claro.

T1SYNC: Timer1 External Clock Input Synchronization Control bit
When TMR1CS = 1:
Cuando TMR1CS = 1:
1 = Do not synchronize external clock input
1 = No sincronizar la entrada del reloj externo
0 = Synchronize external clock input
0 = Sincronizar la entrada del reloj externo
When TMR1CS = 0:
Cuando TMR1CS = 0:
This bit is ignored. Timer1 uses the internal clock when TMR1CS = 0
Este bit es ignorado. El Timer1 usará el reloj interno cuando TMR1CS = 0

Así que prácticamente se menciona que el Timer 1 se sincronizará con un reloj externo cuando el bit TMR1CS sea 1
De otra forma, o sea, con TMR1CS = 0, el Timer 1 se sincronizará con el reloj interno.

TMR1CS: Timer1 Clock Source Select bit
1 = External clock from pin RC0/T1OSO/T1CKI (on the rising edge)
1 = Reloj externo del pin RC0/T1OSO/T1CKI (en el flanco ascendente)
0 = Internal clock (FOSC/4)
0 = Reloj interno (Frecuencia de oscilación / 4)

Por lo tanto, si se selecciona la sincronización externa para el Timer 1, se podrá usar otra frecuencia de reloj.
Esto se usa, por ejemplo, para sincronizar el Timer 1 con un cristal de 32768 Hz en los pines T1OSO, T1OSI y obtener un desborde de 1 Hz.
Algo bastante usado para realizar un reloj en tiempo real (RTC)

Ver el archivo adjunto 174270
La información que me das abunda por internet y no digo que no sa obvio o irreal, solo que me gustaria saber más cosas sobre ese registro.
Muchas gracias!
 
Atrás
Arriba