CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

timer0 not working properly

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
GiG



Joined: 03 Sep 2021
Posts: 39

View user's profile Send private message

timer0 not working properly
PostPosted: Thu Nov 04, 2021 2:11 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 04, 2021 6:32 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 04, 2021 7:03 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Nov 07, 2021 12:01 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Nov 07, 2021 3:38 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Nov 07, 2021 4:37 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Nov 07, 2021 10:20 am     Reply with quote

It increments 'second' every 15625 times the interrupt occurs.
PrinceNai



Joined: 31 Oct 2016
Posts: 480
Location: Montenegro

View user's profile Send private message

PostPosted: Sun Nov 07, 2021 1:04 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Nov 08, 2021 12:29 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Nov 08, 2021 12:49 am     Reply with quote

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: 9247
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Nov 08, 2021 6:37 am     Reply with quote

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....
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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