|
|
View previous topic :: View next topic |
Author |
Message |
GiG
Joined: 03 Sep 2021 Posts: 39
|
timer0 not working properly |
Posted: Thu Nov 04, 2021 2:11 am |
|
|
Hello
I had a problem setting the time for one minute with a zero timer.
The problem is that I use PLL so the frequency is supposed to be 32 GHz.
And my formulaic calculations to get a second was this:
32000000 / (4 * 2) * (256-0) = 15625
So if I set the prescaler div to 2 and put 0 inside the timer.
And then counting it to 15625, I have to get to 1 second.
Well, when I do this, every minute instead of 60 seconds, it becomes almost 63 seconds and it does not give an exact output. I wanted to know where I am doing something wrong.
Code: |
#include <16f1939.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,PLL_SW,NOMCLR,NOBROWNOUT,PUT
#device ADC=10
#use delay(internal=8000000)
#use FIXED_IO( A_outputs=PIN_A7,PIN_A6,PIN_A5,PIN_A4,PIN_A3,PIN_A2,PIN_A1,PIN_A0 )
#use FIXED_IO( B_outputs=PIN_B1,PIN_B0 )
#use FIXED_IO( C_outputs=PIN_C7,PIN_C6,PIN_C5,PIN_C4,PIN_C3,PIN_C2,PIN_C1,PIN_C0 )
#use FIXED_IO( D_outputs=PIN_D7,PIN_D6,PIN_D5,PIN_D4,PIN_D3,PIN_D2,PIN_D1,PIN_D0 )
#use FIXED_IO( E_outputs=PIN_E1,PIN_E0 )
#INCLUDE <math.h>
const int16 timing= 15625; |
Code: | #INT_TIMER0
void timer0_isr(void)
{
set_timer0(0);
clear_interrupt(INT_TIMER0);
}
void calculate_time()
{
if (counter_time>=timing){
counter_time=0;
second++;
}
if (second>59)
{
minute++;
second=0;
}
void main (){
Setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2|RTCC_8_BIT);//
enable_interrupts(INT_TIMER0);
setup_oscillator(OSC_8MHZ | OSC_PLL_on);
enable_interrupts(GLOBAL);
}
while(1)
{
calculate_time();
//display();
}
|
The code is more detailed, but this is the summary. |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Thu Nov 04, 2021 6:32 am |
|
|
The code posted won't work as-is, but on to what I believe is your root problem. The timer 0 interrupt fires when the timer has overflowed and is set back to zero. You get into the timer 0 interrupt a short time later and then set it to zero, so you are losing some of the hardware timer counts and forcing it back to zero. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19553
|
|
Posted: Thu Nov 04, 2021 7:03 am |
|
|
First thing, if you are running at 32MHz (not GHz), then tell the compiler
this. So
#use delay(internal=32MHz)
You don't need a setup oscillator line at all.
Then get rid of any fuses that setup the oscillator
#fuses NOWDT,NOPROTECT,NOLVP,NOMCLR,NOBROWNOUT,PUT
Then your code in the timer:
Code: |
int16 timing=15625;
int8 second=0;
#INT_TIMER0
void timer0_isr(void)
{
//Not needed the timer has just wrapped to 0 set_timer0(0);
//Not needed the compiler clears this clear_interrupt(INT_TIMER0);
if (--timing==0)
{
timing=15625;
second++;
}
}
|
'second' will then increment once a second.
However you need to be aware that the internal oscillator is not accurate.
+/-2% at best.
The reason it is running slow, is you are resetting the timer back to zero,
when it has already counted about 16 counts. If takes typically about 30
instruction times to get into the interrupt handler routine. With the /2
division, perhaps 15 to 16 counts before it reaches your reset instruction.
I see Gaugeguy has already pointed this out.
The chip will be spending perhaps 12% of it's time actually inside this
interrupt. Much better to count a lot slower. Use the /256 prescaler and
count to 122 and the chip will waste only about 1% of it's time doing this
count.
Though the accuracy is limited using the internal clock, you could do an
accurate division using timer2, where you can specify the division, so
use the /64 prescaler and then a count of 249 (which gives /250), and
you'd get 500 interrupts per second. |
|
|
GiG
Joined: 03 Sep 2021 Posts: 39
|
|
Posted: Sun Nov 07, 2021 12:01 am |
|
|
Ttelmah wrote: |
The chip will be spending perhaps 12% of it's time actually inside this
interrupt. Much better to count a lot slower. Use the /256 prescaler and
count to 122 and the chip will waste only about 1% of it's time doing this
count.
Though the accuracy is limited using the internal clock, you could do an
accurate division using timer2, where you can specify the division, so
use the /64 prescaler and then a count of 249 (which gives /250), and
you'd get 500 interrupts per second. |
Thanks for your guidance.
What is very important to me is how to easily count using the formula I wrote above.
I mean, every time I use this formula, I have to come and check how many commands I have in the interrupt?
Another question: if I have risen according to the same code I wrote above, I can also count a few variables of the pot.
How about this time?
I want to add to all these variables every time interrupt is activated!
Okay ! What problems am I facing?
Code: | #INT_TIMER0 //
void timer0_isr(void)
{
set_timer0( 0 + get_timer0() );
counter_time++;
counter_b++;
counter_rotation++;
counter_led++;
counter_out++;
counter_gass++;
counter_gass2++;
counter_temp++;
counter_buz++;
temptimer++;
delaytime++;
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19553
|
|
Posted: Sun Nov 07, 2021 3:38 am |
|
|
Do what I said, and use a slower interrupt.
Every addition takes time.
Don't set the timer. This is completely pointless.
The interrupt is called when the timer wraps to zero, so setting it is
just a waster of time.
Just calling the interrupt at your fast rate (with /2), doesn't give you time
to perform a dozen additions, especially if any of these values are
larger types like int16 or int32. |
|
|
GiG
Joined: 03 Sep 2021 Posts: 39
|
|
Posted: Sun Nov 07, 2021 4:37 am |
|
|
Ttelmah wrote: | Do what I said, and use a slower interrupt.
Every addition takes time.
Don't set the timer. This is completely pointless.
The interrupt is called when the timer wraps to zero, so setting it is
just a waster of time.
Just calling the interrupt at your fast rate (with /2), doesn't give you time
to perform a dozen additions, especially if any of these values are
larger types like int16 or int32. |
OK can you tell me what is the purpose of this part ?Or explain why you were doing this
Code: | if (--timing==0)
{
timing=15625;
second++;
} |
in this code in every 25 minutes
3 seconds time is ahead |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19553
|
|
Posted: Sun Nov 07, 2021 10:20 am |
|
|
It increments 'second' every 15625 times the interrupt occurs. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Sun Nov 07, 2021 1:04 pm |
|
|
Quote: |
in this code in every 25 minutes
3 seconds time is ahead
|
Your error is 3s/1500s, which equals 0,002 or 0,2%. When you compare that to 65535, you get 65536*0,002 or 131,072. I didn't quite get it if your timer is slow or fast with respect to the "correct" time. But since your reload value for timing is 15625, try with 15494 if your clock is faster or 15756 if your clock is slower. |
|
|
GiG
Joined: 03 Sep 2021 Posts: 39
|
|
Posted: Mon Nov 08, 2021 12:29 am |
|
|
PrinceNai wrote: | Quote: |
in this code in every 25 minutes
3 seconds time is ahead
|
Your error is 3s/1500s, which equals 0,002 or 0,2%. When you compare that to 65535, you get 65536*0,002 or 131,072. I didn't quite get it if your timer is slow or fast with respect to the "correct" time. But since your reload value for timing is 15625, try with 15494 if your clock is faster or 15756 if your clock is slower. |
thankyou It was a useful guide
The question that baffles me is that we always have to set the timer this way ؟when we use interrupts?
i mean after using the formula, we have to calculate the 2% errors in timers and the numbers of commands used in interrupt? To reach the exact number, that is, by trial and error
This problem is only in PIC or all the microphones are like this? |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Mon Nov 08, 2021 12:49 am |
|
|
GiG wrote: |
This problem is only in PIC or all the microphones are like this? |
A lot of the more modern PICs let you set the period of the timer too, so that part can just be set and forget on those chips. I don't know if yours has that option or not.
The error % has a lot to do with your hardware setup and choice of peripherals. There's probably going to be some tolerance you have to account for but usually the best error % values come from externally timed timers. You can get crystals with very low error (though it is on you to ensure the board layout is correct to actually attain those good numbers).
I know on our PIC24's we use Timer1 which allows for async crystal inputs and we select a very accurate crystal for it.
Of course there are external IC options too that might give better error %.
Just for example, our timer setup code is something like:
Code: | setup_timer1(TMR_EXTERNAL_RTCC,0x7FFF); |
and that makes the interrupt fire once per second. We use a 32kHz crystal with enough tolerance for our application. And the ISR doesn't even need to have much of a handler since setting the period to 0x7FFF is exactly 32767, which matches the crystal frequency. So no fancy math, just count the seconds by incrementing the count each time the interrupt occurs. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Mon Nov 08, 2021 6:37 am |
|
|
timer tidbits....
1) unless the timer clock source is exactly a 'binary' number (say 2.45760 MHz ), the divisor will have to be 'tweaked'. NO micro can divide by 2.347 and 1/2.
2) there's 'overhead' (stuff the PIC has to do) when the ISR is called (stuuf like save registers,move this here,there,etc.) That all takes time, which will factor into the overall code. Stuff done inside the ISR has to be short and fast.
3) if using the internal RC osc, it's NOT exactly say, 4.000000000000 MHz, 24/7 ,hot or cold, so even IF you do the 'math' 100%, the clock is just a lil bit fast or slow. You'll need to adjust for this and every PIC, even within the same batch, can be different. Some PICs allow you to 'tweak' the internal clock, a bit.... |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|