The Perfect Clock: The code behind itA few days ago, I posted
the theoretical point of view of a perfect PIC clock. Today, I'll present you with a few code snippets. TWHL could really,
really use [code] or [ pre ] tags, and I don't mean just for this.
*Remember to define variable names - i.e seconds equ 0x25I'll start easy. This is the interrupt routine. There's nothing special in it.
;*******************
Interrupt:
call Clock_step
bcf INTCON, T0IF ;Clear interrupt flag to be able to return
retfie
The above code is called on each timed interrupt - every 8.192ms. Now you need to make something useful of that. The following is only a 122-interrupt second, just to show context.
;*******************
Clock_step:
incf tick
movfw tick
sublw D'122' ;Count 122 cycles, add 1 second
btfss STATUS,Z
goto Clock_end
clrf tick ;I have 1 second, reset int counter.
call Seconds_inc ;Increment seconds counter
movfw seconds
btfss STATUS,Z ;On seconds=0, increment minutes
goto Clock_end
call Minutes_inc ;Increment minutes counter
movfw minutes
btfss STATUS,Z ;On minutes=0, increment hours
goto Clock_end
call Hours_inc ;Increment hours counter
;--snip-- you get the idea.
Clock_end:
return
;*******************
Seconds_inc:
incf seconds
movfw seconds
sublw D'60'
btfsc STATUS,Z
clrf seconds ;Reset on 60 seconds
return
Minutes_inc:
;--snip-- again, you get the idea.
Remember, this is only the imprecise clock, only to show the concept. Now you'll need to adjust for 122 and 123 cycles and all that shizzle I mentioned in the other journal.
To do this, I have allocated a
tick_wait variable, to store whether my next cycle should be 122 or 123 interrupts long. I have also allocated
adj_s to count 14-second cycles, and
adj_c, to count 64 14-second cycles.
We must make a few changes to the code above.
;*******************
Clock_step:
incf tick
movfw tick
[b]subwf tick_wait,w[/b] ;Instead of 122, check against tick_wait
btfss STATUS,Z
goto Clock_end
clrf tick ;I have 1 second, reset int counter.
[b]call Tick_adj[/b] ;Check if next cycle counts 122 o 123
call Seconds_inc ;Increment seconds counter
;--snip-- same as previous sample.
Clock_end:
return
;*******************
Seconds_inc:
;--snip-- same as previous sample.
;*******************
; NEW CODE BELOW
;*******************
Tick_adj:
incf adj_s
movfw adj_s
sublw D'14'
btfss STATUS,Z ;If 14, I'm done with 14s cycle
goto tick_adj2 ;Otherwise, check if it's 13
clrf adj_s ;reset 14s cycle
movlw D'122'
movwf tick_wait
goto tick_adj_end
tick_adj2
movfw adj_s
sublw D'13'
btfss STATUS,Z ;If 13, it's adjust time
goto tick_adj_end ;if not 13 either, nothing to do
incf adj_c
movfw adj_c
sublw D'64'
btfsc STATUS,Z
goto tick_adj_end ;if this is the 64th adj cycle, ignore it
incf tick_wait ;14th second is next, lasts 123
movfw adj_c
sublw D'65' ;Check if 65
btfsc STATUS,Z
clrf adj_c ;If 65, reset count
tick_adj_end:
return
As you can see, the code has grown quite a bit. But here we have our (theoretically) perfect clock.
I had to revise this code before posting, as the code I've written has functions to decrement seconds, minutes, and hours (so there's no need to wrap around incrementing if you missed 1 minute) as well as date keeping and alarm. What I posted here is only a fraction of it, but feel free to use this code in any clocks you intend to make.
By the way, since I still haven't built it, I'm not sure how to store years. Therefore I risk being subject to either the year 2256 bug (returns to 2000) or the year 2999 (returns to 2000 too). It could also be in 9999, but it'd be wishful thinking to expect it not to break before that
I hope you have found this an educational experience
Edit: Wow, [ pre ] works! Although only sometimes. WTF?
Edit2: I just found out why. Dude, at least let it respect tabs.
Edit3: No, I was wrong. It appears to be random. TWHL BACKEND NO WORKIE!