title "3x5dcf_high_side.asm"
; I've never seen a clock with 3x5 displays. This should put that right. HH:MM:SS format only. This version drives the rows from GND via MOSFETs and the columns from high side using HEF4094 shift registers.
;
; 200725 v0.1 Copied from original low side shift register LED drive
; 200730 v0.2 Fixed missing pulses (DCFLOSS) from crap Elektor ESP01 code (March 2018)
; 200731 v0.3 Copy decoded time only when parcheck passed twice to avoid zeroes at DCFLOSS but immediately after successful decode at poweron
; 200731 v1.0 Release
; 200801 v1.1 Still issues with DCFOK after DCFLOSS event (skip 1 minute)
;
; GPL Copyleft 2019, 2020 pic@polonai.se
LIST P=16F628A, F=INHX8M
#include <p16f628a.inc>
__CONFIG _INTRC_OSC_NOCLKOUT & _WDT_OFF & _LVP_OFF & _CP_OFF & _BODEN_OFF
; Equates
RESET_V EQU 0x00 ; Address of RESET Vector
OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4 MHz
; Registers
TEMP EQU 0x20 ; TEMP register
THOURS EQU 0x21 ; 10 Hours value
HOURS EQU 0x22 ; Hours value
TMINS EQU 0x23 ; 10 Minutes value
MINS EQU 0x24 ; Minutes value
TSECS EQU 0x25 ; 10 Seconds value
HSECS EQU 0x26 ; Half Seconds value (because of TIMER1)
DIGIT1 EQU 0x31 ; 10 hr digit
DIGIT2 EQU 0x32 ; hour digit
DIGIT3 EQU 0x33 ; 10 min digit
DIGIT4 EQU 0x34 ; minute digit
DIGIT5 EQU 0x35 ; 10 sec digit
DIGIT6 EQU 0x36 ; seconds digit
DCFHIGH EQU 0x37 ; Counter for the length of received DCF high pulses, used for decoding
DCFLOW EQU 0x38 ; Counter for the length of received DCF space between pulses, used for decoding and syncing
MINBUF EQU 0x39 ; Received DCF Data Minutes Buffer
HRBUF EQU 0x3A ; Received DCF Data Hours Buffer
DCFSEC EQU 0x3D ; Counter for DCF data
FLAGS EQU 0x7F ; Various flags
#define ROW0 PORTB,0 ; Row 0 (low side switching)
#define ROW1 PORTB,1 ; Row 1
#define ROW2 PORTB,2 ; Row 2
#define ROW3 PORTB,3 ; Row 3
#define ROW4 PORTB,4 ; Row 4
#define DCFIN PORTA,4 ; Input DCF signal, positive (mark = HIGH)
#define SDI PORTA,6 ; Serial Data line of HEF4094
#define CLK PORTA,7 ; Clock for HEF4094 (high pulse)
#define STR PORTA,0 ; Strobe for HEF4094 (high pulse)
#define OE PORTA,1 ; Output Enable for HEF4094 (active high)
#define LED PORTA,2 ; Blue LED for DCF input activity
#define TETS PORTA,3 ; Yellow LED for debugging
#define FIRSTDEC FLAGS,1 ; First successful decode after poweron
#define DCFOK FLAGS,2 ; when both hour and minute even parities are OK, needs good signal, colon solid otherwise flashing/alternating
#define DCFBAD FLAGS,3 ; Clock free running after having had valid time (parity fail, loss of signal), colon alternating (prio over DCFOK)
#define P1 FLAGS,4 ; Calculated parity over received minute
#define P2 FLAGS,5 ; Calculated parity over received hour
#define RXD FLAGS,6 ; Received DCF data bit
org 0x00
GOTO START
org 0x04
; Interrupt handler
; NOTE: Everything of this program runs inside an interrupt handler so it's not necesssary
; to back up any critical registers (WREG, STATUS) when entering or exiting the handler.
BTFSC INTCON,TMR0IF ; TMR0 interrupt
GOTO DCFHandler
BTFSC PIR1,TMR1IF ; Check to see if the interrupt was caused by a TIMER1 rollover Overflow)
GOTO Timehandler ; half second timer
BTFSC PIR1,TMR2IF ; Check to see if the interrupt was caused by a TIMER2 rollover (overflow)
GOTO Multiplex ; 6 ms multiplex time for LED display
RETFIE ; If none of the above is true, then just leave the interrupt handler
DCFHandler
BCF INTCON,TMR0IF ; Clear interrupt source
MOVLW 0x44 ; Check DCFIN every 50 ms-ish (too many interrupts and too low internal clock of 4 MHz)
MOVWF TMR0
BTFSC DCFIN ; Input high?
GOTO DCF1 ; Yes
BTFSC LED ; LED still on?
GOTO FIRSTLOW ; Yes
INCF DCFLOW,F
MOVLW 0x2A ; Test for 42 pulses
SUBWF DCFLOW,W ; if true, C=1, loss of signal
BTFSC STATUS,C
GOTO DCFLOSS
RETFIE
DCFLOSS
MOVLW 0x29
MOVWF DCFLOW
BTFSC FIRSTDEC ; Skip setting DCFBAD if firstdecode hasn't happened yet
BSF DCFBAD
BCF DCFOK
RETFIE
FIRSTLOW ; Test for one or zero DCF bit
BCF LED ; Switch off LED
BCF RXD
CLRF DCFLOW ; Destroy value in counter
MOVLW 0x00 ; Decode received bit
SUBWF DCFHIGH,W
BTFSC STATUS,Z ; One sample?
GOTO SETZERO ; Yes
MOVLW 0x01
SUBWF DCFHIGH,W
BTFSC STATUS,Z ; Two samples?
GOTO SETZERO ; Yes
MOVLW 0x02
SUBWF DCFHIGH,W
BTFSC STATUS,Z ; Three samples?
GOTO SETZERO ; Yes
MOVLW 0x03
SUBWF DCFHIGH,W
BTFSC STATUS,Z ; Four samples?
GOTO SETONE ; Yes
MOVLW 0x04
SUBWF DCFHIGH,W
BTFSC STATUS,Z ; FIVE samples? (just in case)
GOTO SETONE ; Yes
BCF DCFOK ; HIGH pulse too long
RETFIE
SETONE
BSF RXD
SETZERO ; Rather remain zero
INCF DCFSEC,F
MOVLW 0x16
SUBWF DCFSEC,W
BTFSS STATUS,C ; At minutes yet?
RETFIE ; No
MOVLW 0x1E
SUBWF DCFSEC,W
BTFSC STATUS,C ; At hours yet?
GOTO SHIFTHOUR ; Yes
BCF STATUS,C
BTFSC RXD
BSF STATUS,C
RRF MINBUF,F ; Move received bit into minutes buffer
RETFIE
SHIFTHOUR
MOVLW 0x25
SUBWF DCFSEC,W
BTFSC STATUS,C ; Done hours?
RETFIE ; Yes
BCF STATUS,C
BTFSC RXD
BSF STATUS,C
RRF HRBUF,F ; Move received bit into hours buffer
RETFIE
DCF1
BTFSS LED ; LED on?
GOTO FIRSTHIGH ; No
INCF DCFHIGH,F
RETFIE ; Not testing anything else, already done at FIRSTLOW
FIRSTHIGH
BSF LED
CLRF DCFHIGH ; Clear HIGH pulse duration counter
MOVLW 0x0D
SUBWF DCFLOW,W ; Test for pulse > 0x0D*50 ms (valid LOW pulse)
BTFSS STATUS,C ; Pause too short?
RETFIE ; Yes
MOVLW 0x21
SUBWF DCFLOW,W ; Test for pulse > 0x21*50 ms (59th second)
BTFSS STATUS,C ; Pause too short for 59th second?
RETFIE ; Yes
MOVLW 0x28
SUBWF DCFLOW,W ; Test for pulse >= 0x28*50 ms (59th second)
BTFSC STATUS,C ; Pause too long?
RETFIE
MOVLW 0x0B ; Preload TIMER1 (0.5 second)...
MOVWF TMR1H
MOVLW 0xD0
MOVWF TMR1L ; ...to start the second half second after half a second
CLRF DCFSEC ; This is the zeroth second (M)
CLRF TSECS
CLRF HSECS
MOVLW 0x7F ; Blank parity bit
ANDWF MINBUF,W ; and store in W
CALL PARCHECK ; Call parity routine
btfsc TEMP,0 ; Test parity bit 0
goto MINODD ; if bit=1 odd # of bits set
BTFSS MINBUF,7 ; Parity even?
GOTO HRCHECK ; Yes, check hour parity
GOTO DCFNOK ; No, no need to test hours
MINODD
BTFSC MINBUF,7 ; Parity odd?
GOTO HRCHECK ; Yes, check hour parity
GOTO DCFNOK ; No, no need to test hours
HRCHECK ; Check parity of hour
MOVLW 0x7E ; Blank parity bit (and bit 0)
ANDWF HRBUF,W ; and store in W
CALL PARCHECK ; Call parity routine
btfsc TEMP,0 ; Test parity bit 0
goto HRODD ; if bit=1 odd # of bits set
BTFSS HRBUF,7 ; Parity even?
GOTO DCFWOK ; Yes, make DCF OK ("Wel OK")
GOTO DCFNOK ; No ("Not OK")
HRODD
BTFSC HRBUF,7 ; Parity odd?
GOTO DCFWOK ; Yes, make DCF OK
GOTO DCFNOK ; No
; Parity Subroutine
; http://picprojects.org.uk/projects/pictips.htm#Parity
PARCHECK
movwf TEMP
swapf TEMP,W
xorwf TEMP,W
movwf TEMP
rrf TEMP,F
rrf TEMP,F
xorwf TEMP,W
movwf TEMP
rrf TEMP,F
xorwf TEMP,F
return
DCFWOK
BTFSC DCFBAD
GOTO Skipdecode
BSF FIRSTDEC ; Enable setting DCFBAD after loading time at powerup
BCF MINS,0 ; Decode minutes from buffer
BTFSC MINBUF,0
BSF MINS,0
BCF MINS,1
BTFSC MINBUF,1
BSF MINS,1
BCF MINS,2
BTFSC MINBUF,2
BSF MINS,2
BCF MINS,3
BTFSC MINBUF,3
BSF MINS,3
BCF TMINS,0
BTFSC MINBUF,4
BSF TMINS,0
BCF TMINS,1
BTFSC MINBUF,5
BSF TMINS,1
BCF TMINS,2
BTFSC MINBUF,6
BSF TMINS,2
BCF HOURS,0 ; Decode hours from buffer
BTFSC HRBUF,1 ; Only seven "hour" bits so offset by one
BSF HOURS,0
BCF HOURS,1
BTFSC HRBUF,2
BSF HOURS,1
BCF HOURS,2
BTFSC HRBUF,3
BSF HOURS,2
BCF HOURS,3
BTFSC HRBUF,4
BSF HOURS,3
BCF THOURS,0
BTFSC HRBUF,5
BSF THOURS,0
BCF THOURS,1
BTFSC HRBUF,6
BSF THOURS,1
Skipdecode
BCF DCFBAD
CLRF MINBUF
CLRF HRBUF
BSF DCFOK
RETFIE
DCFNOK
BCF DCFOK
BTFSC FIRSTDEC ; Skip setting DCFBAD if firstdecode hasn't happened yet
BSF DCFBAD
CLRF MINBUF
CLRF HRBUF
RETFIE
Timehandler
BCF PIR1,TMR1IF ; Clear Interrupt Source
MOVLW 0x0E ; Preload TIMER1 (0.5 second-ish)
MOVWF TMR1H
CLRF TMR1L
; Increment halfseconds
INCF HSECS,F
MOVLW 0x14 ; Test for overflow
SUBWF HSECS,W ; if true, C=1, increment 10 seconds
BTFSS STATUS,C
RETFIE
CLRF HSECS
; Increment 10 seconds
INCF TSECS,F
MOVLW 0x06 ; Test for overflow
SUBWF TSECS,W ; if true, C=1, increment minutes
BTFSS STATUS,C
RETFIE
CLRF TSECS
BTFSC DCFOK ; DCF OK? If so skip further time processing and get time from decoded DCF
RETFIE ; Yes
; Increment minutes (only when free-running)
INCF MINS,F
MOVLW 0x0A ; Test for overflow
SUBWF MINS,W ; if true, C=1, increment 10 minutes
BTFSS STATUS,C
RETFIE
CLRF MINS
; Increment 10 minutes
INCF TMINS,F
MOVLW 0x06 ; Test for overflow
SUBWF TMINS,W ; if true, C=1, increment hours
BTFSS STATUS,C
RETFIE
CLRF TMINS
; Check for midnight
MOVLW 0x02
SUBWF THOURS,0 ; if true, C=1, check for midnight
BTFSC STATUS,C
GOTO MIDNIGHT
; Increment hours
INCF HOURS,F
MOVLW 0x0A ; Test for overflow
SUBWF HOURS,W ; if true, C=1, increment 10 hours
BTFSS STATUS,C
RETFIE
CLRF HOURS
; Increment 10 hours
INCF THOURS,F
RETFIE
MIDNIGHT
INCF HOURS,F
MOVLW 0x04 ; Test for midnight
SUBWF HOURS,W ; if true, C=1, new day
BTFSS STATUS,C
RETFIE
CLRF HOURS
CLRF THOURS
RETFIE
Multiplex ; Get the pattern for the current time display per row
BCF PIR1,TMR2IF ; Clear interrupt source (4.114ms)
BCF OE ; Disable (Hi-Z) outputs HEF chip to prevent ghosting
BTFSC ROW0 ; Top row active?
GOTO ONROW1 ; Yes, go to next row
BTFSC ROW1 ; (etcetera)
GOTO ONROW2
BTFSC ROW2
GOTO ONROW3
BTFSC ROW3
GOTO ONROW4
BCF ROW4 ; Rows 0-3 were not active so switch off ROW4
MOVLW 0x02
MOVWF PCLATH ; Adjust for page boundary computed goto
BCF STATUS,C ; Clear carry
RRF HSECS,W ; Divide half seconds by two to get whole seconds and place in W reg
CALL row0show ; Get pattern to shift into register
MOVWF DIGIT6
MOVFW TSECS
CALL row0show
MOVWF DIGIT5
MOVFW MINS
CALL row0show
MOVWF DIGIT4
MOVFW TMINS
CALL row0show
MOVWF DIGIT3
MOVFW HOURS
CALL row0show
MOVWF DIGIT2
MOVFW THOURS
CALL row0show
MOVWF DIGIT1
CLRW
SUBWF THOURS,0 ; Test for leading zero in tenhours
BTFSC STATUS,Z
CLRF DIGIT1 ; Blank first digit
BSF ROW0 ; Switch on ROW0
GOTO Show
ONROW1
BCF ROW0 ; Switch off ROW0
MOVLW 0x02
MOVWF PCLATH ; Adjust for page boundary computed goto
BCF STATUS,C ; Clear carry to prevent spurious bit7 being set
RRF HSECS,W ; Divide half seconds by two to get whole seconds and place in W reg for lookup table
CALL row1show
MOVWF DIGIT6
MOVFW TSECS
CALL row1show
MOVWF DIGIT5
MOVFW MINS
CALL row1show
MOVWF DIGIT4
MOVFW TMINS
CALL row1show
MOVWF DIGIT3
MOVFW HOURS
CALL row1show
MOVWF DIGIT2
MOVFW THOURS
CALL row1show
MOVWF DIGIT1
CLRW
SUBWF THOURS,0 ; Test for leading zero in tenhours
BTFSC STATUS,Z
CLRF DIGIT1 ; Blank first digit
BSF ROW1
GOTO Show
ONROW2
BCF ROW1
MOVLW 0x02
MOVWF PCLATH ; Adjust for page boundary computed goto
BCF STATUS,C ; Clear carry
RRF HSECS,W ; Divide half seconds by two to get whole seconds and place in W reg
CALL row2show
MOVWF DIGIT6
MOVFW TSECS
CALL row2show
MOVWF DIGIT5
MOVFW MINS
CALL row2show
MOVWF DIGIT4
MOVFW TMINS
CALL row2show
MOVWF DIGIT3
MOVFW HOURS
CALL row2show
MOVWF DIGIT2
MOVFW THOURS
CALL row2show
MOVWF DIGIT1
CLRW
SUBWF THOURS,0 ; Test for leading zero in tenhours
BTFSC STATUS,Z
CLRF DIGIT1 ; Blank first digit
BSF ROW2
GOTO Show
ONROW3
BCF ROW2
MOVLW 0x02
MOVWF PCLATH ; Adjust for page boundary computed goto
BCF STATUS,C ; Clear carry
RRF HSECS,W ; Divide half seconds by two to get whole seconds and place in W reg
CALL row3show
MOVWF DIGIT6
MOVFW TSECS
CALL row3show
MOVWF DIGIT5
MOVFW MINS
CALL row3show
MOVWF DIGIT4
MOVFW TMINS
CALL row3show
MOVWF DIGIT3
MOVFW HOURS
CALL row3show
MOVWF DIGIT2
MOVFW THOURS
CALL row3show
MOVWF DIGIT1
CLRW
SUBWF THOURS,0 ; Test for leading zero in tenhours
BTFSC STATUS,Z
CLRF DIGIT1 ; Blank first digit
BSF ROW3
GOTO Show
ONROW4
BCF ROW3
MOVLW 0x02
MOVWF PCLATH ; Adjust for page boundary computed goto
BCF STATUS,C ; Clear carry
RRF HSECS,W ; Divide half seconds by two to get whole seconds and place in W reg
CALL row4show
MOVWF DIGIT6
MOVFW TSECS
CALL row4show
MOVWF DIGIT5
MOVFW MINS
CALL row4show
MOVWF DIGIT4
MOVFW TMINS
CALL row4show
MOVWF DIGIT3
MOVFW HOURS
CALL row4show
MOVWF DIGIT2
MOVFW THOURS
CALL row4show
MOVWF DIGIT1
CLRW
SUBWF THOURS,0 ; Test for leading zero in tenhours
BTFSC STATUS,Z
CLRF DIGIT1 ; Blank first digit if zero
BSF ROW4
Show ; Fill shift register
BTFSC DIGIT6,5 ; Get Col27 (rightmost column, HEF3:QP4, display4:ROW2)
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT6,6 ; Get Col26
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT6,7 ; Get Col25
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT5,5 ; Get Col23 (skip Col24)
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT5,6 ; Get Col22
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT5,7 ; Get Col21
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
CALL Colon1 ; Get colon (flashing or not)
BTFSC DIGIT4,5 ; Get Col17
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT4,6 ; Get Col16
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT4,7 ; Get Col15
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT3,5 ; Get Col13
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT3,6 ; Get Col12
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT3,7 ; Get Col11
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
CALL Colon2
BTFSC DIGIT2,5 ; Get Col7
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT2,6 ; Get Col6
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT2,7 ; Get Col5
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT1,5 ; Get Col3
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT1,6 ; Get Col2
BSF SDI
BSF CLK
BCF CLK ; Output bit
BCF SDI ; Data -> 0
BTFSC DIGIT1,7 ; Get Col1 (HEF1:QP1, display1:ROW7)
BSF SDI
BSF CLK
BCF CLK ; Output bit
BSF STR
BCF STR ; Drive latch
BCF SDI ; Make sure data line is zero to prevent spurious display in Col27
BSF OE ; Done shift register, enable outputs
RETFIE
Colon1
BTFSC ROW0
GOTO Endcolon
BTFSC ROW2
GOTO Endcolon
BTFSC ROW4
GOTO Endcolon
BTFSC DCFBAD
GOTO Altcolon1
BTFSS DCFOK ; Solid colon when DCF OK
BTFSC HSECS,1 ; Get colon pattern (0.5 Hz flash) if not OK
BSF SDI
GOTO Endcolon
Altcolon1
BTFSC ROW1
GOTO Altcolon11
BTFSC HSECS,1 ; This is ROW3
BSF SDI
GOTO Endcolon
Altcolon11
BTFSS HSECS,1 ; This is ROW1
BSF SDI
GOTO Endcolon
Colon2
BTFSC ROW0
GOTO Endcolon
BTFSC ROW2
GOTO Endcolon
BTFSC ROW4
GOTO Endcolon
BTFSC DCFBAD
GOTO Altcolon2
BTFSS DCFOK ; Solid colon when DCF OK
BTFSC HSECS,1 ; Get colon pattern (0.5 Hz flash) if not OK
BSF SDI
GOTO Endcolon
Altcolon2
BTFSC ROW1
GOTO Altcolon21
BTFSS HSECS,1 ; This is ROW3
BSF SDI
GOTO Endcolon
Altcolon21
BTFSC HSECS,1 ; This is ROW1
BSF SDI
Endcolon
BSF CLK
BCF CLK ; Output bit (colon1)
BCF SDI
RETURN
; END Interrupthandlers
START
;Init stuff
BCF STATUS,RP0 ; Go to bank 0
BCF STATUS,RP1 ; Go to bank 0
MOVLW 0x07 ; Turn comparators off
MOVWF CMCON
BSF STATUS,RP0 ; Go to bank 1
CLRF TRISA ; Set port A as all outputs
BSF TRISA,4 ; except port A (DCFIN)
CLRF TRISB ; Set port B as all outputs
MOVLW B'00000111'
MOVWF OPTION_REG ; Weak pullups, prescaler Timer0, 1:256 (0.26ms per count for Timer0)
BCF STATUS,RP0 ; Go back to bank 0
BSF T1CON,T1CKPS1 ; These set the TIMER1 prescaler. Here are the possible values:
BSF T1CON,T1CKPS0 ; 00=1:1 01=1:2 10=1:4 11=1:8. Now set to 1:4
BCF T1CON,T1OSCEN ; Turn off the TIMER1 oscillator to save power (we don't need it because we're using the internal oscillator)
BCF T1CON,TMR1CS ; Select the internal oscillator for TIMER1
BSF T1CON,TMR1ON ; Enable TIMER1
BSF T2CON,T2CKPS1 ; Prescale 1:16 for TIMER2
BCF T2CON,T2CKPS0 ;
BCF T2CON,TOUTPS3 ; Postscale 1:1 for TIMER2
BCF T2CON,TOUTPS2 ;
BCF T2CON,TOUTPS1 ;
BCF T2CON,TOUTPS0 ;
BSF T2CON,TMR2ON ; Enable TIMER2
; Enable interrupts
BCF INTCON,INTF ; Clear INTF flag before enabling interrupts
BCF INTCON,T0IF ; Clear T0IF (TIMER0 Interrupt Flag) before enabling interrupts
BCF PIR1,TMR1IF ; Clear TMR1IF (TIMER1 Interrupt Flag) before enabling interrupts
BCF PIR1,TMR2IF ; Clear TMR2IF (TIMER1 Interrupt Flag) before enabling interrupts
BCF INTCON,INTE ; Disable interrupt on RB0/INT pin (an External interrupt)
BSF INTCON,PEIE ; Enable PEIE (PEripheral Interrupt Enable - for TIMER1, the 16 bit timer)
BSF STATUS,RP0 ; Go to bank 1
BSF PIE1,TMR1IE ; Enable interrupt on TIMER1 overflow (when the TMR1 register pair wraps around from 0xFFFF to 0x0000)
BSF PIE1,TMR2IE ; Enable interrupt on TIMER2 overflow
BCF PIE1,CMIE ; Disable interrupt on comparator output change
BCF STATUS,RP0 ; Go to bank 0
BSF INTCON,GIE ; Enable global interrupts
; INIT Registers
CLRF TMR1H
CLRF TMR1L
CLRF THOURS
CLRF HOURS
CLRF TMINS
CLRF MINS
CLRF TSECS
CLRF HSECS
CLRF FLAGS
; INIT Ports
CLRF PORTB
CLRF PORTA
WaitForInterrupt
GOTO WaitForInterrupt ; Do Nothing
; Lookup tables
ORG 0x240
row0show
ADDWF PCL,F ; Jump into the lookup table
RETLW B'11100000' ; 0
RETLW B'11000000' ; 1
RETLW B'11100000' ; 2
RETLW B'11100000' ; 3
RETLW B'10000000' ; 4
RETLW B'11100000' ; 5
RETLW B'11000000' ; 6 with short top bar
RETLW B'11100000' ; 7
RETLW B'11100000' ; 8
RETLW B'11100000' ; 9
row1show
ADDWF PCL,F ; Jump into the lookup table
RETLW B'10100000' ; 0
RETLW B'01000000' ; 1
RETLW B'00100000' ; 2
RETLW B'00100000' ; 3
RETLW B'10100000' ; 4
RETLW B'10000000' ; 5
RETLW B'10000000' ; 6
RETLW B'10100000' ; 7 with a hook
RETLW B'10100000' ; 8
RETLW B'10100000' ; 9
row2show
ADDWF PCL,F ; Jump into the lookup table
RETLW B'10100000' ; 0
RETLW B'01000000' ; 1
RETLW B'11100000' ; 2
RETLW B'11100000' ; 3
RETLW B'11100000' ; 4
RETLW B'11100000' ; 5
RETLW B'11100000' ; 6
RETLW B'00100000' ; 7
RETLW B'11100000' ; 8
RETLW B'11100000' ; 9
row3show
ADDWF PCL,F ; Jump into the lookup table
RETLW B'10100000' ; 0
RETLW B'01000000' ; 1
RETLW B'10000000' ; 2
RETLW B'00100000' ; 3
RETLW B'00100000' ; 4
RETLW B'00100000' ; 5
RETLW B'10100000' ; 6
RETLW B'00100000' ; 7
RETLW B'10100000' ; 8
RETLW B'00100000' ; 9
row4show
ADDWF PCL,F ; Jump into the lookup table
RETLW B'11100000' ; 0
RETLW B'11100000' ; 1
RETLW B'11100000' ; 2
RETLW B'11100000' ; 3
RETLW B'00100000' ; 4
RETLW B'11100000' ; 5
RETLW B'11100000' ; 6
RETLW B'00100000' ; 7
RETLW B'11100000' ; 8
RETLW B'11100000' ; 9 with long tail
NOP
END