Autor Tema: Precisión del oscilador de cuarzo  (Leído 3674 veces)

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

Desconectado Picuino

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 5421
Precisión del oscilador de cuarzo
« en: 03 de Enero de 2012, 13:22:29 »
Hola a todos, aprovecho para desearles feliz año.

Estoy programando un frecuencímetro con un PIC18F2550 y me he encontrado con que el oscilador de cuarzo tiene una exactitud bastante mala.

Comparando el oscilador del pic con un reloj digital, el error es de 2.4 segundos en 3000 segundos (error de 750 ppm) y este error me parece exagerado.

El programa para contar segundos se basa en el timer0:

Código: [Seleccionar]
unsigned int sys_clk, sys_second;

/*******************************************************************
      INTERRUPT SERVICE ROUTINE
 *******************************************************************/
void isr_main(void);

#pragma code low_vector=0x18
void isr_low(void) {
   _asm GOTO isr_main  _endasm
}

#pragma interrupt isr_main
void isr_main(void) {
   if (INTCONbits.TMR0IF==1)  {   // TIMER0 overflow interrupt
        TMR0L -= 125;
        INTCONbits.TMR0IF = 0;
        sys_clk++;
        if (sys_clk == 375) {     // 1 SECOND EVERY 375*125*128 = 6000000 CYCLES
           sys_clk = 0;
           sys_second++;
        }
    }
}


/*******************************************************************
      MAIN PROGRAM
 *******************************************************************/
void main(void) {
   unsigned int old_second;

   //
   // CONFIGURE INTERRUPTS
   //
   INTCON = 0;          // All interrupts disabled
   INTCONbits.TMR0IE = 1;  // Enable TMR0 interrupt
   INTCONbits.PEIE = 1;    // Global Interrupt Enable. Enable all unmasked interrupts
   INTCONbits.GIE = 1;     // Global Interrupt Enable. Enable all unmasked interrupts
 
   //
   // CONFIGURE TIMER 0
   //
   T0CON =  (char)
           (0<<7)   // TMR0ON: Timer0 On/Off Control
         + (1<<6)   // T08BIT: 1 = Timer0 is configured as an 8-bit timer/counter
         + (0<<5)   // T0CS:   1 = Transition on T0CKI pin
         + (0<<4)   // T0SE:   1 = Increment on high-to-low transition on T0CKI pin
         + (0<<3)   // PSA:    1 = Timer0 prescaler is NOT assigned.
         + (0b110); // T0PS:   Prescale value 2^(T0PS+1)
               // 111 = 1:256 Prescale value
               // 110 = 1:128 Prescale value
               // 101 = 1:64 Prescale value
               // 100 = 1:32 Prescale value
               // 011 = 1:16 Prescale value
               // 010 = 1:8 Prescale value
               // 001 = 1:4 Prescale value
               // 000 = 1:2 Prescale value

   TMR0H = 0;
   TMR0L = -1;
   T0CONbits.TMR0ON = 1;

   //
   // MAIN ROUTINE
   //
   rs232_init();
   sys_clk = 0;
   sys_second = 0;
   
   while(1) {
      if (sys_second != old_second) {
          fprintf(_H_USART, "Second = %d\r\n", sys_second);
          old_second = sys_second;
      }
   };
}

Si el error fuese mayor, pensaría que es un error del programa; pero creo que es un problema del oscilador.

¿Es normal este error o debo pensar que hay un problema en el cristal?

Saludos.
« Última modificación: 03 de Enero de 2012, 19:34:00 por picuino »

Desconectado JBQ

  • PIC16
  • ***
  • Mensajes: 118
Re: Precisión del oscilador de cuarzo
« Respuesta #1 en: 03 de Enero de 2012, 13:39:45 »
El datasheet del uc dice al respecto que no es recomendable usar el oscilador interno si se ha de trabajar con tiempos crìticos, incluso recomendia un cristal externo para el uso del USART. Pero incluso en estos casos, se le puede dar solución por medio el firmware.

Desconectado Picuino

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 5421
Re: Precisión del oscilador de cuarzo
« Respuesta #2 en: 03 de Enero de 2012, 13:45:36 »
Estoy utilizando un cristal de cuarzo de 20MHz.

Esta frecuencia la paso a traves del PLL del PIC18F2550 y el divisor posterior para conseguir una frecuencia de trabajo de 24Mhz

¿Da problemas de precisión utilizar el PLL?

Saludos!
« Última modificación: 03 de Enero de 2012, 15:36:56 por picuino »

Desconectado JBQ

  • PIC16
  • ***
  • Mensajes: 118
Re: Precisión del oscilador de cuarzo
« Respuesta #3 en: 03 de Enero de 2012, 13:51:18 »
Aya, mmmm.... tecnicamente no deberìa darte ese tipos de problemas; debe haber un desfase... si, pero este no debe de ser tanto, y generalmente es cada 1 ò 10 horas, dependiendo de tu firmware. Parece que hay un bug ahi en tu firmware, como veo que estas programando en C, derepente una instrucciòn està haciendo una latencia demasiado larga. Como estas trabajando con el interrup hab, asegurate de actualizar de la forma apropiada el TMR0... saludos.

Desconectado Picuino

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 5421
Re: Precisión del oscilador de cuarzo
« Respuesta #4 en: 03 de Enero de 2012, 15:36:26 »
Eso había pensado, que podía ser un error de software.

¿Alguien conoce un programa ya probado para 'afinar' o medir la frecuencia del oscilador de cuarzo?

Tengo un polímetro con frecuencímetro, pero si le conecto al cristal deja de oscilar.

Saludos!

Desconectado MerLiNz

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2463
Re: Precisión del oscilador de cuarzo
« Respuesta #5 en: 03 de Enero de 2012, 15:56:53 »
el TMR0 pierde 2 ciclos cada escritura, luego algunos ciclos mas para el if(INTCON....

Lo normal es que los cristales tengan unos 100ppm de error como mucho y el error del PLL de tu pic es de 0.25%, o bien tu cristal es malo (alguno de mala fabricacion china) o algo hay de software que no te cuadra.

Desconectado Picuino

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 5421
Re: Precisión del oscilador de cuarzo
« Respuesta #6 en: 03 de Enero de 2012, 19:44:15 »
Gracias,
Mirando el manual he visto que el prescaler se pone a cero cada vez que se escribe en el registro TMR0L. Esto hace perder bastantes pulsos (el prescaler está en 1/128) y el contador se retrasa.
El problema es que no se como solucionarlo.

Si dejo correr libre al TMR0 para que divida por 256, salen números decimales a la hora de contar segundos:

    Fosc = 24000000Hz = 6000000 pulsos/segundo

    F timer0 = 6000000/256 = 23437.5 ciclos/segundo

Saludos!
« Última modificación: 03 de Enero de 2012, 20:02:00 por picuino »

Desconectado MerLiNz

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2463
Re: Precisión del oscilador de cuarzo
« Respuesta #7 en: 03 de Enero de 2012, 20:28:31 »
yo diria que no se pone a 0 eh? Me suena haber usado el timer0 en otras ocasiones para bajas frecuencias sin ese problema.

Bueno, el tema esta en que puedes usar otro timer, como estas usando variables para calcular los segundos te seria tan facil como un timer de 16bits

le cargas el valor de 28036 al timer. Y ahora cada 50ms tendras una interrupcion, 50ms*20=1segundo, para que te quede exacto deberias calcular el tiempo que tarda en volver a cargar el registro, asi le restas un par de Tcy y tendras un tiempo bastante exacto.

Desconectado Picuino

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 5421
Re: Precisión del oscilador de cuarzo
« Respuesta #8 en: 04 de Enero de 2012, 06:08:46 »
He conseguido un adelanto de 2.1 segundos en 8 horas y media (70ppm)  :-/

El programa funciona así:
   Micro funcionando a 20Mhz (directamente del cuarzo)
   Prescaler al mínimo (1/2)
   No pongo a cero el Timer0 (como comentas) así que tengo 9765.625 interrupciones por segundo
   Cada 9766 interrupciones atraso el contador:  TMR0L += 96;     // 96 = 256 * 0.375

De esta forma, el programa puede perder uno o dos pulsos de un total de 5 millones cada segundo (error de 0.4 ppm)

(Utilizo el timer0 en modo 8 bit porque quiero que este mismo programa sirva también para otro micro más pequeño con menos timers)

Muchas gracias y saludos!
« Última modificación: 04 de Enero de 2012, 06:37:43 por picuino »

Desconectado tapi8

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1506
Re: Precisión del oscilador de cuarzo
« Respuesta #9 en: 04 de Enero de 2012, 10:19:01 »
Citar
Prescaler al mínimo (1/2)

Creo que puedes usarlo 1/1 sino tienes habilitado el WDT, le asignas el preescaler al WDT y ya esta.

Citar
(Utilizo el timer0 en modo 8 bit porque quiero que este mismo programa sirva también para otro micro más pequeño con menos timers)

El TMR1 es el mas preciso, toda la serie 16f lo lleva excepto el 16f84 (no se si hay alguna excepcion muy especial) y la serie 12f los modernos creo que lo traen todos. La 10f si que no lo se.


Desconectado Picuino

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 5421
Re: Precisión del oscilador de cuarzo
« Respuesta #10 en: 04 de Enero de 2012, 20:35:09 »
Tienes razón, se puede desabilitar el prescaler y es más preciso.

El timer1 lo quiero utilizar para contar pulsos de entrada (la temporización con el timer0 servirá después para hacer un frecuencímetro)
El timer0 quiero utilizarle en modo 8bit para que el programa valga para un 16F628 o un 16F88.


Por ahora programo un reloj para poder compararlo con otro reloj digital y medir el error del cuarzo. Luego compenso el error por software.

Al final he conseguido un error muy bueno (menos de 10ppm):

Código: [Seleccionar]
/****************************************************************************
   SECOND COUNTER
 ****************************************************************************/
#include <p18cxxx.h>
#include <stdio.h>
#include <string.h>

/****************************************************************************
      GLOBAL VARIABLES AND DEFINITIONS
 ****************************************************************************/
#define FOSC            20000000
#define BAUD 57600
#define FOSC_ERROR_PPM  70                 
#define FOSC_REAL       (FOSC + FOSC_ERROR_PPM*(FOSC/1000000))
#define TMR0_COUNT      (FOSC_REAL/(4*256)+1)            // Number of carrys per second
#define TMR0_OFFSET     (TMR0_COUNT*256-(FOSC_REAL/4))   // TMR0L preset every second

unsigned int sys_clk, seconds, old_seconds;


/****************************************************************************
      INTERRUPT SERVICE ROUTINE
 ****************************************************************************/
// Rutinas de Interrupcion.-

#pragma interrupt isr_main
void isr_main(void) {
   if (INTCONbits.TMR0IF==1)  {        // if TIMER0 overflow interrupt
      INTCONbits.TMR0IF = 0;           // Clear Timer0 interrupt flag
      sys_clk--;
      if (sys_clk == 0) {
         TMR0L += TMR0_OFFSET + 3;
         sys_clk = TMR0_COUNT;
         seconds++;           
      }
   }
}

#pragma code high_vector=0x08
void isr_high(void) {
   _asm GOTO isr_main  _endasm
}


/****************************************************************************
      MAIN PROGRAM
 ****************************************************************************/
#pragma code

/*
   MAIN ROUTINE
*/
void main(void) {
   // Configure Timer0
   sys_clk = 1;
   seconds = 0;
   T0CON = 0b11001000;     // Timer0 ON, 8bit count, No prescaler
   INTCON = 0b11100000;    // Global Interrupt, Peripheral Interrupt, TMR0 interrupt


   // Configure UART
   BAUDCONbits.BRG16 = 0;        // BRG16: 16-Bit Baud Rate Register Enable bit
   SPBRGH = 0;
   SPBRG = (FOSC/(16*BAUD))-1;   // Configure UART speed
   TXSTA = 0b00100110;
   RCSTA = 0b10010000;
   TRISCbits.TRISC6 = 0;         // Enable TX output
   PIE1bits.TXIE = 0;            // Disable RS232 interrupts
 
   // Main loop
   old_seconds = -1;
   while(1) {
      if (seconds != old_seconds) {
         old_seconds = seconds;
         fprintf(_H_USART, "Seconds=%u\r\n", seconds);
      }
      if (seconds == 60000)
         seconds = 0;
   }
}

Saludos!
« Última modificación: 05 de Enero de 2012, 17:40:40 por picuino »

Desconectado SavageChicken

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 919
Re: Precisión del oscilador de cuarzo
« Respuesta #11 en: 05 de Enero de 2012, 14:10:11 »
Para realmente poder medir el error del cristal deberías trabajar en assembler. De esa forma sabrás exáctamente cuantas instrucciones realiza el PIC en cada bucle, y de esa manera tener un valor exacto del tiempo de oscilación del cristal. Todos los programas compiladores agregan instrucciones entre bucle y bucle, y generalmente esas instrucciones no tenidas en cuenta estan incrementando el error.

Salud.-  8)
No hay preguntas tontas...
Solo hay tontos que no preguntan.

Desconectado JBQ

  • PIC16
  • ***
  • Mensajes: 118
Re: Precisión del oscilador de cuarzo
« Respuesta #12 en: 05 de Enero de 2012, 18:55:55 »
El disassembly listing puede ayudar en estos casos.

Desconectado SavageChicken

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 919
Re: Precisión del oscilador de cuarzo
« Respuesta #13 en: 06 de Enero de 2012, 13:46:33 »
El disassembly listing puede ayudar en estos casos.

Efectivamente, esa sería una buena forma de contar las instrucciones si utilizas un compilador.
No hay preguntas tontas...
Solo hay tontos que no preguntan.

Desconectado reiniertl

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 1187
Re: Precisión del oscilador de cuarzo
« Respuesta #14 en: 06 de Enero de 2012, 14:08:55 »
TIMER0, mala elección para el frecuencímetro.

Mi sugerencia es utilizar un módulo CCP+TIMER1 y TIMER1 con oscilador externo y de precisión para el mismo. Ya con eso te evitarás una muy buena parte de los problemas.

El módulo CCP en modo captura te permitirá analizar señales de baja frecuencia y también las de alta solamente con configurar el valor de comparación para activar la interrupción cuando la captura coincida con el valor de comparación deseado. Esto es algo relativamente de lograr con un PIC si se utilizan los periféricos apropiados.

Reconozco que todo mundo tira al pobre TIMER0 este tipo de aplicaciones cuando lo correcto es utilizar el hardware que viene con el PIC para ello.

Espero que esta sugerencia te ayude a resolver tu problema.