Working clock example using 32K watch crystal
Looked all over trying to find an example with a second crystal connected to the TIMER1 overflow. This example uses the earlier 18F452 version of the Olimex PIC-WEB board. Ran the clock for a day without gaining or loosing a second! Lots of places where I was not sure what to do. Comments are welcome.
Regards
Tim C
Code:
' Name : TMR1CLK.pbp
' Target PIC : PIC18F452 or similar 18F types
' Hardware : PIC-WEB ver A board with added LCD
' Oscillator : 10MHz crystal. You May have to modify default 18F452 fuses for > 4Mhz
' Resolution : Expect to get +- 5sec/day or better
' Description : PicBasic Pro program using external 32K watch xtal and Timer1
' interrupt for a real-time clock.
' Origional ver from: http://melabs.com/resources/samples/18f/tmr1clk18.htm
'
DEFINE OSC 10 ' We're using a 10MHz oscillator
DEFINE LOADER_USED 1 ' Boot-Loader is being used
Define INTHAND myint ' Define interrupt handler
Symbol LED_0 = PORTD.5
symbol BUTTON_0 = PORTB.0
wsave VAR BYTE bankA system ' Saves W
ssave VAR BYTE bankA system ' Saves STATUS
seconds VAR BYTE bankA ' variables within myint must be in bank 0.
minutes VAR Byte ' Elapsed minutes
hours var byte
' LCD config
Define LCD_DREG PORTD
Define LCD_DBIT 0
Define LCD_RSREG PORTE
Define LCD_RSBIT 0
Define LCD_EREG PORTE
Define LCD_EBIT 1
ADCON1 = 7 ' Set PORTA and PORTE for digital operation
Low PORTE.2 ' Enable the LCD
Pause 150 ' Pause to allow LCD to initialize
LCDOut $fe,1 ' Clear LCD
hours = 2
minutes = 23 ' Pre Set time here then add seconds to clock using button
seconds = 0
T1CON.7=0 ' 8 Bit r/w (16 bit seems to cause problems)
T1CON.5=0 ' Part 1 of 1:1 prescale
T1CON.4=0 ' Part 2 pf 1:1 prescale
T1CON.3=1 ' turn on the low freq clock osc
T1CON.2=1 ' Do not Sync low Freq clock with main clock
T1CON.1=1 ' use 32Khz xtal as the Timer1 source
T1CON.0=1 ' enable Timer1
PIE1 = $01 ' Enable TMR1 overflow interrupt
INTCON = $C0 ' Finally Enable global interrupt and peripheral interrupts
GoTo mainloop ' jump over the interrupt handler and sub
' Assembly language interrupt handler
Asm
myint
; Save the state of critical registers
movwf wsave ; Save W
swapf STATUS, W ; Swap STATUS to W (swap avoids changing STATUS)
clrf STATUS ; Clear STATUS
movwf ssave ; Save swapped STATUS
; Set the high register of Timer1 to cause an interrupt every
; 32768 counts (2^15).
movlw 080h ; Prepare to set TMR1 high register
movwf TMR1H ; Set TMR1H to 80h
incf _seconds,F ; INCREMENT seconds COUNT
bcf PIR1, 0 ; Clear interrupt flag
swapf ssave, W ; Retrieve the swapped STATUS value (swap to avoid changing STATUS)
movwf STATUS ; Restore it to STATUS
swapf wsave, F ; Swap the stored W value
swapf wsave, W ; Restore it to W (swap to avoid changing STATUS)
retfie ; Return from interrupt
EndAsm
' Subroutine to update the time variables
get_time:
if seconds > 59 then
seconds = seconds - 60 ' better then making seconds=0
minutes = minutes + 1
if minutes > 59 then
minutes = 0
hours = hours + 1
if hours > 12 then ' simple 12 hour clock format
hours = 1
endif
endif
endif
Return
mainloop:
GoSub get_time ' Update minutes and seconds
TOGGLE LED_0
LCDOut $fe,2,"Time: ",DEC hours, ":", DEC2 minutes, ":", DEC2 seconds, " "
Pause 300 ' Pause to see LED blink. Also help with debounce
if button_0 = 0 then
LCDOut $fe,$C0,"+1s "
seconds = seconds + 1
else
LCDOut $fe,$C0," "
endif
GoTo mainloop ' Repeat main loop
End
Naw only just point the way
INCLUDE "DT_INTS-18.pbp" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.pbp" ; Include if using PBP interrupts"
Re: Working clock example using 32K watch crystal
I was playing with TimC RTC code, and I found 1 problem...
If the interrupt occurs between these lines
Code:
GoSub get_time ' Update minutes and seconds
TOGGLE LED_0
LCDOut $fe,2,"Time: ",DEC hours, ":", DEC2 minutes, ":", DEC2 seconds, " "
There is a chance to show 60 seconds.
It happened to me, so I then wondered what was going on...
Solution:
Code:
seconds VAR BYTE bankA ' variables within myint must be in bank 0.
minutes VAR Byte bankA ' Elapsed minutes
hours var byte bankA
:
:
:
@myint ; create myint label
TMR1H.7=1
seconds = seconds+1 ' Increment second
if seconds > 59 then
seconds = seconds - 60 ' better then making seconds=0
minutes = minutes + 1
if minutes > 59 then
minutes = 0
hours = hours + 1
if hours > 12 then hours = 1 ' simple 12 hour clock format
endif
endif
PIR1.0=0 ' Clear TMR1 int flag
@ retfie FAST
And remove get_time procedure
Re: Working clock example using 32K watch crystal
I'm trying to add the calendar.
Does anyone have an idea how to make a calculation of leap year.
I tried this
If day>30+month.0 or (Month=2 and day>28 and year//4<>0) or (Month=2 and day>29 and year//4=0)then
month=month+1
but the code is 300b larger then this
If day>30+month.0 or (Month=2 and day>28)then
month=month+1
Is there a more efficient way?
Re: Working clock example using 32K watch crystal
How about using 3 If-Then's insead of one with 3 OR's?
Ioannis
Re: Working clock example using 32K watch crystal
I spent all night trying to find the best way ... I think this is
Code:
If month=2 then
If year//4<>0 then
DMonth=29
else
DMonth=28
endif
else
Dmonth=30+month.0
endif
If day>Dmonth then
@ CLRF _Day
@ INCF _Month,F
If month>12 then
And everywhere there is any = 0, I replaced the @ clrf, +1 replaced with @ incf.
The end result was the RTC which consumes about 2uA and code size about 500B. :o
Re: Working clock example using 32K watch crystal
I think you have to change the <>0 to =0 when you test for the modulo 4.
A better solution to cover more years (you code will not cover year 2100) is to use mod 400, mod 100 and mod 4 to test for leap year (mod 100 is NOT leap year, while 400 and 4 ARE leap years).
Of course we may not live in year 2100, but just in case... :)
Now about the @ commands, just be sure you are on page 0. Else you have to check the page bits. Or put this subroutine on top of your code.
Ioannis
Re: Working clock example using 32K watch crystal
Thanks for that... It was just typo... 0-99 year is fine for this aplication.
On the top of ISR I have BSR=0, and isr routine is on top of my programm.
Re: Working clock example using 32K watch crystal
If I may suggest, make the minutes and hours update in your main loop and not in Interrupt. A temp variable wll be needed for this.
Ioannis
Re: Working clock example using 32K watch crystal
If pic loses power, it goes to sleep. And everything is shut off, only tmr1 is on. So i need that in ISR. Is there better way?