View previous topic :: View next topic |
Author |
Message |
guestplanet Guest
|
timing |
Posted: Mon Dec 03, 2007 2:44 am |
|
|
i'm using PIC18F452 with crystal 11.0592MHz
i've completed the source code for my system that needs accurate timing.
the calculation i've done for my timer0 interrupt is as follows,
11059200/4=2764800;
2764800/256(8-bit TMR0 register)=10800
10800/16(pre-scaler)=675
therefore, i need to count up to 675, a good round figure for one sec timing
my code for High priority timer0 interrupt
/*
#INT_TIMER0 FAST //fast context saving
void ISR_TMR0 (void) //High priority
{ //triggers every 1.48ms
if (++cnt_sec_timeup == 675)
{
cnt_sec_timeup = 0;
bit_timeout_1s = 1; //set 1s task
}
bit_timeout_1ms = 1; //set 1.48ms task
if (++cnt_1ms == 7) //triggers every 10.3ms
{
cnt_1ms = 0;
bit_timeout_10ms = 1; //set 10ms task
}
}
*/
every 1 sec bit generated is accumulated in the main program
my system will generate an output every 24 hours, but i find that this system actually triggers an output about 5-6 seconds earlier every single day. i've checked and double check, other sub-functions do not interfere with the timing and i'm not sure what went wrong |
|
![](templates/subSilver/images/spacer.gif) |
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Mon Dec 03, 2007 9:16 am |
|
|
Well you are in and out of the timer 675 times per sec and the calling and returning from the interrupt takes cycles...this should slow things down and cause your timing to lag real time..so at the end of the day after thousands of isr calls your system time is dilated ( system seconds were stretched slightly) so that means there were less system seconds in your day than real seconds. If this is what you mean by early then this might be the explanation. |
|
![](templates/subSilver/images/spacer.gif) |
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Mon Dec 03, 2007 9:38 am |
|
|
You're not leaving much time for your PIC to do much else than service the ISR. You don't want your timer sucking up more time than it absolutely needs. Whenever I am planning on having a timer flag once a second I'll choose a crystal that will give me an even number when divided by all of the register and prescalers.
For instance, I used a 19.6608MHZ crystal with Timer0. The timer's prescaler was set to 256. That would have resulted in - 19660800/4/256/256 = 75 interrupts per second. This will allow the PIC plenty of time to do other things.
You might want to find a crystal that will do the same thing for you.
Ronald |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Dec 03, 2007 10:02 am |
|
|
Douglas Kennedy wrote: | Well you are in and out of the timer 675 times per sec and the calling and returning from the interrupt takes cycles...this should slow things down and cause your timing to lag real time.. | I don't think this is the problem here. The time taken to enter the interrupt would only be a problem if he was changing the value of timer0 in the interrupt but he isn't.
How accurate is the clock source? 6 out of 86400 seconds is an error of only 0.007% ...
What are the accuracy specifications for your crystal?
Are you sure the crystal has correct capacitive loading? Incorrect capacitive load will cause the frequency to change.
Is it build on a PCB or breadboard? Breadboards have _lots_ of capacitance.
Another problem could have to do with your high interrupt frequency. It won't be easy to find, but maybe there is a routine or function in your program disabling the interrupts for a few milliseconds? This would cause an interrupt to be missed. Some of the CCS inbuilt functions are known to do disable interrupts, for example the software UART and write to EEPROM routines.
An easy method to test if you are missing interrupts is to add the following code to your interrupt handler: Code: | if (get_timer0() > 50) // It takes about 30 instructions to enter the interrupt handler.
// 50 * 16 prescaler = 800 instructions and should never be true.
output_low(LED); // activate LED, or some other visible sign. |
Have this code running for some time and if the LED is activated you know you are missing interrupts. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Mon Dec 03, 2007 11:09 am |
|
|
There are some thing that would increase the efficiency of the code (for example, it is more efficient to set the counter to a required value, and decrement it, than to test for a counter 'being' a value). The former returns zero, when it reaches zero, the latter has to perform a separate subtraction to test for the required result. However 675 times per second, is not hard to do, and shouldn't cause problems. If the code was taking too long, the clock would lose time, rather than gain time.
My biggest suspicion would simply be that the loading capacitors on the crystal are the wrong value. The error involved is well inside the range that would be achieved with incorrect loading.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
guestplanet Guest
|
|
Posted: Mon Dec 03, 2007 7:21 pm |
|
|
well, i needed the timer to set 1ms task (actually 1.48ms but i can live with that), set 10ms task (10.3ms, again not critical) and set 1sec task
i find that my single 24-hour task actually triggers earlier (about 5-6 secs) than it actually should. Putting it as PIC counting from 1sec to 86400sec beginning from actual time of 12.00.00 am, i'm getting an output at 11.59.55 p.m
i've not used any in-built CCS functions and EEPROM. i'm aware that these will cause interrupt to cease for a moment
i used 15pF capacitors with the crystal |
|
![](templates/subSilver/images/spacer.gif) |
guestplanet Guest
|
|
Posted: Mon Dec 03, 2007 9:43 pm |
|
|
i found out that i've used table read instructions, and in turn will switch off my timer0 interrupt temporarily but i doubt this will cause much problem to my interrupts. the TMR0 will keep on incrementing and setting a flag upon overflow whether the interrupt enable bit is off or on thus i still have precise timing for 1 sec.
correct me if i'm wrong |
|
![](templates/subSilver/images/spacer.gif) |
|