¿Hay algún problema con el uso de funciones de retardo cuando se usa el oscilador interno en PIC?

Estoy haciendo un proyecto que requiere tener el microcontrolador para usar las funciones delay_ms() (compilador CCS C) para esperar un tiempo determinado.

Estoy usando PIC 16f628A y, aunque el programa se ejecutó según lo previsto en Proteus, se ejecutó unas 85 veces más rápido que cuando lo probé en la placa.

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

Qué estoy haciendo mal ?.

Respuestas (3)

Resumen:

Debe configurar OSCF(bit 3) 0en el PCONregistro de su código (es decir, durante el tiempo de ejecución) cuando desee que el PIC INTOSC (oscilador interno) se ejecute a 48 kHz nominales (en realidad, entre 31,4 kHz y 78,62 kHz) en lugar del frecuencia predeterminada de encendido INTOSC de 4 MHz.

Detalles:

Elegí configurar el oscilador interno a la frecuencia mínima posible (48 khz) para disminuir el consumo de energía y lo especifiqué 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 enumera realmente configuran el hardware INTOSC a 48 kHz. Según lo que dijo, parece que su software asume que la CPU se ejecutará a 48 kHz, pero su hardware seguirá funcionando a la frecuencia INTOSC predeterminada de 4 MHz.

el programa funcionó según lo previsto en Proteus pero funcionó unas 85 veces más rápido que cuando lo probé en la placa.

Sí, eso es lo que espero.

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

Este resultado sugiere que su MCU en realidad todavía se estaba ejecutando en la frecuencia INTOSC predeterminada de 4 MHz.

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

Luego, cuando desee cambiarlo a 48 kHz (quizás al comienzo de su main()pero quizás en otra parte de su código; depende de usted elegir), luego configure OSCF(bit 3) en 0el PCONregistro: ese bit es lo que cambia el Frecuencia INTOSC de 4 MHz a 48 kHz (después de una breve transición de conmutación).


extracto de la hoja de datos PIC16F628A que muestra el bit OSCF en el registro PCON


Consulte la sección 14.2.8 "FUNCIÓN ESPECIAL: MODOS DE OSCILADOR DE VELOCIDAD DOBLE" en la página 101 de la hoja de datos PIC16F628A para obtener más detalles.


extracto de la hoja de datos PIC16F628A sobre el cambio de velocidad INTOSC


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


Errata PIC16F628A para INTOSC a 48 kHz


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);)

Es posible que no ajuste correctamente el reloj. Puedes hacer la siguiente prueba:

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

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

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

retraso.c

/*
 *  Delay functions
 *  See delay.h for details
 *
 *  Make sure this code is compiled with full optimization!!!
 */

#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
}

demora.h . tenga en cuenta que debe definir el valor de XTAL_FREQ. en este ejemplo es 4MHz

/*
 *  Delay functions for HI-TECH C on the PIC
 *
 *  Functions available:
 *      DelayUs(x)  Delay specified number of microseconds
 *      DelayMs(x)  Delay specified number of milliseconds
 *
 *  Note that there are range limits: x must not exceed 255 - for xtal
 *  frequencies > 12MHz the range for DelayUs is even smaller.
 *  To use DelayUs it is only necessary to include this file; to use
 *  DelayMs you must include delay.c in your project.
 *
 */

/*  Set the crystal frequency in the CPP predefined symbols list in
    HPDPIC, or on the PICC commmand line, e.g.
    picc -DXTAL_FREQ=4MHZ

    or
    picc -DXTAL_FREQ=100KHZ

    Note that this is the crystal frequency, the CPU clock is
    divided by 4.

 *  MAKE SURE this code is compiled with full optimization!!!

 */

#ifndef XTAL_FREQ
#define XTAL_FREQ   4MHZ        /* Crystal frequency in MHz */
#endif

#define MHZ *1000L          /* number of kHz in a MHz */
#define KHZ *1          /* number of kHz in a 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);
Desafortunadamente no tengo un osciliscopio.

El uso de delay_ms() siempre es fundamental si desea tener una sincronización precisa. Es difícil sin ver su código, pero probablemente su procesamiento lleve demasiado tiempo. Un ejemplo sencillo:

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

Puede pensar que el LED cambiará cada 100 ms, pero si el cálculo toma, por ejemplo, 10 ms, el intervalo es más bien 110 ms. Incluso alternar un LED en sí mismo tiene una influencia en el tiempo.

Entonces, si desea tener una sincronización precisa, use un temporizador de hardware y no delay_ms().

El cálculo es muy mínimo en mi código, literalmente, simplemente configure un pin alto y luego una función que usa retardo ms para minites, no necesito que el tiempo sea crítico, pero al menos similar al tiempo previsto, ¿podría estar defectuoso el microcontrolador?