Autor Tema: Como configurar el timer 1 en modo contador  (Leído 9257 veces)

0 Usuarios y 2 Visitantes están viendo este tema.

Desconectado Trev

  • PIC16
  • ***
  • Mensajes: 115
Como configurar el timer 1 en modo contador
« en: 02 de Octubre de 2009, 19:53:10 »
Hola,queria saber si alguein me puede dar una mano de como configurar el timer1 en modo contador,lo que quiero hacer es un reloj usando un cristal externo de 32.768 Hz pero no se como conectar este y no me queda claro que instruccion usar si
setup_timer_1(T1_CLK_OUT I T1_DIV_BY_1) o T1_EXTERNAL y la ecuacion del timer no me queda no la recuerdo bien
no se si era asi:
T=(65536-T1INICIAL)xToscXPREESCALER donde Tosc seria de 1/32768 Hz,estoy lejos de mi casa y me olvide toda la documentacion estoy en un ciber si alguien me ayuda se lo agradeceré.Gracias.

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Como configurar el timer 1 en modo contador
« Respuesta #1 en: 03 de Octubre de 2009, 01:06:48 »
Hola.

El código seria mas o menos así:

Código: C#
  1. #int_TIMER1
  2. void Reloj_isr(void)
  3. {
  4.  //Aqui tu código
  5.  set_timer1(32768);
  6. }
  7.  
  8. ...
  9.  
  10. void main (void)
  11. {
  12.  ..
  13.  setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT);
  14.  enable_interrupts(INT_TIMER1);
  15.  enable_interrupts(GLOBAL);
  16.  set_timer1(32768);
  17.  ...
  18. }

No te olvides de colocar los condensadores a tierra para el cristal.

Saludos
El papel lo aguanta todo

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Como configurar el timer 1 en modo contador
« Respuesta #2 en: 03 de Octubre de 2009, 01:54:05 »
MLO_ si configura el timer en preescaler 2 ya no necesita recargar el timer con 32768 y será mucho más preciso.   ;-) <<-- Error de cálculos  :mrgreen:

Edit: Se podría combinar el timer con el módulo CCP en modo captura y evento especial (Todo en conjunto funcionaria de la manera que trabaja el timer2 con PR2) para generar la interrupción automática sin recarga del timer logrando mayor precisión.-

Saludos!
« Última modificación: 13 de Octubre de 2009, 01:18:14 por Suky »
No contesto mensajes privados, las consultas en el foro

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Como configurar el timer 1 en modo contador
« Respuesta #3 en: 03 de Octubre de 2009, 11:54:00 »
Si?  :P No da lo mismo? Porque sería mas preciso? Porque nos ahorramos los ticks que toma cargar el timer? o hay alguna otra razón oculta por ahí? jeje

Saludos
El papel lo aguanta todo

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Como configurar el timer 1 en modo contador
« Respuesta #4 en: 03 de Octubre de 2009, 20:43:11 »
Lo oculto esta en los ciclos que utiliza en decidir que interrupción y atenderla. Porque por ejemplo:

1:1 -> | Habilito interrupción |Se genera interrupción | Recargo Timer | Se genera interrupción
CCP -> | Habilito interrupción |Se genera interrupción |                |Se genera interrupción


El desfasaje que se ve es porque en realidad se debería de recargar el timer justo después de ocurrida y no después de varias otras instrucciones "desconocidas" realizadas por CCS.


Saludos!
« Última modificación: 13 de Octubre de 2009, 01:18:58 por Suky »
No contesto mensajes privados, las consultas en el foro

Desconectado Trev

  • PIC16
  • ***
  • Mensajes: 115
Re: Como configurar el timer 1 en modo contador
« Respuesta #5 en: 06 de Octubre de 2009, 06:17:43 »
Muchisimas gracias pero lo hago de esa forma y no funciona :? ya tengo todo listo me faltaria la presición que me daria esto aca cuelgo el código

Código: [Seleccionar]
#include <16f877a.h>
#use delay(clock=4000000)
#fuses XT,PUT,NOPROTECT,NOWDT,NOLVP
#byte portb=6
#byte portc=7
#byte portd=8
#include <flex_lcd.c>
#use standard_io(b)
//#use fast_io(b)

#define SEGUNDOS_EN_UNA_HORA 3600
#define SEGUNDOS_EN_UN_MINUTO 60


int32 Conta_Segundos=0,MomentoActual=0;
int32 Horas=0,Minutos=0,Segundos=0;
int set,FLAG_TIMER1;
byte last_b;

void Mi_Hora(void);
void Cambiar_Hora(int32 *Horas,int32 *Minutos);
void reset(void)
{
Conta_Segundos=0;
Momentoactual=0;
}

#INT_TIMER1
timer1_rsi()
{
Mi_Hora();        //Pasado el segundo calculo la hora.
lcd_gotoxy(6,1);
printf(lcd_putc,"%02ld:%02ld:%02ld    ",Horas,Minutos,Segundos);
}

// Interrupcion RB4 - RB7 /////////////////////////////////////////////////////
#INT_RB
rb_isr()
{
    byte changes;
    changes=last_b^portb;       //XOR.
    last_b=portb;
    if (bit_test(changes,5) && !bit_test(last_b,5))
    {                                                     
         lcd_gotoxy(6,2);
         lcd_putc("..              ");    //Indica que se va a incrementar las horas.
         delay_ms(200);
         lcd_gotoxy(6,2);
         lcd_putc("                ");
         delay_ms(200);
         lcd_gotoxy(6,2);
         lcd_putc("..              ");
         if(set==1)
         {
         lcd_gotoxy(1,2);
         lcd_putc("        ..      ");   // Indica que se van a incrementar los minutos
         delay_ms(250);
         lcd_gotoxy(1,2);
         lcd_putc("                ");
         delay_ms(250);
         lcd_gotoxy(1,2);
         lcd_putc("        ..      ");
         }
         set+=1;
         if (set==2)
         set=0;   
    }
    if (bit_test(changes,6) && !bit_test (last_b,6))   //INCREMENTAR.
    {
    Cambiar_hora(&Horas,&Minutos);
    }
    if (bit_test(changes,7) && !bit_test (last_b,7))   //DECREMENTAR.
    {
    Cambiar_hora(&Horas,&Minutos);       
    }
    Conta_Segundos=(Minutos*60)+(Horas*3600)+Segundos;
    bit_clear(portb,0);          //Solo modifico el nibble bajo sin tocar el alto
    bit_clear(portb,1);          //y consigo escribir el port
    bit_clear(portb,2);
    bit_clear(portb,3);
    delay_ms(10);
    set_timer1(0);   
}


// Programa Principal /////////////////////////////////////////////////////////
   
void  Mi_Hora()
      {
      ++Conta_Segundos;
      MomentoActual=Conta_Segundos;
      Horas=MomentoActual/SEGUNDOS_EN_UNA_HORA;
      MomentoActual%=SEGUNDOS_EN_UNA_HORA;               //Guarda el resto de la división entera.
      Minutos=MomentoActual/SEGUNDOS_EN_UN_MINUTO; 
      MomentoActual%=SEGUNDOS_EN_UN_MINUTO;   
      Segundos=MomentoActual;
      MomentoActual=1;
      if(Horas==24 && Minutos==0 && Segundos==0)
      {
      Horas=0;
      Minutos=0;
      Segundos=0;
      reset();
      }
      }
     
void Cambiar_hora(int32 *Horas,int32 *Minutos)
{
if(set==0)
   {
      if(portb==0b10110000)
      {
      ++*Minutos;
      if(*Minutos==60){*Minutos=0;}
      }
   }
if(set==1)
   {
      if(portb==0b10110000)
      {
      ++*Horas;
      if(*Horas==24){*Horas=0;}
      }
   }
if(set==0)
   {
      if(portb==0b01110000)
      {
      if(*Minutos==0){*Minutos=60;}
      --*Minutos;
      }
   }   
if(set==1)
   {
      if(portb==0b01110000)
      {
      if(*Horas==0){*Horas=24;}
      --*Horas;
      }
   }   
}     
       
void  main(void)
      {
      lcd_init();
      set_tris_b(0xf0);
      port_b_pullups(TRUE);
      portb=0xf0;
      setup_timer_1(T1_EXTERNAL|T1_DIV_BY_2|T1_CLK_OUT);
      enable_interrupts(INT_TIMER1);
      enable_interrupts(INT_RB);
      enable_interrupts(GLOBAL);
      set_tris_c(0xff);
      set_tris_d(0x00);
      lcd_gotoxy(1,1);
      lcd_putc("Reloj Digital");
      delay_ms(1500);
      lcd_putc("\fHora 00:00:00 ");
      lcd_gotoxy(1,2);
      lcd_putc("        ..      ");
      delay_ms(250);
      lcd_gotoxy(1,2);
      lcd_putc("                ");
      delay_ms(250);
      lcd_gotoxy(1,2);
      lcd_putc("        ..      ");
      delay_ms(250);
      setup_timer_1(T1_EXTERNAL|T1_DIV_BY_2|T1_CLK_OUT);
      set_timer1(0);
         while(1)
         {
         lcd_gotoxy(6,1);
         printf(lcd_putc,"%02ld:%02ld:%02ld    ",Horas,Minutos,Segundos);
         }
       }
       
       
       
       
       
       
No se que pasara y no se si estare conectando mal el crystal asi que les muestro,Gracias amigos

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Como configurar el timer 1 en modo contador
« Respuesta #6 en: 06 de Octubre de 2009, 08:59:20 »
Las interrupciones trata de que sean lo mas corta posible, no envíes datos al LCD dentro de ella, setea una bandera y ejecútalos en el main o una función según como organices tu código. Con respecto a como se conecta el cristal puedes revisar el datasheet, allí está explicado  :mrgreen:

Una cosa que me olvide de comentar es que proteus no simula osciladores, hay que probarlo en la vida real  :mrgreen:


Saludos!
« Última modificación: 06 de Octubre de 2009, 09:26:01 por Suky »
No contesto mensajes privados, las consultas en el foro

Desconectado Trev

  • PIC16
  • ***
  • Mensajes: 115
Re: Como configurar el timer 1 en modo contador
« Respuesta #7 en: 06 de Octubre de 2009, 12:13:44 »
Ahh que piola lo mio y yo dandole a run como un tarado jaja bue gracias = mi idea es que se deje de lado la cuenta cuando esta dentro de la interrupción int_rb asique no le afectaria lo largo de esta pero bue lo voy a intentar gracias nos vemos ;-)

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Como configurar el timer 1 en modo contador
« Respuesta #8 en: 06 de Octubre de 2009, 12:33:20 »
Hola.

Para simular la entrada del cristal se puede conectar un generador de señales y asignar la frecuencia a la del cristal, o una fuente tipo Clock.

Saludos

El papel lo aguanta todo

Desconectado Trev

  • PIC16
  • ***
  • Mensajes: 115
Re: Como configurar el timer 1 en modo contador
« Respuesta #9 en: 06 de Octubre de 2009, 13:42:36 »
¿Donde esta el problema? lo conecté con 2 condensadores de 27 pF porque no tengo de 33pF como indica el data y al fin cuenta pero muy lento me incrementa los segundos como cada 4 o 5 segundos reales,vi en el archivo .lst que la funcion Mi_Hora() tiene mas de 200 instrucciones lo cual a 4 MHz serian 200 µs pero a la interrupción del timer entra supuestamente cada segundo no por cada cuenta asique no se que estara pasando  :(

Desconectado Trev

  • PIC16
  • ***
  • Mensajes: 115
Re: Como configurar el timer 1 en modo contador
« Respuesta #10 en: 08 de Octubre de 2009, 18:19:11 »
Logré mejorarlo mucho colocando todo lo del while(1) dentro de la interrupción del timer porque a 4 MHz el printf demoraba 74 ms  :P asique recargando el timer con 32768+estos 74 ms o sea con un 35193 antes de salir de la misma me conforma mucho -aunque adelanta 3 seg cada 10 min- sino digan que se les ocurre,Gracias  ;-)

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Como configurar el timer 1 en modo contador
« Respuesta #11 en: 08 de Octubre de 2009, 18:25:50 »
La forma correcta de trabajar con interrupciones es utilizar una bandera para indicar lo ocurrido y tratarla después, y usando preescaler 1:2 no tienes que recargar el timer  :mrgreen:

Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado Trev

  • PIC16
  • ***
  • Mensajes: 115
Re: Como configurar el timer 1 en modo contador
« Respuesta #12 en: 08 de Octubre de 2009, 19:02:00 »
Para mi es lo mismo Suky porque en algún momento debo recargar el timer como corrección ya que desde que ocurre la interrupción hasta que se actualiza la hora en el display pasan 74.04 en promedio ms (esto lo cheque trazando un breakpoint en proteus) por eso hay que adelantar la cuenta antes de salir de la interrupción, en fin esto va a ser a pila asique va a ir bien porque en una semana adelanta un poquito mas de un minuto y ¿cuanto va a durar la pila?

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Como configurar el timer 1 en modo contador
« Respuesta #13 en: 08 de Octubre de 2009, 22:10:12 »
Cuando lo seteas en 1:2 la interrupción va a ocurrir siempre a 1 seg y no se va atrasar, no hay manera que se atrase, excepto que el reloj no sea exactamente de 32768Hz. Después cuanto dure la pila, mmm hay que calcular el consumo que tendrá el dispositivo y dependiendo de la pila se pude estimar el tiempo de duración.


Saludos!
« Última modificación: 13 de Octubre de 2009, 01:19:48 por Suky »
No contesto mensajes privados, las consultas en el foro

Desconectado Trev

  • PIC16
  • ***
  • Mensajes: 115
Re: Como configurar el timer 1 en modo contador
« Respuesta #14 en: 08 de Octubre de 2009, 22:31:39 »
A ver Suky corrigeme el código según dices porque yo pongo como dices T1_DIV_BY_2 e interrumpe cada 4 segundos sin cargar el timer como dices!  :( mira aca esta el código actualizado:

Código: [Seleccionar]
#include <16f877a.h>
#use delay(clock=4000000)
#fuses XT,PUT,NOPROTECT,NOWDT,NOLVP
#byte portb=6
#byte portc=7
#byte portd=8
#include <flex_lcd.c>
#use standard_io(b,c)
//#use fast_io(b)

#define SEGUNDOS_EN_UNA_HORA 3600
#define SEGUNDOS_EN_UN_MINUTO 60


int32 Conta_Segundos=0,MomentoActual=0;
int32 Horas=0,Minutos=0,Segundos=0;
int set,flag_timer1;
byte last_b;

void Mi_Hora(void);
void Cambiar_Hora(int32 *Horas,int32 *Minutos);
void reset(void)
{
Conta_Segundos=0;
Momentoactual=0;
}

#INT_TIMER1
timer1_rsi()
{
set_timer1(32768);
++Conta_Segundos;
Mi_Hora();
lcd_gotoxy(6,1);
printf(lcd_putc,"%02ld:%02ld:%02ld    ",Horas,Minutos,Segundos);
}

// Interrupcion RB4 - RB7 /////////////////////////////////////////////////////
#INT_RB
rb_isr()
{
    byte changes;
    changes=last_b^portb;       //XOR.
    last_b=portb;
    if (bit_test(changes,5) && !bit_test(last_b,5))
    {                                                     
         lcd_gotoxy(6,2);
         lcd_putc("..              ");    //Indica que se va a incrementar las horas.
         delay_ms(200);
         lcd_gotoxy(6,2);
         lcd_putc("                ");
         delay_ms(200);
         lcd_gotoxy(6,2);
         lcd_putc("..              ");
         if(set==1)
         {
         lcd_gotoxy(1,2);
         lcd_putc("        ..      ");   // Indica que se van a incrementar los minutos
         delay_ms(250);
         lcd_gotoxy(1,2);
         lcd_putc("                ");
         delay_ms(250);
         lcd_gotoxy(1,2);
         lcd_putc("        ..      ");
         }
         set+=1;
         if (set==2)
         set=0;   
    }
    if (bit_test(changes,6) && !bit_test (last_b,6))   //INCREMENTAR.
    {
    Cambiar_hora(&Horas,&Minutos);
    }
    if (bit_test(changes,7) && !bit_test (last_b,7))   //DECREMENTAR.
    {
    Cambiar_hora(&Horas,&Minutos);       
    }
    Conta_Segundos=(Minutos*60)+(Horas*3600)+Segundos;
    bit_clear(portb,0);          //Solo modifico el nibble bajo sin tocar el alto
    bit_clear(portb,1);          //y consigo escribir el port
    bit_clear(portb,2);
    bit_clear(portb,3);
    lcd_gotoxy(6,1);
    printf(lcd_putc,"%02ld:%02ld:%02ld    ",Horas,Minutos,Segundos);
    delay_ms(10);
    set_timer1(32768);   
}


// Programa Principal /////////////////////////////////////////////////////////
   
void  Mi_Hora()
      {
      MomentoActual=Conta_Segundos;
      Horas=MomentoActual/SEGUNDOS_EN_UNA_HORA;
      MomentoActual%=SEGUNDOS_EN_UNA_HORA;               //Guarda el resto de la división entera.
      Minutos=MomentoActual/SEGUNDOS_EN_UN_MINUTO; 
      MomentoActual%=SEGUNDOS_EN_UN_MINUTO;   
      Segundos=MomentoActual;
      if(Horas==24 && Minutos==0 && Segundos==0)
      {
      Horas=0;
      Minutos=0;
      Segundos=0;
      reset();
      }
      }
     
void Cambiar_hora(int32 *Horas,int32 *Minutos)
{
if(set==0)
   {
      if(portb==0b10110000)
      {
      ++*Minutos;
      if(*Minutos==60){*Minutos=0;}
      }
   }
if(set==1)
   {
      if(portb==0b10110000)
      {
      ++*Horas;
      if(*Horas==24){*Horas=0;}
      }
   }
if(set==0)
   {
      if(portb==0b01110000)
      {
      if(*Minutos==0){*Minutos=60;}
      --*Minutos;
      }
   }   
if(set==1)
   {
      if(portb==0b01110000)
      {
      if(*Horas==0){*Horas=24;}
      --*Horas;
      }
   }   
}     
       
void  main(void)
      {
      lcd_init();
      set_tris_b(0xf0);
      port_b_pullups(TRUE);
      portb=0xf0;
      setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT);//el preescaler q va es 2.
      enable_interrupts(INT_TIMER1);
      enable_interrupts(INT_RB);
      enable_interrupts(GLOBAL);
      set_tris_c(0b00000011);
      set_tris_d(0x00);
      lcd_gotoxy(1,1);
      lcd_putc("Reloj Digital");
      delay_ms(1500);
      lcd_putc("\fHora 00:00:00 ");
      lcd_gotoxy(1,2);
      lcd_putc("        ..      ");
      delay_ms(250);
      lcd_gotoxy(1,2);
      lcd_putc("                ");
      delay_ms(250);
      lcd_gotoxy(1,2);
      lcd_putc("        ..      ");
      delay_ms(250);
      set_timer1(32768);
         while(1)
         {
         
         }
       }
       
       
       
       
       
       
= me parece que tengo un problema físico porque hace mas de 20 min que esta runeando esto en el proteus y la diferencia entre el reloj del simulador y lo que marca el display se mantiene constante!deben ser los capacitores o el cristal mientras q en el protoboard en el mismo tiempo se adelanta un par de segundos cuando lo comparo con un crónometro que tengo