Autor Tema: Contar un seg....  (Leído 5561 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado pocher

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: Contar un seg....
« Respuesta #15 en: 16 de Abril de 2008, 06:49:34 »
Y el mio, que estaba más arriba, pero que se le ha debido de pasar a Enigma:

No se emplean decimales para la temporización del TMR0, ya que lo hago girar una vuelta completa, sin precargarlo y al no haber precarga no se pierde tiempo en la instrucción de precarga (no hay set_timer0()).

Tampoco entra en la interrupción con lo que tampoco se pierde tiempo.

Para esta técnica es necesario usar un cristal de 3,2768MHz ó otro cualquiera de forma que no aparezcan decimales en el cálculo de la temporización y que aunque el cálculo de la temporización sea exacto no haya que precargar al TMR0 (el de 4MHz no sirve), es decir que la precarga sea de 0.

Como alguién habrá deducido esta es la técnica para programar un reloj con un PIC que funcione bien, sin retrasos ni adelantos.

Este es el programa:

Código:

#include <16f876.h>

#fuses XT, NOPROTECT, NOWDT, NOPUT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use fast_io(B) 
#use delay(clock=3276800)       //Para conseguir 1s sin precargar (retrasos) al TMR0
#include <lcd.c>
#include <math.h>

#bit T0IF=0x0B.2

#define radios 4                                             //Encoder de 4 radios

main()
{
   float n;
   int16 pulsos;
   int8 cuenta_interrupciones;
   int16 velocidad_s,velocidad_m;
   
   lcd_init();
   lcd_putc('\f');   
   
   set_tris_c(0x01);                              //Entrada de pulsos por RC0
   
   setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_128);
   // El TMR0 se desbordará cada: Temp=(256-0)·(4·128)/3,2768=40ms (40ms · 25 = 1s)
   setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1);
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RTCC);
   
   cuenta_interrupciones=0;
   set_timer1(0);             
   set_timer0(0);
   T0IF=0;
   
   while(1)
   {
      if(T0IF)
      {
         T0IF=0;
         cuenta_interrupciones++;
         if(cuenta_interrupciones==25)          //  40ms · 25 = 1s
         {   
            pulsos=get_timer1();           
           
            n=pulsos/radios;
           
            velocidad_s=floor(n+(n-floor(n)));   //Redondea n, por si recibe algún pulso
                                                //de más ó de menos
            velocidad_m=velocidad_s*60;
     
            lcd_putc('\f');                        //Borra display
            lcd_gotoxy(1,1);             
            printf(lcd_putc,"%lu rev/s %uradios",velocidad_s,radios);      //rev/s
            lcd_gotoxy(1,2);       
            printf(lcd_putc,"%lu r.p.m.",velocidad_m);                     //r.p.m.           
   
            cuenta_interrupciones=0;
            set_timer1(0);             
            set_timer0(0);   
         }
      }
   }
}

 
La técnica es no utilizar rutina de interrupción para que no se pierda tiempo.

Un saludo

Desconectado PalitroqueZ

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5474
    • Electrónica Didacta
Re: Contar un seg....
« Respuesta #16 en: 16 de Abril de 2008, 12:13:39 »
Enigma, si estas usando un 18F2550, recuerda que la frecuencia del timer que éste usa NO es la del cristal, es la que entra al cpu del micro (después de la etapa del bloque oscilador)






La propiedad privada es la mayor garantía de libertad.
Friedrich August von Hayek

Desconectado Cryn

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4169
Re: Contar un seg....
« Respuesta #17 en: 02 de Mayo de 2008, 00:53:05 »
y si en la rutina de interrupcion solamente incremento un contador y seteo el temporizador y despues en el main hago que ese conteo cambie, claro, talvez sea en algo que no haya mucho q hacer en el main solo contar, o bueno, que dicen? ya qeu la interrupcion no haria anda mas, y ya el timer va contando lo que se hace fuera de la interrupcion
.

Desconectado firepic

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1130
    • JC Servicios
Re: Contar un seg....
« Respuesta #18 en: 03 de Mayo de 2008, 00:55:37 »
Saludos!  :-/

Bueno en cuanto a la pregunta del máximo valor que puede contar el timer0:

- Si es de 8 bits: por ahí 255
- La máxima pre-escala es de 256
- El oscilador es de 20MHz, pero como la frecuencia que toma en cuenta el temporizador es Fosc/4 (tal como dice PalitroqueZ), hay que multiplicar por 4 también.
Entonces la cuenta sería:
  Tiempo maximo = 255*256*4*20e6^-1 = 0.013056
  Tiempo maximo = 13.056ms

No obstante, para el pic que usas también hay configuración a 16 bits, por lo cual el cálculo sería:

  Tiempo maximo = (2^16-1)*256*4*20e6^-1
  Tiempo maximo = 3.3554s

Por eso la observación que hace kallitos me parece genial!  :mrgreen:
Me gusta también el método de Porcher, lo único es que el cristal no es de 20 MHz...
Ok nos leemos!  :-)

"Por la presunción solo se ocasiona una lucha, pero con los que consultan juntos hay sabiduría" (Proverbios 13:10).
Visita Mi Sitio Web

Desconectado pocher

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: Contar un seg....
« Respuesta #19 en: 03 de Mayo de 2008, 16:07:21 »
Si el segundo lo quereis como base de tiempos para diseñar un reloj, no sirven los métodos que usan interrupción, si lo haceis así vuestro reloj atrasará je, je.

Desconectado firepic

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1130
    • JC Servicios
Re: Contar un seg....
« Respuesta #20 en: 03 de Mayo de 2008, 16:28:59 »
El maestro porcher como siempre... tiene toda la razón!!  :mrgreen:
"Por la presunción solo se ocasiona una lucha, pero con los que consultan juntos hay sabiduría" (Proverbios 13:10).
Visita Mi Sitio Web

Desconectado Cryn

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4169
Re: Contar un seg....
« Respuesta #21 en: 04 de Mayo de 2008, 17:32:27 »
creo q se me olvido mencionar algo :mrgreen:

y si utilizamos el timer1 con cristal de 32.768KHz cons osc externo y a la vez osc de 20MHz para codigo de programa

entonces una parte del codigo quedaria asi:

#int_tmr1
void isr_tmr1(void)
{
   seg++;
   set_timer1(32767);
}

void main()
{
   setup_timer_1(T1_EXTERNAL|T1_CLK_OUT|T1_DIV_BY_1);
   enable_interrupts(int_TIMER1);
   enable_interrupts(global);
   while(true)
   {
      funcion();//encargada de contar seg hasta 60 e incrementar minutos, horas, dias, meses y años
   }
}

que te parece eso, tb lleva mucha demora, o es algo aceptable??
« Última modificación: 04 de Mayo de 2008, 17:35:47 por Cryn »
.

Desconectado pocher

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: Contar un seg....
« Respuesta #22 en: 05 de Mayo de 2008, 02:26:57 »
No estaría bien, atrasaría.

El problema viene no de si utilizas un oscilador interno o externo, si no del propio C.

Al hacer un set_timer1(32767) se pierde tiempo en la ejecución de las instrucciones en ensamblador ---> el reloj atrasaría

Al entrar dentro de una rutina de interrupción se pierde tiempo ---> el reloj atrasaría

El problema a simple vista no lo verás, pero si dejas al reloj funcionando varios días verás como cada vez va atrasando más.


 

anything