5 votos

¿Hay algún problema con usar funciones de retraso cuando se utiliza el oscilador interno en un PIC?

Estoy haciendo un proyecto que requiere que el microcontrolador utilice las funciones delay_ms() (compilador CCS C) para esperar un período de tiempo determinado.

Estoy usando un PIC 16f628A y aunque el programa funcionaba según lo previsto en Proteus, se ejecutaba aproximadamente 85 veces más rápido cuando lo probé en la placa.

Elegí establecer el oscilador interno a la frecuencia mínima posible (48 khz) para disminuir el consumo de energía y lo especificé en el asistente, por lo que el archivo .h tiene la línea #use delay(internal=48kHz).

¿Qué estoy haciendo mal?

4voto

Link Puntos 148

Resumen:

Necesitas establecer OSCF (bit 3) en 0 en el registro PCON en tu código (es decir, durante la ejecución) cuando quieras que el PIC INTOSC (Oscilador Interno) funcione a una frecuencia nominal de 48 kHz (en realidad en cualquier lugar entre 31.4 kHz y 78.62 kHz) en lugar de la frecuencia predeterminada de 4 MHz al encenderse.

Detalles:

Elegí establecer el oscilador interno a la frecuencia mínima posible (48kHz) para disminuir el consumo de energía y lo especificé en el asistente, por lo que el archivo .h tiene la línea #use delay(internal=48kHz).

El problema es que ninguna de las cosas que mencionas realmente configuran el INTOSC hardware a 48 kHz. Según lo que dijiste, parece que tu software asume que la CPU funcionará a 48 kHz, pero tu hardware seguirá funcionando a la frecuencia predeterminada INTOSC de 4 MHz.

el programa funcionó según lo previsto en Proteus, pero funcionó alrededor de 85 veces más rápido cuando lo probé en la tarjeta.

Sí, eso es lo que espero.

85 veces más rápido x 48 kHz = 4 MHz (aprox.)

Este resultado sugiere que tu MCU en realidad seguía funcionando a la frecuencia predeterminada INTOSC de 4 MHz.

El punto importante es que no puedes configurar ese PIC para funcionar a 48 kHz desde el encendido. Si configuras los BITS DE CONFIGURACIÓN (también conocidos como Fusibles) a una de las dos variantes de configuración INTOSC, entonces el MCU utilizará la frecuencia interna de 4 MHz al encenderse.

Luego, cuando quieras cambiarlo a 48 kHz (quizás al inicio de tu main() pero tal vez en otra parte de tu código, depende de ti elegir), entonces configuras OSCF (bit 3) en 0 en el registro PCON - ese bit es lo que cambia la frecuencia INTOSC de 4 MHz a 48 kHz (después de una corta transición de cambio).


extract from PIC16F628A datasheet showing OSCF bit in PCON register


Consulta la sección 14.2.8 "CARACTERÍSTICA ESPECIAL: MODOS DE OSCILADOR DE DOBLE VELOCIDAD" en la página 101 de la hoja de datos del PIC16F628A para más detalles.


extract from PIC16F628A datasheet about switching INTOSC speed


También ten en cuenta que la hoja de datos no especifica la precisión del reloj de 48 kHz (solo se especifica la precisión del reloj de 4 MHz allí). Sin embargo, la errata del PIC16F628A muestra que el reloj de 48 kHz puede variar entre 31.4 kHz y 78.62 kHz.


PIC16F628A errata for INTOSC at 48 kHz


1 votos

Ese era el problema, muchas gracias, debo agregar que hay una función en el compilador CCS que se puede usar sin escribir los registros (setup_oscillator(OSC_48KHZ);)

0voto

Craig Puntos 51

Puede que no hayas configurado correctamente el reloj. Puedes realizar la siguiente prueba:

  1. realiza una prueba de bucle while: while(1){RB0=1;RB0=0;} Utiliza un osciloscopio para medir la velocidad. Cada instrucción tomaría 4 ciclos de reloj para ejecutarse, si recuerdo correctamente. Si la velocidad es correcta, significa que el reloj no tiene problemas. De lo contrario, corrige la configuración del reloj.

  2. si el reloj es correcto, por favor verifica el código de la función de retraso. Adjunto un código que usé anteriormente para este chip:

Creo que obtuve el código fuente de : http://www.alternatezone.com/electronics/dds.htm

delay.c

/*
 *  Funciones de retraso
 *  Consulta delay.h para más detalles
 *
 *  ¡Asegúrate de que este código se compile con optimización completa!
 */

#include    "delay.h"

void
DelayMs(unsigned char cnt)
{
#if XTAL_FREQ <= 2MHZ
    do {
        DelayUs(996);
    } while(--cnt);
#endif

#if    XTAL_FREQ > 2MHZ 
    unsigned char   i;
    do {
        i = 4;
        do {
            DelayUs(250);
        } while(--i);
    } while(--cnt);
#endif
}

delay.h . por favor ten en cuenta que necesitas definir el valor de XTAL_FREQ. en este ejemplo es 4MHz

/*
 *  Funciones de retraso para HI-TECH C en el PIC
 *
 *  Funciones disponibles:
 *      DelayUs(x)  Retrasar un número especificado de microsegundos
 *      DelayMs(x)  Retrasar un número especificado de milisegundos
 *
 *  Ten en cuenta que hay límites de rango: x no debe exceder 255 - para
 *  frecuencias de cristal > 12MHz el rango para DelayUs es aún más pequeño.
 *  Para usar DelayUs simplemente incluye este archivo; para usar
 *  DelayMs debes incluir delay.c en tu proyecto.
 *
 */

/*  Establece la frecuencia del cristal en la lista de símbolos predefinidos de CPP en
    HPDPIC, o en la línea de comandos de PICC, por ejemplo
    picc -DXTAL_FREQ=4MHZ

    o
    picc -DXTAL_FREQ=100KHZ

    Ten en cuenta que esta es la frecuencia del cristal, el reloj de la CPU
    se divide entre 4.

 *  ASEGÚRATE de que este código se compile con optimización completa!!!

 */

#ifndef XTAL_FREQ
#define XTAL_FREQ   4MHZ        /* Frecuencia del cristal en MHz */
#endif

#define MHZ *1000L          /* número de kHz en un MHz */
#define KHZ *1          /* número de kHz en un kHz */

#if XTAL_FREQ >= 12MHZ

#define DelayUs(x)  { unsigned char _dcnt; \
              _dcnt = (x)*((XTAL_FREQ)/(12MHZ)); \
              while(--_dcnt != 0) \
                  continue; }
#else

#define DelayUs(x)  { unsigned char _dcnt; \
              _dcnt = (x)/((12MHZ)/(XTAL_FREQ))|1; \
              while(--_dcnt != 0) \
                  continue; }
#endif

extern void DelayMs(unsigned char);

0 votos

Desafortunadamente no tengo un osciloscopio.

0voto

Martin G Puntos 27

Usar delay_ms() es siempre crítico si quieres tener una temporización precisa. Es difícil sin ver tu código, pero probablemente tu procesamiento está tardando demasiado. Un ejemplo simple:

while(1) {
  delay_ms(100);
  do_some_calculation();
  toggle_an_led();
}

Puedes pensar que el LED se alternará cada 100 ms, pero si la cálculo tarda por ejemplo 10 ms, el intervalo será más bien de 110 ms. Incluso la alternancia de un LED en sí misma tiene influencia en la temporización.

Entonces, si quieres tener una temporización precisa, es mejor usar un temporizador de hardware y no delay_ms().

0 votos

La calculación es muy minimalista en mi código, literalmente solo configuro un pin en alto y luego una función que utiliza un retraso de ms para minutos. No necesito que el tiempo sea crítico, pero al menos que sea similar al tiempo previsto, ¿podría ser que el microcontrolador esté defectuoso?

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X