Catching with real time - interrupt

Thread Starter

oookey

Joined May 24, 2010
70
Hi everybody,

I got stuck to keep my program running on real time.
The program suppose to turn off the O/P at 57th second, & back on the O/P at 60th second, however I noticed the 57th second kept shifting backwards! say after power up chip running for about 5 minutes or so the O/P no more off at 57th second, but off at 60+ seconds, and on at 3 seconds later, and…keep on shifting back! When compared to the real time clock. I could not figure out my mistake. :confused:
Is there any way to keep the cycle stays with the real time?
I’m using PIC12F615, interrupt timer0 overflow, program with mikroCpro version 6.0.0.
If the WDT can play apart to overcome this problem, how do I program? Please any advice?
Thanks!

The source code:
Rich (BB code):
 unsigned pwm, count;
   void interrupt(){     //ISR
       if(intcon.t0if ){   // interrupt timer0 flag overflow
          intcon.t0if=0;  // reset timer0 flag
           count++;       // increase counter by 1
           tmr0=0;     }  //reset timer0
                   }

   void init(){
       count=0;
       tmr0=0;
       option_reg.t0cs=0; // use internal clock
       option_reg.psa=0; //prescaler assigned to timer0
       //Prescaler timer0 rate setting 1:256
       option_reg.ps0=1;
       option_reg.ps1=1;
       option_reg.ps2=1;
       intcon.t0ie=1;        //enable timer0 interrupt
       intcon.gie=1;        //enable global interrupt
       trisio=0;               // all ports as output
       pwm=25;                // 10%
       pwm1_init(10000);   //initial pwm F=10khz
              }

void main() {
     init();
       while(1){
     while(count<1954){  //about 57sec
         pwm1_start();
         pwm1_set_duty(pwm);
                       } //ends while(<1954)

      while(count<2054){ //about another 3sec
         pwm1_stop();
         gpio.f2=0;
                      }
                       //ends while(<2054)
       count=0;  // reset counter
                      }// ends while(1)
            } //ends main()
 
Last edited by a moderator:

ErnieM

Joined Apr 24, 2011
8,415
Are you trying to say your timer is running fast?

What is the clock source for the PIC? External crystal (very accurate) or internal RC (wanders)?
 

Thread Starter

oookey

Joined May 24, 2010
70
I need not to observe the 8 MHz clock, just simply compare with real time stop watch for 57 second off and 60 sec on.
 

THE_RB

Joined Feb 11, 2008
5,438
The numbers seem wrong?

Internal clock of 8MHz gives 2MHz timer ticks.

Then TMR0 is set to 256:1 prescale, so TMR0 rolls at;
2000000 /256 / 256 = 30.51 Hz

So to time a period of 57 seconds;
counts = 57 * 30.51 = 1739.5

The OP is using this;
while(count<1954){ //about 57sec
and saying it is STILL fast, maybe 56 seconds?

So it looks like the internal osc is running significantly faster than 8MHz;
(((1954*57)/56) / 1739.5) * 8000000
=9.1 MHz :eek:

That internal osc is running about 14.3% fast!
 

Thread Starter

oookey

Joined May 24, 2010
70
The numbers seem wrong?

Internal clock of 8MHz gives 2MHz timer ticks.

Then TMR0 is set to 256:1 prescale, so TMR0 rolls at;
2000000 /256 / 256 = 30.51 Hz

So to time a period of 57 seconds;
counts = 57 * 30.51 = 1739.5

The OP is using this;
while(count<1954){ //about 57sec
and saying it is STILL fast, maybe 56 seconds?

So it looks like the internal osc is running significantly faster than 8MHz;
(((1954*57)/56) / 1739.5) * 8000000
=9.1 MHz :eek:

That internal osc is running about 14.3% fast!
Thanks TH_RB :) , this indeed a good pointer to me, but i do not think they would produce such a high error MCU do they?
i'll approach by eliminating the accumulative error.
 

THE_RB

Joined Feb 11, 2008
5,438
Some PIC will run quite fast on INTRC if you are not correctly using the calibration constant.

Please read the datasheet for your PIC 12F615, the chapter on "oscillator" or whatever it's called these days. That should have a section on setting the calibration constant for the internal RC osc. There should even be a little source code example.
:)

Once you have set the calibration constant properly, the PIC should then run within about 1% of its proper INTRC osc speed 8MHz.

If you really want to count seconds i suggest you change the TMR0 interrupt to use a zero-error 1 second routine from this page;
http://www.romanblack.com/one_sec.htm

So the interrupt generates actual seconds, which can be tweaked by adjusting one numerical constant.

I've been able to get decent timer accuracy using the INTRC osc and that code technique (with some back-forth tweaking, comparing to a household clock).
 
Last edited:

THE_RB

Joined Feb 11, 2008
5,438
OK, I tidied up the messy curly braces in your code, changed the TMR0 prescaler to 1:4, and changed your interrupt to use a 1-second average bresenham routine. So the interrupt now generates perfect seconds on average (assuming your 8MHz osc is 8MHz).

Rich (BB code):
unsigned char secs;
unsigned int pwm; 
unsigned long bres;

   void interrupt()
   {     //ISR
       if(intcon.t0if)
       {   
         intcon.t0if=0;  // reset timer0 flag
         
         // this makes an exact 1 second average period, from 8MHz osc.  
         // interrupt occurs every 1024 ticks, tick = 2MHz
         bres += 1024;
         if(bres >= 2000000)
         { 
           bres -= 2000000;
           secs++;
         }
       }
   }

   void init()
   {
       secs=0;
       option_reg.t0cs=0; // use internal clock
       option_reg.psa=0; //prescaler assigned to timer0
       //Prescaler timer0 rate setting 1:4
       option_reg.ps0=1;
       option_reg.ps1=0;
       option_reg.ps2=0;
       intcon.t0ie=1;        //enable timer0 interrupt
       intcon.gie=1;        //enable global interrupt
       trisio=0;               // all ports as output
       pwm=25;                // 10%
       pwm1_init(10000);   //initial pwm F=10khz
   }

   void main() 
   {
     init();
     while(1)
     {
       while(secs < 57)
       {
         pwm1_start();
         pwm1_set_duty(pwm);
       } 
       else   // 57 to 60 secs
       {
         pwm1_stop();
         gpio.f2=0;
         if(secs >= 60) secs=0;  // reset counter at 60 secs
       }
                       
     }
   } //ends main()
Now if your timer still runs fast or slow, just adjust that 2000000 value in the code; >2mil = slower, <2mil = faster

:)
 
Last edited:

paulfjujo

Joined Mar 6, 2014
23
Hello The_RB

Why do you suspect FOSC is 14% over ?

because 57em second must be, has you told before, at 1739
and 60em at 1831
not 1954 and 2051 like in the software Posted in #1

What is the result with the corrected limites values ?

nota: unsigned count , must be declared as volatile.

I allready used internal FOSC with 12F1840 , and never met big probleme
due to FOSC accuracy .
+-1% could be usual without correction by FOSCTUNE.
 

Markd77

Joined Sep 7, 2009
2,806
One time I forgot to add a decoupling capacitor close to the PIC (using internal osc), the frequency was about 10% out, added the capacitor and it was well within 1%.
 

THE_RB

Joined Feb 11, 2008
5,438
Hello The_RB

Why do you suspect FOSC is 14% over ?
...
Because you did not setup the calibration value, see my post #10.

...
nota: unsigned count , must be declared as volatile.
Yes that's good practice. But your compiler MikroCpro does not require it, it treats vars in interrupt as volatile by default.

...
I allready used internal FOSC with 12F1840 , and never met big probleme
due to FOSC accuracy .
+-1% could be usual without correction by FOSCTUNE.
It depends on which PIC! They handle INTRC osc and OSCTUNE etc differently. It also depends if your programmer erases the calibration constant. Please read the datasheet for the PIC you are using; chapter "oscillator".
:)
 
Top