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.
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
!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
=]
!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:
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-'
'-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-'