# Is there a problem with using delay functions when using internal oscillator in PIC ?

I am doing a project that requires having the micro-controller to use the delay_ms() functions (compiler CCS C) to wait for a determined period of time.

I am using PIC 16f628A and while the program ran as intended in Proteus but it ran about 85 times faster that that when I tried it on the board .

I did choose to set the internal oscillator to the minimum possible frequency (48khz) to decrease power consumption and I specified that in the wizard and so the .h file have the line #use delay(internal=48kHz).

What am I doing wrong ?.

Summary:

You need to set OSCF (bit 3) to 0 in the PCON register in your code (i.e. during runtime) when you want the PIC INTOSC (Internal Oscillator) to run at a nominal 48 kHz (actually anywhere between 31.4 kHz and 78.62 kHz) instead of the power-on INTOSC default frequency of 4 MHz.

Details:

I did choose to set the internal oscillator to the minimum possible frequency (48khz) to decrease power consumption and I specified that in the wizard and so the .h file have the line #use delay(internal=48kHz).

The problem is that none of the things you list actually set the INTOSC hardware to 48 kHz. Based on what you said, it seems your software assumes the CPU will run at 48 kHz, but your hardware will still run at the default 4 MHz INTOSC frequency.

the program ran as intended in Proteus but it ran about 85 times faster that that when I tried it on the board .

Yes, that's what I expect.

85 faster x 48 kHz = 4 MHz (approx.)

This result suggests that your MCU was actually still running at the default INTOSC frequency of 4 MHz.

The important point is that you cannot configure that PIC to run at 48 kHz from power-on. If you set the CONFIG BITS (a.k.a. Fuses) to one of the two variants of INTOSC setting, then the MCU will use the internal 4 MHz frequency at power-on.

Then, when you want to switch it to 48 kHz (perhaps at the start of your main() but perhaps elsewhere in your code - it's up to you to choose) you then set OSCF (bit 3) to 0 in the PCON register - that bit is what switches the INTOSC frequency from 4 MHz to 48 kHz (after a short switchover transition).

See section 14.2.8 "SPECIAL FEATURE: DUAL-SPEED OSCILLATOR MODES" on page 101 of the PIC16F628A datasheet for more details.

Also note that the datasheet does not specify the accuracy of the 48 kHz clock (only the 4 MHz clock accuracy is specified there). However the PIC16F628A errata shows that the 48 kHz clock can actually vary between 31.4 kHz to 78.62 kHz.

• That was the problem, thank you very much, I should add that there is a function in CCS compiler that can be used without writing the registers ( setup_oscillator(OSC_48KHZ);) – Ahmad Hani Jan 16 '17 at 15:22

You may not correctly set the clock. You can do the following test:

1. do a while loop test: while(1){RB0=1;RB0=0;} Use oscilloscope to measure the speed. Each instruct would take 4 clock cycle to execute if i remember correctly. If the speed is right, which means clock has no problem. otherwise fix the clock setting.

2. if the clock is right, please check the code for delay function. I attached a code I used earlier for this chip:

I believe I got the source code from : http://www.alternatezone.com/electronics/dds.htm

delay.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
}


delay.h . please note that you need to define the value of XTAL_FREQ. in this example it is 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);

• Unfortunately I dont have an osciliscope. – Ahmad Hani Jan 16 '17 at 0:35

Using delay_ms() is always critical if you want to have accurate timing. It is difficult without seeing your code, but probably your processing takes too long. A simple example:

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


You might think the LED will toggle every 100 ms, but if the calculation takes for example 10 ms, the interval is rather 110 ms. Even toggling an LED itself has an influence on the timing.

So, if you want to have accurate timing, rather use a hardware timer and not delay_ms().

• The calculation is very minimal in my code literally just set a pin high then a function that uses delay ms for minites, I dont need the timing to be critical but at least similar to the intended timing, could the microcontroller be faulty. – Ahmad Hani Jan 16 '17 at 0:31