; ------------------------------------------------------------------------------
;
; Single Nixie Clock v0.0.2
;
; ------------------------------------------------------------------------------
;
; Written by :
;
; Jan Wagemakers : Donated to the Public Domain
;
; ------------------------------------------------------------------------------
LIST p=PIC16F648A
INCLUDE "p16f648a.inc"
errorlevel -302
;
__CONFIG _CP_OFF&_DATA_CP_OFF&_LVP_OFF&_BODEN_OFF&_MCLRE_OFF&_PWRTE_ON&_WDT_OFF&_INTOSC_OSC_NOCLKOUT
; ------------------------------------------------------------------------------
; Define variables
; ------------------------------------------------------------------------------
cblock h'20'
menu ; 0 = display clock
; 1 = menu H(high)
; 2 = menu H(low)
; 3 = menu M(high)
; 4 = menu M(low)
submenu ; 0 = menu
; 1 = submenu
HZ50counter ; Count the 50HZ pulse
buttonr ; count how long button is released
buttonp ; count how log button is pressed
number ; number to display on Nixie
DL ; used in number to digit conversion
DH ; used in number to digit conversion
S ; Seconds in Binary (only used internal)
H ; Hours in BCD
M ; Minutes in BCD
Hstep1 ; Hours in BCD at the moment DisplayCounter = 1
Mstep1 ; Minutes in BCD at the moment DisplayCounter = 1
Delay ; used in sleep routine
DisplayCounter ; Display what part of the clock?
endc
; ------------------------------------------------------------------------------
; Let's start
; ------------------------------------------------------------------------------
org h'0000'
; ------------------------------------------------------------------------------
; Init PIC input output
; ------------------------------------------------------------------------------
bcf STATUS, RP1
bsf STATUS, RP0 ; select bank 1
bcf PCON, OSCF ; CLK=48Khz
movlw b'11111000' ; 1 = input 0 = output
movwf TRISA ; set input/output PORTA
clrf TRISB ; PORTB = output
bcf STATUS, RP0 ; select bank 0
movlw h'07' ; turn comparators off
movwf CMCON
; ------------------------------------------------------------------------------
; Reset some variables
; ------------------------------------------------------------------------------
clrf H
clrf M
clrf S
clrf menu
clrf submenu
clrf buttonp
clrf buttonr
clrf DisplayCounter
; ------------------------------------------------------------------------------
; Loop : everything is done is this loop
; ------------------------------------------------------------------------------
Loop:
; ------------------------------------------------------------------------------
; Start clock menu routine
; ------------------------------------------------------------------------------
btfsc PORTA, D'3' ; IF RA3 <> 0 THEN ...
goto released ; ... button is not pressed ELSE ...
pressed: ; ... button is pressed
incf buttonp, F
movlw D'2' ; check how long key is pressed
subwf buttonp, w
btfss STATUS, Z
goto chkkey_done ; not long enough, go away
; ----------------------------------------------------------------------
; button is pressed long enough
; ----------------------------------------------------------------------
clrf buttonp ; reset counter
;
movf submenu, w ; menu or submenu?
btfss STATUS, Z
goto psubmenu
; ----------------------------------------------------------------------
; button pressed : menu routine (:menu)
; ----------------------------------------------------------------------
incf menu, F
movlw D'5'
subwf menu, w
btfsc STATUS, Z
clrf menu ; if menu = 5 then menu = 0
;
movf menu, W
movwf number
call number_to_digit ; display menu number
bsf PORTA, D'2' ; display menu number with :
;
goto chkkey_done ; go away
; ----------------------------------------------------------------------
; button pressed : submenu routine
; ----------------------------------------------------------------------
psubmenu:
; ----------------------------------------------------------------------
; IF menu=1 THEN H = H + 0x10
; ----------------------------------------------------------------------
movlw D'1'
subwf menu, w
btfss STATUS, Z
goto XH
movlw H'10'
addwf H, F
; ----------------------------------------------------------------------
; IF menu=2 THEN H++
XH: ; ----------------------------------------------------------------------
movlw D'2'
subwf menu, w
btfsc STATUS, Z
incf H, F
; ----------------------------------------------------------------------
; IF menu=3 THEN M = M + 0x10
; ----------------------------------------------------------------------
movlw D'3'
subwf menu, w
btfss STATUS, Z
goto XM
movlw H'10'
addwf M, F
; ----------------------------------------------------------------------
; IF menu=4 THEN M++
XM: ; ----------------------------------------------------------------------
movlw D'4'
subwf menu, w
btfsc STATUS, Z
incf M, F
; ----------------------------------------------------------------------
; Check for overflow of digits
; ----------------------------------------------------------------------
movlw B'11110000'
btfsc M, D'3'
btfss M, D'1'
goto check1
andwf M, f ; IF M(low) = 10 then M(low) = 0
check1:
movlw B'00001111'
btfsc M, D'6'
btfss M, D'5'
goto check2
andwf M, f ; IF M(high) = 10 then M(high) = 0
check2:
movlw B'11110000'
btfsc H, D'3'
btfss H, D'1'
goto check3
andwf H, f ; IF H(low) = 10 then H(low) = 0
check3:
movlw B'00001111'
btfsc H, D'5'
btfss H, D'4'
goto check4
andwf H, f ; IF H(high) = 3 then H(high) = 0
check4:
btfss H, D'5' ; IF H(high) = 2 AND ...
goto check5
movlw B'00001111'
andwf H, w ; w = H(low)
sublw D'3' ; ... H(low) > 3 then ...
btfss STATUS, C
clrf H ; .... reset H because for ex. ...
; .... 25:00 is false
check5:
; ----------------------------------------------------------------------
; Display the right digit on the Nixie
; ----------------------------------------------------------------------
disp_digit:
; -----------------------------------------------------------------------
; IF menu = 1 THEN display H(high)
; -----------------------------------------------------------------------
movlw B'11110000'
andwf H, w
movwf number
swapf number, F ; number = H(high)
movlw D'1'
subwf menu, w
btfsc STATUS, Z
call number_to_digit
; -----------------------------------------------------------------------
; IF menu = 2 THEN display H(low)
; -----------------------------------------------------------------------
movlw B'00001111'
andwf H, w
movwf number ; number = H(low)
movlw D'2'
subwf menu, w
btfsc STATUS, Z
call number_to_digit
; -----------------------------------------------------------------------
; IF menu = 3 THEN display M(high)
; -----------------------------------------------------------------------
movlw B'11110000'
andwf M, w
movwf number
swapf number, F ; number = M(high)
movlw D'3'
subwf menu, w
btfsc STATUS, Z
call number_to_digit
; -----------------------------------------------------------------------
; IF menu = 41 THEN display M(low)
; -----------------------------------------------------------------------
movlw B'00001111'
andwf M, w
movwf number ; number = M(low)
movlw D'4'
subwf menu, w
btfsc STATUS, Z
call number_to_digit
;
goto chkkey_done ; and done.
; ----------------------------------------------------------------------
; END button pressed
; ----------------------------------------------------------------------
released:
incf buttonr, F
movlw D'2'
subwf buttonr, w
btfss STATUS, Z
goto chkkey_done
; ----------------------------------------------------------------------
; button is released long enough
; ----------------------------------------------------------------------
clrf buttonr ; reset counter
;
movf menu, W
btfsc STATUS, Z
goto clock ; if menu = 0 then display normal clock
;
movf submenu, w ; menu or submenu
btfss STATUS, Z
goto rsubmenu
; ----------------------------------------------------------------------
; button released : menu routine (:menu --> digit)
; ----------------------------------------------------------------------
rmenu:
bsf submenu, D'1' ; enter submenu
goto disp_digit ; Mmmm, spaghetti code ;-)
; ----------------------------------------------------------------------
; button released : submenu routine
; ----------------------------------------------------------------------
rsubmenu:
clrf menu
clrf submenu
clrf DisplayCounter ; exit menu/submenu
; ----------------------------------------------------------------------
; Let's end the button/menu/submenu routine
; ----------------------------------------------------------------------
chkkey_done:
movf menu, W
btfsc STATUS, Z
goto clock ; if menu = 0 then display normal clock
goto HZ50
; ------------------------------------------------------------------------------
; Start normal clock routine
; ------------------------------------------------------------------------------
clock:
incf DisplayCounter, F
; ----------------------------------------------------------------------
; IF DisplayCounter = 1 THEN
; Display Nothing AND
; Hstep1 = H Mstep1 = M
; ----------------------------------------------------------------------
movlw d'1'
subwf DisplayCounter, w
btfsc STATUS, Z
call cls_and_saveHM
; ----------------------------------------------------------------------
; IF DisplayCounter = 2 THEN
; Display Hstep1(high)
; ----------------------------------------------------------------------
movlw B'11110000'
andwf Hstep1, w
movwf number
swapf number, F ; number = Hstep1(high)
movlw d'2'
subwf DisplayCounter, w
btfsc STATUS, Z
call number_to_digit
; ----------------------------------------------------------------------
; IF DisplayCounter = 3 THEN
; Display Nothing
; ----------------------------------------------------------------------
movlw d'3'
subwf DisplayCounter, w
btfsc STATUS, Z
call cls
; ----------------------------------------------------------------------
; IF DisplayCounter = 4 THEN
; Display Hstep1(low)
; ----------------------------------------------------------------------
movlw B'00001111'
andwf Hstep1, w
movwf number ; number = Hstep1(low)
movlw d'4'
subwf DisplayCounter, w
btfsc STATUS, Z
call number_to_digit
; ----------------------------------------------------------------------
; IF DisplayCounter = 5 THEN
; Display Nothing
; ----------------------------------------------------------------------
movlw d'5'
subwf DisplayCounter, w
btfsc STATUS, Z
call cls
; ----------------------------------------------------------------------
; IF DisplayCounter = 6 THEN
; Display :
; ----------------------------------------------------------------------
movlw d'6'
subwf DisplayCounter, w
btfsc STATUS, Z
bsf PORTA, D'2' ; display :
; ----------------------------------------------------------------------
; IF DisplayCounter = 7 THEN
; Display Nothing
; ----------------------------------------------------------------------
movlw d'7'
subwf DisplayCounter, w
btfsc STATUS, Z
call cls
; ----------------------------------------------------------------------
; IF DisplayCounter = 8 THEN
; Display Mstep1(high)
; ----------------------------------------------------------------------
movlw B'11110000'
andwf Mstep1, w
movwf number
swapf number, F ; number = Mstep1(high)
movlw d'8'
subwf DisplayCounter, w
btfsc STATUS, Z
call number_to_digit
; ----------------------------------------------------------------------
; IF DisplayCounter = 9 THEN
; Display Nothing
; ----------------------------------------------------------------------
movlw d'9'
subwf DisplayCounter, w
btfsc STATUS, Z
call cls
; ----------------------------------------------------------------------
; IF DisplayCounter = 10 THEN
; Display Mstep1(low)
; ----------------------------------------------------------------------
movlw B'00001111'
andwf Mstep1, w
movwf number ; number = Mstep1(low)
movlw d'10'
subwf DisplayCounter, w
btfsc STATUS, Z
call number_to_digit
; ----------------------------------------------------------------------
; IF DisplayCounter = 11 THEN
; Display Nothing AND
; DisplayCounter = 0
; ----------------------------------------------------------------------
movlw d'11'
subwf DisplayCounter, w
btfsc STATUS, Z
call cls_and_crlf_DisplayCounter
; ------------------------------------------------------------------------------
; Synchronize with 50HZ __+--+__+--+__
; ------------------------------------------------------------------------------
HZ50:
clrf HZ50counter
HZ50islow:
call zzz ; sleep a while
btfss PORTA, d'4'
goto HZ50islow
HZ50ishigh:
call zzz ; sleep a while
btfsc PORTA, d'4'
goto HZ50ishigh
;
incf HZ50counter, F ; Do every 1/50 sec. : 50HZcounter++
movlw d'50'
subwf HZ50counter, w ; 50 * 1/50 seconds -> 1 second
btfss STATUS, Z
goto HZ50islow
; ------------------------------------------------------------------------------
; INC clock sec, min, hour
; ------------------------------------------------------------------------------
incf S, F ; Do every second : S = S + 1
movlw d'60'
subwf S, w
btfss STATUS, Z
goto Loop
clrf S ; IF S = 60 THEN S = 0 and ...
; ----------------------------------------------------------------------
; OK, it's time to update the clock by 1 minute
; ----------------------------------------------------------------------
incf M, f ; M = M + 1
movlw D'6'
btfsc M, D'3'
btfss M, D'1'
goto Mok ; IF M(low) = 10 THEN
addwf M, f ; M(low) = 0 AND M(high)++
Mok:
movlw H'60'
subwf M, w
btfss STATUS, Z
goto Loop
clrf M ; IF M(BCD) = 60 THEN M = 0 and ...
; ----------------------------------------------------------------------
; OK, it's time to update the clock by 1 hour
; ----------------------------------------------------------------------
incf H, F ; ... H = H + 1
movlw D'6'
btfsc H, D'3'
btfss H, D'1'
goto Hok ; IF H(low) = 10 THEN
addwf H, f ; H(low) = 0 AND H(high)++
Hok:
movlw H'24'
subwf H, w
btfsc STATUS, Z
clrf H ; IF H(BCD) = 24 THEN H = 0
goto Loop
; ------------------------------------------------------------------------------
; ------------------------------------------------------------------------------
; Subroutines
; ------------------------------------------------------------------------------
cls_and_crlf_DisplayCounter:
clrf DisplayCounter
goto cls
cls_and_saveHM:
movf H, w
movwf Hstep1
movf M, w
movwf Mstep1
cls:
clrf PORTB ; Display nothing
clrf PORTA
return
;
number_to_digit:
movf number, w
BTFSC STATUS, Z ; if number = 0 then number = 10
movlw D'10'
movwf number
movlw b'00000001'
movwf DL
clrf DH ; DH:DL = 0000000000000001
dountilzero:
decfsz number, F
goto isnotzero
movf DL, w
movwf PORTB
movf DH, w
movwf PORTA
return
isnotzero:
BCF STATUS, C
rlf DL, F
rlf DH, F
goto dountilzero
;
zzz: ; zzz zzz zzz zzz (sleep)
movlw D'4'
movwf Delay
zloop:
decfsz Delay, F
goto zloop
return
;
; ----------------------------------------------------------------------------
end
; ----------------------------------------------------------------------------