I'll chuck a code snippet at you that will let you do longer software delays than the native delay macros can handle. Its good out to over a minute.
//Just a simple delay, tuned for accuracy
//XC8 v1.35 Free mode @30MHz on PIC18
#define DELTUNE 1.2
#define DELTUNE1 2.666
void DelayMs(unsigned int ms) {
if(!ms) return; //Handle zero case
__delay_us(1000-DELTUNE1);
while(--ms)
__delay_us(1000-DELTUNE); // Tuning breakpoint here
}
DELTUNE compensates for loop overhead and DELTUNE1 for function entry/exit overhead. They will need tweaking if you want accuracy. see
http://www.microchip.com/forums/m946599.aspxHere's another snippet for an ISR to implement a 1/10 second 'tick' counter that's as accurate as the crystal over long periods. Individual ticks jitter about a bit by up to one tick period, but the correction is carried forward from tick to tick. It rolls over after about 13 1/2 YEARS.
. A 16 bit version has a 109 minute rollover. Bump up the tick rate to 100 per second if you need better accuracy for short periods.
The natural timer rollover rate must be between the tick rate and half the tick rate .
#include <stdint.h>
volatile uint32_t ticks=0; // tick count in 1/10 s units
#define COUNT100MS 62500UL // for 10Hz tick rate
#define T1ROLLOVER 0x10000UL
#define SECONDS *10
#define MINUTES *600
#define HOURS *36000
//ISR
void interrupt ISR(void) {
static uint16_t excess=0;
if(PIE1bits.TMR1IE && PIR1bits.TMR1IF) {
PIR1bits.TMR1IF=0;
ticks++;
excess+=T1ROLLOVER-COUNT100MS;
if(excess>=COUNT100MS) {
excess-=COUNT100MS;
ticks++;
}
}
}
It was written for a PIC16 so will need some tweaking for a PIC18. COUNT100MS is the number of timer increments per tick. It should be between 32768 and 65535. N.B. when the correction is applied 'ticks' double increments so never test if it is exactly equal to some number, only use inequaities.
You would have to set up Timer1 and enable its interrupt yourself as the PIC18 version differs too much from the PIC16 version for it to directly help you.
Also you need to disable interrupts while reading 'ticks' in the main program so you don't get it while its being changed. e.g.:
di();
t=ticks; //Read ticks with interrupts disabled
ei();
if(t>5 MINUTES){
//do whatever here
}
I prefer a macro 'ATOMIC' to handle the di()/ei() so I can simply do:
ATOMIC t=ticks;
See
http://www.microchip.com/forums/m839163.aspx for details. and reasons why you need to disable the interrupts while manipulating a multibyte variable shared with an ISR.