SoftRTC

SwordfishUser.SoftRTC History

Hide minor edits - Show changes to output

Changed lines 4-5 from:
It's common knowledge that PIC's have timers.  Timers' incremental counting is synchronized the internal PIC clock, which is the usual default operating state of timers at the Power On Reset (POR).  Further, the internal clock speed is a division by 4 of the external oscillator frequency (Fosc), sometimes shown as "Fosc/4" in the datasheet (Note that many PIC's also have an internal RC oscillator which can be used in lieu of the external oscillator, but for the sake of precision and accuracy, we are only going to recommend an external crystal oscillator for these examples).  Implementing PIC timers as a precision high-resolution real-time clock source and taking advantage of the microcontroller's other useful features without problems can be a challenge.  This article and following code examples intend to demonstrate 4 methods for creating a precision time base that can run concurrent with managing other tasks, such as outputing data to an LCD for a 24-hour real time clock.
to:
It's common knowledge that PIC's have timers.  Timers' incremental counting is synchronized with the internal PIC clock, which is the usual default operating state of timers at the Power On Reset (POR).  Further, the internal clock speed is a division by 4 of the external oscillator frequency (Fosc), sometimes shown as "Fosc/4" in the datasheet (Note that many PIC's also have an internal RC oscillator which can be used in lieu of the external oscillator, but for the sake of precision and accuracy, we are only going to recommend an external crystal oscillator for these examples).  Implementing PIC timers as a precision high-resolution real-time clock source and taking advantage of the microcontroller's other useful features without problems can be a challenge.  This article and following code examples intend to demonstrate 4 methods for creating a precision time base that can run concurrent with managing other tasks, such as outputing data to an LCD for a 24-hour real time clock.
Changed lines 4-5 from:
It's common knowledge that PIC's have timers.  These timers can be synchronized to the internal machine cycles of the PIC which is a division by 4 of the external oscillator speed (Many PIC's also have an internal RC oscillator which can be used in lieu of the external oscillator, but for the sake of precision and accuracy, we are only going to recommend an external crystal oscillator for these examples).  Implementing PIC timers as a precision real-time clock source and taking advantage of the microcontroller's other useful features without problems can be a challenge.  The code examples below will demonstrate 4 coding methods to create a precision time base that can run concurrent with managing other tasks, such as outputting data to an LCD for a 24-hour real time clock.
to:
It's common knowledge that PIC's have timers.  Timers' incremental counting is synchronized the internal PIC clock, which is the usual default operating state of timers at the Power On Reset (POR).  Further, the internal clock speed is a division by 4 of the external oscillator frequency (Fosc), sometimes shown as "Fosc/4" in the datasheet (Note that many PIC's also have an internal RC oscillator which can be used in lieu of the external oscillator, but for the sake of precision and accuracy, we are only going to recommend an external crystal oscillator for these examples).  Implementing PIC timers as a precision high-resolution real-time clock source and taking advantage of the microcontroller's other useful features without problems can be a challenge.  This article and following code examples intend to demonstrate 4 methods for creating a precision time base that can run concurrent with managing other tasks, such as outputing data to an LCD for a 24-hour real time clock.
Changed lines 4-5 from:
It's common knowledge that most PIC's have several timers.  These timers can be synchronized to the internal machine cycles of the PIC which is a division by 4 of the external oscillator speed (Many PIC's also have an internal RC oscillator which can be used in lieu of the external oscillator, but for the sake of precision and accuracy, we are only going to recommend an external crystal oscillator for these examples).  Implementing PIC timers as a precision real-time clock source and taking advantage of the microcontroller's other useful features without problems can be a challenge.  The code examples below will demonstrate 4 coding methods to create a precision time base that can run concurrent with managing other IO tasks, such as outputting data to an LCD for a 24-hour real time clock.
to:
It's common knowledge that PIC's have timers.  These timers can be synchronized to the internal machine cycles of the PIC which is a division by 4 of the external oscillator speed (Many PIC's also have an internal RC oscillator which can be used in lieu of the external oscillator, but for the sake of precision and accuracy, we are only going to recommend an external crystal oscillator for these examples).  Implementing PIC timers as a precision real-time clock source and taking advantage of the microcontroller's other useful features without problems can be a challenge.  The code examples below will demonstrate 4 coding methods to create a precision time base that can run concurrent with managing other tasks, such as outputting data to an LCD for a 24-hour real time clock.
Changed lines 4-6 from:
It's common knowledge that PIC's have timers which are synchronized to the internal clock of the PIC.  External oscillator speeds can range from 32KHz through 40MHz, which is the high limit of most PIC18's, which is further divided by 4 (Fosc/4) to produce the internal clock speed of the PIC.  Since PIC's are generally more versatile than just being a time base, it's helpful to understand how to take advantage of these it's other features without interfering with accurate time management.  The code examples below will demonstrate 4 coding methods to create a precision time base and also manage other IO tasks, such as outputting data to an LCD for a 24-hour real time
clock.
to:
It's common knowledge that most PIC's have several timers.  These timers can be synchronized to the internal machine cycles of the PIC which is a division by 4 of the external oscillator speed (Many PIC's also have an internal RC oscillator which can be used in lieu of the external oscillator, but for the sake of precision and accuracy, we are only going to recommend an external crystal oscillator for these examples).  Implementing PIC timers as a precision real-time clock source and taking advantage of the microcontroller's other useful features without problems can be a challenge.  The code examples below will demonstrate 4 coding methods to create a precision time base that can run concurrent with managing other IO tasks, such as outputting data to an LCD for a 24-hour real time clock.
Changed line 4 from:
It's common knowledge that PIC's have timers which are synchronized to the internal clock of the PIC.  External oscillator speeds can range from 32KHz through 40Mhz, which is the high limit of most PIC18's, which is further divided by 4 (Fosc/4) to produce the internal clock speed of the PIC.  Since PIC's are generally more versatile than just being a time base, it's helpful to understand how to take advantage of these it's other features without interfering with accurate time management.  The code examples below will demonstrate 4 coding methods to create a precision time base and also manage other IO tasks, such as outputting data to an LCD for a 24-hour real time
to:
It's common knowledge that PIC's have timers which are synchronized to the internal clock of the PIC.  External oscillator speeds can range from 32KHz through 40MHz, which is the high limit of most PIC18's, which is further divided by 4 (Fosc/4) to produce the internal clock speed of the PIC.  Since PIC's are generally more versatile than just being a time base, it's helpful to understand how to take advantage of these it's other features without interfering with accurate time management.  The code examples below will demonstrate 4 coding methods to create a precision time base and also manage other IO tasks, such as outputting data to an LCD for a 24-hour real time
Changed lines 140-141 from:
!FREE RUNNING TIMER USING ZERO-SUM METHOD & TIMER0
to:

!FREE-RUN-TIMER USING ZERO-SUM METHOD & TIMER0
Added lines 250-466:
=]


!FREE-RUN-TIMER USING TIMER2 & PR2 MATCH/RESET METHOD

=code [=
{
****************************************************************
*  Name    : Soft_RTC_PR2_FreeRunTimer.BAS                    *
*  Author  : Warren Schroeder alias "xor"                      *
*  Notice  : Copyright (c) 2007 Warren Schroeder              *
*          : All Rights Reserved                              *
*  Date    : 5/23/2007                                        *
*  Version : 1.0                                              *
*  Notes  : Real Time Clock - PR2 Free Running Timer          *
*            Precision 24H Time Clock Example on LCD          *
*            18F452 @ 8MHz                                    *
*            Timer2, PR2, and No Prescaler                    *
*      Implements PR2 match reset of Free Running Timer2      *
*                                                              *                                               
****************************************************************
}

Device = 18F452
Clock = 8

#option LCD_RS = PORTB.2
#option LCD_EN = PORTB.3
#option LCD_DATA = PORTB.4

Include "lcd.bas"
Include "convert.bas"

{
  For One Second Update:
 
  8MHz Fosc = 2MHz internal clock = 0.5us per cycle (timer count)
  Use 8-bit Timer2, No Prescaler
  Set PR2 = 250; Timer2 resets on match every 250 counts = 125us
  Each Timer2 reset requires 1 cycle compensation... so set PR2 = 249
  8000 interrupts x 125us each = 1 second
}

Dim Int_Counter As Word             
Dim update As Boolean
Dim secs,mins,hrs As Byte

interrupt RTC()
  Dec(Int_Counter)
  If Int_Counter = 0 Then
      Int_Counter = 8000                  ' each interrupt = 125us x 8000 int's = 1 second
      update = true                      ' update LCD output
  End If
  PIR1.1 = 0                            ' clear interrupt flag 
End interrupt

Sub Clock24()
 Dim clk As String
    Inc(secs)
    If secs = 60 Then                    ' check each tally for rollover
      secs = 0
      Inc(mins)
      If mins = 60 Then
          mins = 0
          Inc(hrs)
          If hrs = 24 Then
            hrs = 0
          End If
      End If
    End If
    clk = DecToStr(hrs,2)                ' output to LCD
    LCD.WriteAt(2,5,clk)
    clk = DecToStr(mins,2)
    LCD.WriteAt(2,8,clk)
    clk = DecToStr(secs,2)
    LCD.WriteAt(2,11,clk)
    update = false
End Sub

Sub Initialize()
  ADCON1 = 15
  secs = 0
  mins = 0
  hrs = 0
  Int_Counter = 8000
  update = false
  LCD.Command(130)
  LCD.Write("24-HOUR CLOCK")
  LCD.Command(196)
  LCD.Write("00:00:00")     
  INTCON = 192                          ' enable GIE & PEIE
  T2CON = 0                              ' no prescaler or postscaler: timer2 OFF
  TMR2 = 0                              ' clear TMR2
  PR2 = 249                              ' set match value
  PIE1.1 = 1                            ' enable interrupt
  PIR1.1 = 0                            ' clear interrupt flag
  T2CON.2 = 1                            ' Timer2 ON
  Enable(RTC)                            ' enable jump to RTC ISR
End Sub

  Initialize

  While 1=1
      If update = true Then
        Clock24                          ' update 24H Clock output
      End If
  Wend
=]


!FREE-RUN-TIMER USING TIMER1 SPECIAL EVENT TRIGGER & CCP1 MATCH/RESET METHOD

=code [=
{
****************************************************************
*  Name    : Soft_RTC_CCP1_FreeRunTimer.BAS                    *
*  Author  : Warren Schroeder alias "xor"                      *
*  Notice  : Copyright (c) 2007 Warren Schroeder              *
*          : All Rights Reserved                              *
*  Date    : 5/23/2007                                        *
*  Version : 1.0                                              *
*  Notes  : Real Time Clock - PR2 Free Running Timer          *
*            Precision 24H Time Clock Example on LCD          *
*            18F452 @ 8MHz                                    *
*            Timer1, CCPR1, and No Prescaler                  *
* Implements Special Event Trigger when Timer1 matches CCPR1  *
*                                                              *                                               
****************************************************************
}

Device = 18F452
Clock = 8

#option LCD_RS = PORTB.2
#option LCD_EN = PORTB.3
#option LCD_DATA = PORTB.4

Include "lcd.bas"
Include "convert.bas"

{
  For One Second Update:
 
  8MHz Fosc = 2MHz internal clock = 0.5us per cycle (timer count)
  Use 16-bit Timer1, No Prescaler
  Set CCPR1 = 50000; Timer1 resets on match every 50000 counts = 25000us
  Each Timer1 reset requires 1 cycle compensation... so set CCPR1 = 49999
  40 interrupts x 25000us each = 1 second
}

Dim C1 As Word Absolute $0FBE            ' CCPR1L + CCPR1H
Dim Int_Counter As Byte             
Dim update As Boolean
Dim secs,mins,hrs As Byte

interrupt RTC()
  Dec(Int_Counter)
  If Int_Counter = 0 Then           
      Int_Counter = 40                    ' each interrupt = 25000us x 40 int's = 1 second
      update = true                      ' update LCD output
  End If
  PIR1.2 = 0                            ' clear CCP1 interrupt flag 
End interrupt

Sub Clock24()
 Dim clk As String
    Inc(secs)
    If secs = 60 Then                    ' check each tally for rollover
      secs = 0
      Inc(mins)
      If mins = 60 Then
          mins = 0
          Inc(hrs)
          If hrs = 24 Then
            hrs = 0
          End If
      End If
    End If
    clk = DecToStr(hrs,2)                ' output to LCD
    LCD.WriteAt(2,5,clk)
    clk = DecToStr(mins,2)
    LCD.WriteAt(2,8,clk)
    clk = DecToStr(secs,2)
    LCD.WriteAt(2,11,clk)
    update = false
End Sub

Sub Initialize()
  ADCON1 = 15
  secs = 0
  mins = 0
  hrs = 0
  Int_Counter = 40
  update = false
  LCD.Command(130)
  LCD.Write("24-HOUR CLOCK")
  LCD.Command(196)
  LCD.Write("00:00:00")     
  INTCON = 192                          ' enable GIE & PEIE
  T1CON = 0                              ' no prescaler timer OFF
  TMR1H = 0                              ' clear TMR1
  TMR1L = 0
  CCP1CON = 11                          ' enable special trigger event                   
  C1 = 49999                            ' set match value
  PIE1.2 = 1                            ' enable CCP1 interrupt
  PIR1.2 = 0                            ' clear CCP1 interrupt flag
  T1CON.0 = 1                            ' Timer1 ON
  Enable(RTC)                            ' enable jump to RTC ISR
End Sub

  Initialize

  While 1=1
      If update = true Then
        Clock24                          ' update 24H Clock output
      End If
  Wend
Changed lines 26-249 from:
to:
-----

!TIMER STOP METHOD USING TIMER1

=code [=
{
****************************************************************
*  Name    : Soft_RTC_TimerStop.BAS                            *
*  Author  : Warren Schroeder alias "xor"                      *
*  Notice  : Copyright (c) 2007 Warren Schroeder              *
*          : All Rights Reserved                              *
*  Date    : 5/23/2007                                        *
*  Version : 1.0                                              *
*  Notes  : Real Time Clock - Timer Stop Method              *
*            Precision 24H Time Clock Example on LCD          *
*            18F452 @ 8MHz                                    *
*            Uses Timer1 and No Prescaler                      *
*          :                                                  *
****************************************************************
}

Device = 18F452
Clock = 8

#option LCD_RS = PORTB.2
#option LCD_EN = PORTB.3
#option LCD_DATA = PORTB.4

Include "lcd.bas"
Include "convert.bas"

{
  For One Second Update:
 
  8MHz Fosc = 2MHz internal clock = 0.5us per cycle (timer count)
  Use 16-bit Timer1; No Prescaler
  50000 counts = 50000 x 0.5us = 25000us
  40 x 25000us = 1000000us = 1 second
}
 
Const T1Period As Word = 65536-50000+6    ' 25000us interrupt cycle + 6 cycles for TIMER1 stoppage
Const Int_Total As Byte = 40              ' 40 x 25000us = 1 second 
Dim T1 As Word Absolute $0FCE            ' TMR1L + TMR1H
Dim T1IE As PIE1.0
Dim T1IF As PIR1.0
Dim T1ON As T1CON.0
Dim update As Boolean
Dim int_counter As Byte
Dim secs,mins,hrs As Byte

interrupt RTC()
  T1ON = 0                              ' stop timer
  T1 = T1 + T1Period                    ' reload timer + include cycles after jump to ISR
  T1ON = 1                              ' restart timer
  Dec(int_counter)                       
  If int_counter = 0 Then
      int_counter = Int_Total            ' count 40 interrupts @ 25000us = 1 second
      update = true                      ' update LCD clock
  End If
  T1IF = 0                              ' clear int flag
End interrupt

Sub Clock24()
 Dim clk As String
    Inc(secs)
    If secs = 60 Then                    ' check each tally for rollover
      secs = 0
      Inc(mins)
      If mins = 60 Then
          mins = 0
          Inc(hrs)
          If hrs = 24 Then
            hrs = 0
          End If
      End If
    End If
    clk = DecToStr(hrs,2)                ' output to LCD
    LCD.WriteAt(2,5,clk)
    clk = DecToStr(mins,2)
    LCD.WriteAt(2,8,clk)
    clk = DecToStr(secs,2)
    LCD.WriteAt(2,11,clk)
    update = false
End Sub

Sub Initialize()
  ADCON1 = 15
  secs = 0
  mins = 0
  hrs = 0
  int_counter = Int_Total 
  update = false
  LCD.Command(130)
  LCD.Write("24-HOUR CLOCK")
  LCD.Command(196)
  LCD.Write("00:00:00")     
  INTCON = 192                          ' enable GIE & PEIE
  T1CON = 0                              ' no prescaler and Timer1 is Off
  T1 = 65536-50000                      ' load Timer1
  T1IE = 1                              ' enable Timer1 Interrupt
  T1IF = 0                              ' clear Timer1 Interrupt Flag
  T1ON = 1                              ' start Timer1
  Enable(RTC)                            ' enable jump to RTC ISR
End Sub

  Initialize

  While 1=1
      If update = true Then
        Clock24                          ' update 24H Clock output
      End If
  Wend
=]

!FREE RUNNING TIMER USING ZERO-SUM METHOD & TIMER0

=code [=
{
****************************************************************
*  Name    : Soft_RTC_FreeRunTimer.BAS                        *
*  Author  : Warren Schroeder alias "xor"                      *
*  Notice  : Copyright (c) 2007 Warren Schroeder              *
*          : All Rights Reserved                              *
*  Date    : 5/23/2007                                        *
*  Version : 1.0                                              *
*  Notes  : Real Time Clock - Free Running Timer              *
*            Precision 24H Time Clock Example on LCD          *
*            18F452 @ 8MHz                                    *
*            Timer0 and No Prescaler                          *
*  Program implements Zero-Sum/Zero Cumulative Error Method    *
*  by Roman Black .. http://www.romanblack.com/one_sec.htm    *:                                                 
****************************************************************
}

Device = 18F452
Clock = 8

#option LCD_RS = PORTB.2
#option LCD_EN = PORTB.3
#option LCD_DATA = PORTB.4

Include "lcd.bas"
Include "convert.bas"

{
  For One Second Update:
 
  8MHz Fosc = 2MHz internal clock = 0.5us per cycle (timer count)
  Use 8-bit Timer0; No Prescaler
  2000000 counts = 1 Second
  Timer0 reload requires 2 cycle compensation = 2000000-2
}
 
Const OneSecond As LongWord = 2000000-2  ' 1 Second total clock cycles - 2 for timer relaod
Dim Cyc_Counter As LongWord Absolute $30  ' Timer0 cycle counter
Dim T0Load As Byte Absolute $30          ' Timer0 reload value
Dim Countdown As Word Absolute $31        ' # of 8-bit cycles
Dim update As Boolean
Dim secs,mins,hrs As Byte

interrupt RTC()
  Dec(Countdown)
  If Countdown = 0 Then
      Cyc_Counter = OneSecond            ' reload timer
      TMR0L = TMR0L + T0Load              ' include additional TMR0 counts
      If STATUS.0 = 0 Then
        Inc(Countdown)                  ' if no carry increment "countdown" counter once
      End If
      update = true                      ' flag to update clock output
  End If
  INTCON.2 = 0                          ' clear interrupt flag 
End interrupt

Sub Clock24()
 Dim clk As String
    Inc(secs)
    If secs = 60 Then                    ' check each tally for rollover
      secs = 0
      Inc(mins)
      If mins = 60 Then
          mins = 0
          Inc(hrs)
          If hrs = 24 Then
            hrs = 0
          End If
      End If
    End If
    clk = DecToStr(hrs,2)                ' output to LCD
    LCD.WriteAt(2,5,clk)
    clk = DecToStr(mins,2)
    LCD.WriteAt(2,8,clk)
    clk = DecToStr(secs,2)
    LCD.WriteAt(2,11,clk)
    update = false
End Sub

Sub Initialize()
  ADCON1 = 15
  secs = 0
  mins = 0
  hrs = 0
  Cyc_Counter = OneSecond
  update = false
  LCD.Command(130)
  LCD.Write("24-HOUR CLOCK")
  LCD.Command(196)
  LCD.Write("00:00:00")     
  INTCON = 192                          ' enable GIE & PEIE
  T0CON = 72                            ' 8-bit; no prescaler; Timer0 off
  TMR0L = 0                              ' clear timer0
  INTCON.5 = 1                          ' interrupt enabled
  INTCON.2 = 0                          ' interrupt flag cleared
  T0CON.7 = 1                            ' start Timer0
  Enable(RTC)                            ' enable jump to RTC ISR
End Sub

  Initialize

  While 1=1
      If update = true Then
        Clock24                          ' update 24H Clock output
      End If
  Wend
=]
Changed line 4 from:
'-It's common knowledge that PIC's have timers which are synchronized to the internal clock of the PIC.  External oscillator speeds can range from 32KHz through 40Mhz, which is the high limit of most PIC18's, which is further divided by 4 (Fosc/4) to produce the internal clock speed of the PIC.  Since PIC's are generally more versatile than just being a time base, it's helpful to understand how to take advantage of these it's other features without interfering with accurate time management.  The code examples below will demonstrate 4 coding methods to create a precision time base and also manage other IO tasks, such as outputting data to an LCD for a 24-hour real time
to:
It's common knowledge that PIC's have timers which are synchronized to the internal clock of the PIC.  External oscillator speeds can range from 32KHz through 40Mhz, which is the high limit of most PIC18's, which is further divided by 4 (Fosc/4) to produce the internal clock speed of the PIC.  Since PIC's are generally more versatile than just being a time base, it's helpful to understand how to take advantage of these it's other features without interfering with accurate time management.  The code examples below will demonstrate 4 coding methods to create a precision time base and also manage other IO tasks, such as outputting data to an LCD for a 24-hour real time
Changed lines 25-26 from:
Warren Schroeder 5-07-'
to:
Warren Schroeder May-2007
Added lines 1-25:
!! Soft RTC -  4 Methods For A Precision PIC Time Clock


'-It's common knowledge that PIC's have timers which are synchronized to the internal clock of the PIC.  External oscillator speeds can range from 32KHz through 40Mhz, which is the high limit of most PIC18's, which is further divided by 4 (Fosc/4) to produce the internal clock speed of the PIC.  Since PIC's are generally more versatile than just being a time base, it's helpful to understand how to take advantage of these it's other features without interfering with accurate time management.  The code examples below will demonstrate 4 coding methods to create a precision time base and also manage other IO tasks, such as outputting data to an LCD for a 24-hour real time
clock.

PIC timers have several features which are useful for different applications, and for the sake of brevity this article is only going to consider timers which are synchronized with the internal PIC clock.  PIC timers increment, that is, they count up, and how far they increment or count is determined by their size.  An 8-bit timer can count from 0 to 255 for a total of 256 counts.  A timer that is 16-bits (2 bytes) can count from 0 to 65535 for a total of 65536 counts.  Why 256 counts for 0 to 255?  Because the timer rolls over (overflows) to 0, one count past 255, and continues incrementing.  The same applies to the 16-bit timer.  A count of 256 or 65536 results in a timer value of 0 because of this rollover.  The values of 256 and 65536 will become important later when discussing loading values into the
timers.

Timer overflow is the foundation of a precision time clock because of a potential "side-effect" when it occurs. Overflow sets a bit in a special register related to the timer called the Timer Interrupt Flag.  This flag, or bit, can be cleared through software, but it will always set again when the timer count overflows to 0.  Although this flag is called the Interrupt Flag, and always sets on overflow, no interrupt events can occur unless the Timer Interrupt Enable bit is set, or enabled.  When enabled, the PIC is forced to jump to the Interrupt Service Routine (ISR) at the overflow moment.  So making sure that the timer's Interrupt Enable bit is set, and Interrupt Flag bit is cleared, will ensure that real time clock registers are updated at the same exact interval determined by the timer's count.

Since timers increment, preloading a timer requires deducting the desired counts from the overflow point, or 0.  For example, a PIC which has a 4MHz external oscillator, has a 1MHz internal clock (Fosc/4) which is equivalent to a 1 microsecond timer clock.  Thus, the timer will increment once every microsecond.  Using an 8-bit timer, the value of 250, or 250us, makes a nice time base to work with.  If the value of 250 is loaded into the timer, 6us later the timer would overflow since the count started at 250 and progressed to 256, or 0.  To load the timer correctly, deduct 250 from the rollover point.  As 0 minus 256 will create a negative value, use 256 instead, 256 - 250 = 6.  6 is the correct timer load value for a 250us interrupt cycle.  The same rule follows for a 16-bit timer, except use 65536 as the rollover value.

Those are some timer basics.  Timers also have prescaler and postscaler features which will not be considered.  If implemented these features can introduce timing errors and affect the precision of the time base.  Timer prescalers and postscalers must be set to 1:1 and synchronized to count with each PIC machine cycle. 

Easy.  Not yet.  There is more to consider.  Recall that when a timer has overflowed its count is at 0 when it triggers a jump to the ISR, and then continues to count.  There are a number of machine cycles required just for the interrupt vectoring, and then more for the saving of important registers (context saving) so it's possible to resume exactly where the code left off when it was interrupted.  It's not unusal for a dozen or more machine cycles, and timer counts, to pass before any attempt is made to manage and reload the timer with the desired time base.  Reloading and restarting the timer in itself can require a few more cycles.  If a programmer has access to the assembly code at
the beginning of the ISR he can make an accurate assessment of how many cycles have passed and compensate by deducting those used cycles from his timer reload amount.  When programming in a high level language, such as Basic, the programmer may prefer not to be bothered with cycle counting and would need another method.

ISR timer compensation can be managed in a more clever way than cycle counting.  Simply add the present value in the timer to the desired time base reload value.  Since timers increment, adding to its value pushes it closer to the overflow point and is essentially deducting time from the timer interrupt cycle.  Adding the timer's present count to the reload value when inside the ISR automatcally results in timer compensation for the cycles the timer continued to run after the interrupt.  A point to note, there is further compensation of a cycle or two which must be considered with the timer reload.  This is commented in the code examples.

The 4 coding methods below show how ISR compensation is not a problem using SF Basic for creating a precision interrupt-driven real time clock using various timers and features found in PIC's.  The first example uses a timer stop method, and the other three let the timers run freely.  The second example, in paticular, is notable because it also implements the Zero-Sum/Zero Cumulative Error method of reloading the timer as demonstrated by Roman Black on his webpage, [[http://www.romanblack.com/one_sec.htm]].  The last 2 examples use interrupt features when a timer count matches the value in another register, namely, Timer2 when it matches the PR2 register, and when Timer1 and the CCPR1 register match.  This compare interrupt feature does not require reloading the timers since the timers are automatically reset and will continue to interrupt on the same time interval as long as the respective Interrupt Flag continues to be cleared.

Each of the examples demonstrate a 24-Hour Time Clock using a character LCD.

Warren Schroeder 5-07-'