View previous topic :: View next topic |
Author |
Message |
leto
Joined: 02 Aug 2005 Posts: 14
|
Timer1 and milliseconds |
Posted: Wed Sep 07, 2005 9:13 am |
|
|
Hi,
I am trying to make a chronometer. I am using timer1 each a millisecond, but he is not very exact.
Code: |
#define COUNTER1 60585
setup_counters(RTCC_INTERNAL,RTCC_DIV_1);
set_rtcc(COUNTER1);
#int_rtcc
void crono(){
set_rtcc(COUNTER1);
++tick;
}
|
Anybody can help me ?. May be using another function or something.I need to obtain exactitude. Im using 18F452.
thank you |
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Wed Sep 07, 2005 9:47 am |
|
|
(Isn't rtcc actually Timer 0?)
Anyways,
Is your 1.0 ms off by a few MICROseconds?
This would be due to all the overhead of saving interrupt context before you actually get to the meat of your interrupt service routine. And it will get worse if you have other interrupt sources enabled.
You can try a "fast interrupt" to get some of the latency reduced, but I don't know how to implement one.
One way to get a 'guaranteed' 1ms delay would be to write:
Code: |
disable_interrupts(GLOBAL);
delay_ms(1);
enable_interrupts(GLOBAL);
|
This is an awkward way to do things since you are now starving interrupts from executing, but it is a guaranteed way to get 1ms.
There are other options you can do such as using the CCP. |
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Wed Sep 07, 2005 9:54 am |
|
|
Oh, I think I veered off-topic above.
You are designing a "chronometer", which is just like a watch, right?
Hey, then all you need is a 32.768khz external clock source hooked up to the PIC's timer pins!
32,768 ticks = 0x8000 counts in a 16-bit timer. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Sep 07, 2005 10:36 am |
|
|
Code: | #int_rtcc
void crono(){
set_rtcc(COUNTER1);
++tick;
} | This way of setting the timer is easy but not very accurate. It is very difficult to get the value for COUNTER1 exactly right because as MikeValencia already mentioned you have to account for interrupt overhead as well. The amount of interrupt overhead can be determined from studying the generated assembly code. Problem is that this might change with a new compiler version so is not a very stable solution.
Your main problem is that your clock frequency is not a multiple of 256, if this was the case you could have chosen a prescaler value that would give you an exact 1ms interrupt and no setting of the timer value was required.
I see the following solutions:
1) Choose another clock frequency that gives you exact 1.0ms intervals with the possible prescaler values.
2) Use timer2 which has an extra compare register for exactly this purpose.
3) Attach a 32.768kHz crystal to the timer inputes as MikeValencia suggested. |
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Wed Sep 07, 2005 10:50 am |
|
|
ckielstra wrote: | Code: | #int_rtcc
void crono(){
set_rtcc(COUNTER1);
++tick;
} |
Your main problem is that your clock frequency is not a multiple of 256, if this was the case you could have chosen a prescaler value that would give you an exact 1ms interrupt and no setting of the timer value was required.
I see the following solutions:
1) Choose another clock frequency that gives you exact 1.0ms intervals with the possible prescaler values.
|
I'm looking at Digikey right now, and have found crystals with the following frequencies:
8.192MHz
4.096MHz
You wouldn't need an external 32.768khz clock source if you can use one of the crystals above and just play with the prescaler settings. With that being said, I don't know now if you truly need 1ms precision or 1-second precision. Anyways, you should do as ckielstra said and find a frequency whose number of ticks would be exactly divisible by the time granularity you want. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Wed Sep 07, 2005 11:11 am |
|
|
From you code I figured that you are using a 20MHz crystal. Here's what I do.
Code: |
/* setup timer2 - 1ms counter */
setup_timer_2(T2_DIV_BY_4, 0xFA, 5);
|
|
|
|
Guest
|
|
Posted: Wed Sep 07, 2005 7:17 pm |
|
|
Thank you. But I think I have a oscilator problem because the timing diferences has not constant. I thing the osc change the frecuency.
Im using a 20mhz crystal and two 15pf.
regards, leto |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Sep 08, 2005 4:40 am |
|
|
Do you have other interrupts active besides the timer interrupt?
How large are the timing deviations you get? |
|
|
Ttelmah Guest
|
|
Posted: Thu Sep 08, 2005 4:51 am |
|
|
It might be because the line that Mark has posted will actually give 1.004mSec. The count value needs to be 0xF9, not 0xFA. The count includes zero remember, so needs to be 0....249, not 250.
Te sort of arithmetc slip I do all the time, and which the CCS 'wizard' used to do as well. :-)
Best Wishes |
|
|
Guest
|
|
Posted: Thu Sep 08, 2005 6:50 am |
|
|
Yes, I have activated other interrupts: #ext, #rb and #rda, but there is no events fired while I check the time. The only one fired is #rb that I use to start-stop counting but just twice per count.
The follow result is using: setup_timer_2(T2_DIV_BY_4, 0xFA, 5);
and
#INT_TIMER2
void crono{
++tick;
}
Manual
Chrono PIC
=============
05:02.65 - 05:01.29
00:59.91 - 00:59.28
12:14.25 - 12:11.20
PIC is slower than a standard chronometer. |
|
|
Ttelmah Guest
|
|
Posted: Thu Sep 08, 2005 7:19 am |
|
|
Assuming the first figure is minutes, then this is _exactly_ the error expected from the arithmetic fault I pointed out.
The first example 302.65secs versus 301.29 = 1.0045*
The third example (the best, since with the largest count, it reduces other possible error sources the most), gives 734.25/731.2 = 1.0041*
Correct the count as I have already posted.
Best Wishes |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Sep 08, 2005 8:02 am |
|
|
Ttelmah wrote: | It might be because the line that Mark has posted will actually give 1.004mSec. The count value needs to be 0xF9, not 0xFA. The count includes zero remember, so needs to be 0....249, not 250.
Te sort of arithmetc slip I do all the time, and which the CCS 'wizard' used to do as well. :-)
Best Wishes |
Yep, I learned something today Time to rev all my firmware |
|
|
Guest
|
|
Posted: Thu Sep 08, 2005 8:09 am |
|
|
thank you Ttelmah. It works much better, but look: I still have aprox. 1/300 seg of difference when I test short times 4 or 10 seconds. When I test more time, 30 or 40 minutes it difference disappear and it works well.
Could you tell me how can I improve the accurate. May be using PWM or something. I have a PIC18F452.
Regards,
leto |
|
|
Guest
|
|
Posted: Thu Sep 08, 2005 8:19 am |
|
|
Yes Mark, so the manual about setup_timer2 is wrong.
setup_timer_2 ( T2_DIV_BY_4, 0xc0, 2);
// At 20mhz, the timer will increment every 800ns,
// will overflow every 153.6us,
// and will interrupt every 307.2us. |
|
|
Ttelmah Guest
|
|
Posted: Thu Sep 08, 2005 9:38 am |
|
|
Anonymous wrote: | thank you Ttelmah. It works much better, but look: I still have aprox. 1/300 seg of difference when I test short times 4 or 10 seconds. When I test more time, 30 or 40 minutes it difference disappear and it works well.
Could you tell me how can I improve the accurate. May be using PWM or something. I have a PIC18F452.
Regards,
leto |
How are you actually 'triggering' the two counters?. I saw that the shorter time was in error by more than the other two, and assumed this was probably something like the actual change being detected differently by the two systems. Remember that there will _always_ be differences in short times, unless the clocks are synchronous, and these will be made worse if (for instance), the triggering signal has a fairly slow edge, and one circuit detects it at 2.4v, and the other at 4v.
best Wishes |
|
|
|