Also sometimes the __delay macros just don't work, even if you set the _XTAL_FREQ variable.
So I wrote my own functions some time ago, but they're for 16 Mhz clock (built in more powerful PIC16f micros).
The delay_ms function below would still work reasonably well at 4 Mhz, without making any changes inside it.
You'd just have to say 25ms instead of 100ms for example, to delay for 100ms, since most of the work is done by that asm(goto $+1) which takes 2 us at 4Mhz while it uses 0.5us at 16 Mhz, so basically if you say delay_ms(25) in your code, the function will more or less delay for four times as much compared to when running at 16 Mhz.
It won't be super accurate because that delay_4tcy will now delay for 4 us instead of 1us, so for every loop, the function will delay an extra 3us plus a couple us more in the while loops and that adds up if the number of ms is high etc etc
delay.h
// Delay routines for 16 Mhz clock.
//
// 16 Mhz = 4 Hz per cycle = 4 operations/cycles per uS
//
#ifndef __DELAYH_INIT
#define __DELAYH_INIT
#define delay_1tcy() asm("nop")
#define delay_2tcy() asm("goto $+1")
#define delay_4tcy() asm("goto $+1");asm("goto $+1");
#define delay_10tcy() delay_2tcy();delay_4tcy();delay_4tcy();
#define delay_500ns() delay_2tcy()
#define delay_1us() delay_4tcy()
#define delay_4us() delay_1us();delay_1us();delay_1us();delay_1us();
#define delay_5us() delay_4us();delay_1us();
#define delay_10us() delay_5us();delay_5us();
#define delay_5ms() delay_ms(5);
#define delay_10ms() delay_ms(10);
#define delay_25ms() delay_ms(25);
#define delay_50ms() delay_ms(50);
#endif
extern void delay_25us();
extern void delay_50us();
extern void delay_100us();
extern void delay_1ms();
//extern void delay_10ms();
//extern void delay_25ms();
//extern void delay_50ms();
extern void delay_ms(unsigned char ms);
delay.c
/*
* Hi-Tech C has internal macros : __delay(cycles), __delay_us(uS), __delay_ms(mS)
*
* The routines below are precomputed for 16 Mhz clock.
*/
#include "delay.h"
void delay_25us(){
// function call and return is 4 cycles, on 16Mhz that's 1us
// so delay for 24us here
delay_10us();
delay_10us();
delay_4us();
}
void delay_50us(){
delay_10us();
delay_10us();
delay_10us();
delay_10us();
delay_5us();
delay_4us();
}
void delay_100us(){
delay_50us();
delay_10us();
delay_10us();
delay_10us();
delay_10us();
delay_5us();
delay_4us();
}
void delay_1ms(){
unsigned char n = 248;
do {
asm("goto $+1"); asm("goto $+1"); asm("goto $+1");
asm("goto $+1"); asm("goto $+1"); asm("goto $+1");
asm("nop");
// decrease if not zero - decfsz (1 cycle if !=0, 2 cycles otherwise)
// goto loop start = 2 cycles
} while(--n);
// = 16 cycles x [n+1] + 1 (from last decfsz) - 2 (last goto is skipped)
// 249x16+1-2 = 3983 cycles (1 = decfsz ), -2 for last goto
// + 1 = 3984 cycles (assignment of 248 to n)
// + 4 = 3988 cycles (function call and return)
delay_2tcy(); // = 3990 cycles
delay_10tcy(); // = 4000 cycles
}
// Delay up to 255 milliseconds - approximately (ms + 19 cycles).
// ms can be in range 0 to 255
void delay_ms(unsigned char ms) {
unsigned char n;
while(ms--) { // time in cycles for the inner loop including
n = 249; // cycles = 19+16*ms*[1+n]
// cycles = 4000*ms + 19 for 16MHz clock
// cycles = 2000*ms + 19 for 8MHz clock
delay_4tcy();
do {
asm("goto $+1");
asm("goto $+1");
asm("goto $+1");
asm("goto $+1");
asm("goto $+1");
asm("goto $+1");
asm("nop");
// decrease if not zero - decfsz (1 cycle if !=0, 2 cycles otherwise)
// goto loop start - 2 cycles
} while(--n);
// = 16 cycles x [n+1] + 1 (from last decfsz)
}
}