Catching with real time - interrupt

Discussion in 'Embedded Systems and Microcontrollers' started by oookey, May 26, 2014.

  1. oookey

    Thread Starter Member

    May 24, 2010
    62
    0
    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:
    Code ( (Unknown Language)):
    1.  
    2.  unsigned pwm, count;
    3.    void interrupt(){     //ISR
    4.        if(intcon.t0if ){   // interrupt timer0 flag overflow
    5.           intcon.t0if=0;  // reset timer0 flag
    6.            count++;       // increase counter by 1
    7.            tmr0=0;     }  //reset timer0
    8.                    }
    9.  
    10.    void init(){
    11.        count=0;
    12.        tmr0=0;
    13.        option_reg.t0cs=0; // use internal clock
    14.        option_reg.psa=0; //prescaler assigned to timer0
    15.        //Prescaler timer0 rate setting 1:256
    16.        option_reg.ps0=1;
    17.        option_reg.ps1=1;
    18.        option_reg.ps2=1;
    19.        intcon.t0ie=1;        //enable timer0 interrupt
    20.        intcon.gie=1;        //enable global interrupt
    21.        trisio=0;               // all ports as output
    22.        pwm=25;                // 10%
    23.        pwm1_init(10000);   //initial pwm F=10khz
    24.               }
    25.  
    26. void main() {
    27.      init();
    28.        while(1){
    29.      while(count<1954){  //about 57sec
    30.          pwm1_start();
    31.          pwm1_set_duty(pwm);
    32.                        } //ends while(<1954)
    33.  
    34.       while(count<2054){ //about another 3sec
    35.          pwm1_stop();
    36.          gpio.f2=0;
    37.                       }
    38.                        //ends while(<2054)
    39.        count=0;  // reset counter
    40.                       }// ends while(1)
    41.             } //ends main()
    42.  
     
    Last edited by a moderator: May 26, 2014
  2. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
  3. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    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)?
     
  4. oookey

    Thread Starter Member

    May 24, 2010
    62
    0
    Ya, i'm using internal oscillator clock, 8Mhz
     
  5. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    How does the accuracy of the internal clock compare to the error you observe?
     
  6. oookey

    Thread Starter Member

    May 24, 2010
    62
    0
    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.
     
  7. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    You could read what the data sheet says.
     
  8. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    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!
     
  9. oookey

    Thread Starter Member

    May 24, 2010
    62
    0
    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.
     
  10. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    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: May 29, 2014
    oookey likes this.
  11. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    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).

    Code ( (Unknown Language)):
    1.  
    2. unsigned char secs;
    3. unsigned int pwm;
    4. unsigned long bres;
    5.  
    6.    void interrupt()
    7.    {     //ISR
    8.        if(intcon.t0if)
    9.        {  
    10.          intcon.t0if=0;  // reset timer0 flag
    11.          
    12.          // this makes an exact 1 second average period, from 8MHz osc.  
    13.          // interrupt occurs every 1024 ticks, tick = 2MHz
    14.          bres += 1024;
    15.          if(bres >= 2000000)
    16.          {
    17.            bres -= 2000000;
    18.            secs++;
    19.          }
    20.        }
    21.    }
    22.  
    23.    void init()
    24.    {
    25.        secs=0;
    26.        option_reg.t0cs=0; // use internal clock
    27.        option_reg.psa=0; //prescaler assigned to timer0
    28.        //Prescaler timer0 rate setting 1:4
    29.        option_reg.ps0=1;
    30.        option_reg.ps1=0;
    31.        option_reg.ps2=0;
    32.        intcon.t0ie=1;        //enable timer0 interrupt
    33.        intcon.gie=1;        //enable global interrupt
    34.        trisio=0;               // all ports as output
    35.        pwm=25;                // 10%
    36.        pwm1_init(10000);   //initial pwm F=10khz
    37.    }
    38.  
    39.    void main()
    40.    {
    41.      init();
    42.      while(1)
    43.      {
    44.        while(secs < 57)
    45.        {
    46.          pwm1_start();
    47.          pwm1_set_duty(pwm);
    48.        }
    49.        else   // 57 to 60 secs
    50.        {
    51.          pwm1_stop();
    52.          gpio.f2=0;
    53.          if(secs >= 60) secs=0;  // reset counter at 60 secs
    54.        }
    55.                        
    56.      }
    57.    } //ends main()
    58.  
    Now if your timer still runs fast or slow, just adjust that 2000000 value in the code; >2mil = slower, <2mil = faster

    :)
     
    Last edited: May 31, 2014
    oookey likes this.
  12. paulfjujo

    New Member

    Mar 6, 2014
    20
    3
    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.
     
  13. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    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%.
     
  14. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Because you did not setup the calibration value, see my post #10.

    Yes that's good practice. But your compiler MikroCpro does not require it, it treats vars in interrupt as volatile by default.

    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".
    :)
     
Loading...