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

Timer based Real Time Clock (RTC)
Goto page 1, 2, 3, 4  Next
 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

Timer based Real Time Clock (RTC)
PostPosted: Tue Feb 28, 2006 6:18 pm     Reply with quote

Many times in the forums I have seen people asking for a real time clock based on the internal timers of the PIC. Several implementations of the version supplied by Neutone can be found in the discussion forum but not here in the code forum so I decided to add a new topic.

I like this algorithm because it is very accurate (zero drift) even when your clock frequency is not a multiple of 256Hz. Most algorithms configure the timer to generate an interrupt every 100ms, and then count the number of times the interrupt occurs. The problem in that approach is that with nice round clock frequencies like 16MHz you can't get an exact 100ms and the small error will count up to an error of several seconds a day. The algorithm presented here doesn't count the number of interrupts but counts the number of clock cycles which makes it very accurate in the long run.

The current implementation uses Timer1 but this can easily be changed to another internal timer.

Code:
///////////////////////////////////////////////////////////
// Zero Drift Real Time Clock
// Original code supplied by Neutone.
// Some small optimizations by C.Kielstra.
///////////////////////////////////////////////////////////
#include <18F458.h>
#use delay(clock=20000000)
#fuses HS,NOWDT,NOLVP

//RTC variables
#define XTAL_FREQUENCY  20000000
#define TIMER1_FREQUENCY (XTAL_FREQUENCY / 4)      // 1 clock tick = 1 instr. cycle = crystal frequency / 4
int32 Ticker;
int8 Seconds=0;

//optional:
// int8 Year=11, Month=1, Days=1, Hours=0, Minutes=0;  // 2011-01-01 00:00

////////////////////////////////////////////////////////////////////////////////
// Test whether a given year is a leap year.
// This optimized version only works for the period 1901 - 2099
////////////////////////////////////////////////////////////////////////////////
#define IS_LEAP(year) (year%4 == 0)


////////////////////////////////////////////////////////////////////////////////
//    Initialize RTC
////////////////////////////////////////////////////////////////////////////////
void Initialize_RTC(void)
{
  Ticker = TIMER1_FREQUENCY;                  // initialize clock counter to number of clocks per second
  setup_timer_1( T1_INTERNAL | T1_DIV_BY_1 ); // initialize 16-bit Timer1 to interrupt
                                              // exactly every 65536 clock cycles
                                              // (about 76 times per second)
  enable_interrupts( INT_TIMER1 );            // Start RTC
}

////////////////////////////////////////////////////////////////////////////////
//  -=Process Zero Drift Real Time Clock Information=-
//
// Most algorithms configure the timer to generate an interrupt every 100ms, and
// then count the number of interrupts. The problem in that approach is that most
// clock frequencies can't be divided by 256 and you don't get an exact 100ms.
// The small errors will add up to an error of several seconds a day.
//
// The algorithm presented here is exact in the long run because it doesn't
// count the number of interrupts but counts the number of clock cycles.
////////////////////////////////////////////////////////////////////////////////
#int_TIMER1                               
void TIMER1_isr()                         
{
  Ticker -= 65536;                        // Decrement ticker by clocks per interrupt
  if ( Ticker < 65536 )                   // If second has expired
  {  Ticker += TIMER1_FREQUENCY;          //   Increment ticker by clocks per second
     seconds++;                           //   Increment number of seconds
  }

  /* --- Optional part start ---
  if (Seconds == 60) {Minutes++; Seconds=0;
    if (Minutes == 60) {Hours++; Minutes=0;
      if (Hours == 24) {Days++; Hours=0;
        if (  (Days == 29 && Month==2 && !IS_LEAP(Year))                        // February in leap year
           || (Days == 30 && Month==2)                                          // February in normal years
           || (Days == 31 && (Month==4 || Month==6 || Month==9 || Month==11 ))  // All months with 30 days
           || (Days == 32)                                                      // All months with 31 days
           ) {Month++; Days=1;}
        if (Month == 13) {Year++; Month=1;}
  }}}
   --- Optional part end ---  */
}

////////////////////////////////////////////////////////////////////////////////
// Example program for using the RTC
////////////////////////////////////////////////////////////////////////////////
void main()
{
  int8 prev_second;
 
  Initialize_RTC();
  enable_interrupts( GLOBAL );

  // loop forever
  while(1)
  {
    // Toggle output every second 
    if (seconds != prev_second)
    {
      prev_second = seconds;
      output_toggle(PIN_A1);
    } 
  }
}


Edit 23 Mar 2006: Fixed the factor 4 error as indicated by Dorinm. Thanks.
Edit 13 Sep 2006: Fixed the leap year calculation (original version of IS_LEAP macro wasn't working at all).
Edit 18 Nov 2011: Fixed bug with day and month starting at zero instead of 1. Thanks ünloco.


Last edited by ckielstra on Thu Nov 17, 2011 6:58 pm; edited 7 times in total
dorinm



Joined: 07 Jan 2006
Posts: 38

View user's profile Send private message

PostPosted: Sun Mar 05, 2006 10:41 am     Reply with quote

just tried your code on a 20mhz 458... a second seems to take ~4 seconds ...am I doing something wrong or is there a bug in your code!?

edit: just found out what's wrong; according to microchip documentation (18f458), "When TMR1CS is clear, Timer1 increments every
instruction cycle." , so that in your code timer1 actually counts the XTALFREQ/4 (a instruction cycle) and not crystal cycles ....
...for personal use i set XTAL_FREQUENCY @ realfreq/4 (5.000.000) and the code work well.
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Tue Jun 20, 2006 7:32 am     Reply with quote

Thanks for the implementation, works perfectly on my PIC16.
jmann



Joined: 27 Dec 2004
Posts: 21

View user's profile Send private message

PostPosted: Sat Jun 24, 2006 10:01 pm     Reply with quote

That's cool!

The first assignment in my embedded system design class was just like this.
akokyaw



Joined: 11 Feb 2005
Posts: 24

View user's profile Send private message

PostPosted: Mon Aug 06, 2007 7:54 am     Reply with quote

smart calculation that can be compensate decimal part too.

Thank for your code,
pak
cybergm



Joined: 08 Aug 2007
Posts: 1

View user's profile Send private message

internal timer using WDT
PostPosted: Wed Aug 08, 2007 11:42 am     Reply with quote

hi,
this timer works great, but can anyone tell me if I can use a WDT to do the same operation cos I want my PIC to be in sleep mode
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

Re: internal timer using WDT
PostPosted: Wed Aug 08, 2007 3:15 pm     Reply with quote

cybergm wrote:
hi,
this timer works great, but can anyone tell me if I can use a WDT to do the same operation cos I want my PIC to be in sleep mode


No because the processors must be running in order to keep time.

I have been thinking about using a watch crystal on timer 1 to keep time and instead of going into sleep mode simply switching oscilators. This will drop power by about 2 orders of magnitude if your using a fast crystal. This would get power down to the levels that a coin cell can provide while allowing for higher proformance when more power is available.
jov_damo86



Joined: 29 Nov 2007
Posts: 9
Location: Sarrat, Ilocos Norte,Philippines

View user's profile Send private message

re:Timer based Real Time Clock (RTC)
PostPosted: Fri Dec 14, 2007 11:29 pm     Reply with quote

can i used that code in PIC16f877A with an external crystal of 20Mhz?

what is that 65536 in the code?

void TIMER1_isr()
{
Ticker -= 65536; // Decrement ticker by clocks per interrupt
if ( Ticker < 65536 ) // If second has expired
{ Ticker += TIMER1_FREQUENCY; // Increment ticker by clocks per second
seconds++; // Increment number of seconds
}


please explain further.. thank you!
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

Re: re:Timer based Real Time Clock (RTC)
PostPosted: Sun Dec 16, 2007 5:43 pm     Reply with quote

jov_damo86 wrote:
can i used that code in PIC16f877A with an external crystal of 20Mhz?

what is that 65536 in the code?

void TIMER1_isr()
{
Ticker -= 65536; // Decrement ticker by clocks per interrupt
if ( Ticker < 65536 ) // If second has expired
{ Ticker += TIMER1_FREQUENCY; // Increment ticker by clocks per second
seconds++; // Increment number of seconds
}


please explain further.. thank you!


In the first spot it is the number of times the timer will increment per interrupt. In the second spot is checks to see if "ticker" is greater than the number of timer increments per interrupt.

These values assume that the timer increments per instruction cycles is 1:1. Actual ratio could be set to other values and the number used (65536) would have to be changed to the appropriate value.

Timer is 16 bit
2^16=65536
ThomasC



Joined: 09 Oct 2007
Posts: 62

View user's profile Send private message

PostPosted: Tue Dec 18, 2007 11:17 am     Reply with quote

Can this function run in the background while another function is being run? Thanks!

The program runs well, but it seemed to be blinking 4 times a second so I used:

#define XTAL_FREQUENCY (2000000)

and now it seems to blink once every second. How can I be sure that it is blinking exactly once a second? I'm comparing it to the windows clock second hand, and it's probably me but it seems off.
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

PostPosted: Tue Dec 18, 2007 12:34 pm     Reply with quote

ThomasC wrote:
Can this function run in the background while another function is being run? Thanks!

The program runs well, but it seemed to be blinking 4 times a second so I used:

#define XTAL_FREQUENCY (2000000)

and now it seems to blink once every second. How can I be sure that it is blinking exactly once a second? I'm comparing it to the windows clock second hand, and it's probably me but it seems off.


If you can't do the math just let it run for 24 hours and see how much error you have. You would have to add a printF statement to show time.
ThomasC



Joined: 09 Oct 2007
Posts: 62

View user's profile Send private message

PostPosted: Tue Dec 18, 2007 1:48 pm     Reply with quote

I was wrong. Its rights on the money. Very Happy
ThomasC



Joined: 09 Oct 2007
Posts: 62

View user's profile Send private message

PostPosted: Fri Dec 21, 2007 3:54 pm     Reply with quote

Is there a way to simultaneously run this clock program so it records the ON time of the pic while you are doing other tasks? Or does it only run in succession? Thanks.
cnsnt



Joined: 29 Nov 2007
Posts: 6

View user's profile Send private message

PostPosted: Sun Dec 23, 2007 2:33 pm     Reply with quote

hi masters..

can I use these codes for pic16f628 with internal rc osc(4Mhz).I have to do it because I have a very small area.I can not use rtc hardware(ds1307 etc.)because of small area.

thanks
ThomasC



Joined: 09 Oct 2007
Posts: 62

View user's profile Send private message

PostPosted: Wed Dec 26, 2007 8:12 am     Reply with quote

It should work.

I answered my own question, I figured out that it does run in the background. Sorry for the redundant question.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Goto page 1, 2, 3, 4  Next
Page 1 of 4

 
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