;**************************************************************************
;Earl's Mods  7/2005 Nixie Tube  driven from PORT A and Port B
; CLOCK.ASM
;
; Displays time on a single Nixie display.  The timing source
; 4 MHz  crystal.

; *** Chime signal on RA3 ***

; A Nixie display is attached as follows:
;
;	RB0  0
;	RB1  1
;	RB2  2
;	RB3  3
;	RB4  4
;	RB5  5
;	RB6  6
;	RB7  Switch
;	RA0	7
;	RA1	8
;	RA2	9
;   RA3 Chime output
;
; Each output is connected via a resistor to a transistor base.
;  The common anode
; is connected to high plus voltage through resistor. 
; Holding botton down during power up runs a Nixie Test program 
;
; The time is displayed digit by digit over a four second period
; every 10 seconds and the display is blank otherwise.  
;
; A normally open switch is connected from RB7 to GND via a 470 ohm 
; resistor; no pull-up resistor is needed as an internal weak pull-up 
; is enabled by the program.  To set the clock press the switch when
; the appropriate digit is displayed; the digit can then be incremented 
; by pressing the switch repeatedly.  If the switch is open for about 
; 2 seconds the clock display is restarted allowing another digit to be 
; changed.  It is up to the user to put in sensible times as no checking 
; is done by the program.
;
;**************************************************************************
	processor	16f84a
	include		<p16f84a.inc>
	__config	_XT_OSC & _WDT_OFF & _PWRTE_ON

	ERRORLEVEL      -302    ; suppress bank selection messages

;#DEFINE _3_58MHZ                ; choose clock speed
#DEFINE _4_00MHZ

PCL     EQU     2               ; registers are defined here to make this
STATUS  EQU     3               ; program self contained.
PORTA   EQU     5
PORTB   EQU     6
INTCON  EQU     0BH
TRISA   EQU     85H
TRISB   EQU     86H
OPTREG  EQU     81H

C       EQU     0               ; bits in STATUS
Z       EQU     2
RP0     EQU     5

T0IF    EQU     2               ; bit in INTCON

#IFDEF  _3_58MHZ                ; number of ticks per second for 3.58 MHz:
TCK0    EQU     .109            ; nominal
TCK1    EQU     .111            ; every 10 secs
TCK2    EQU     .113            ; every min
TCK3    EQU     .115            ; every 10 mins
TCK4    EQU     .114            ; every hour
TCK5    EQU     .110            ; every 10 hours
TCK6    EQU     .111            ; every 24 hours
#ENDIF

#IFDEF  _4_00MHZ                ; as above but for 4 MHz
TCK0    EQU     .122
TCK1    EQU     .123
TCK2    EQU     .121
TCK3    EQU     .123
TCK4    EQU     .124
TCK5    EQU     .125
TCK6    EQU     .125
#ENDIF



	CBLOCK  0CH             ; define variables required

	TICKS                   ; decremented every tick (9.15 ms or 8.19 ms)
	SEGS                    ; one bit per segment
	SEC
	SEC10
	MIN
	MIN10
	HOUR
	HOUR10
	FRAME                   ; used to decide when to display time
	HHMM                    ; one bit per digit displayed
	COUNT                   ; scratch register
	DIGIT                   ; last digit displayed
	CHIME					; Number of chimes needed
	ENDC


	;*********************************;
	;         Initialization          ;
	;*********************************;

	ORG     0

INIT    CLRF    SEC
	CLRF    SEC10
	CLRF    MIN
	CLRF    MIN10
	CLRF    HOUR
	movlw	D'1'
	movwf	HOUR10
	CLRF    FRAME
	CLRF    PORTA
	CLRF    PORTB
	CLRF	CHIME
	BSF     STATUS,RP0      ; select register bank 1
	CLRF    TRISA
	MOVLW   80H
	MOVWF   TRISB           ; only RB7 is an input
	MOVLW   4
	MOVWF   OPTREG          ; assign prescaler (1:32) to TMR0
	BCF     STATUS,RP0      ; reselect bank 0

	BTFSS   PORTB,7         ; switch open?
	GOTO    TEST         	; no, go to test mode
	;*********************************;
	;          Main Program           ;
	;*********************************;

MAIN    CALL    CLOCK           ; real-time clock algo called every second
		CALL    SHOW            ; display the time
		MOVF	CHIME,F			; check if chimes needed
		BZ		WAIT			; No Chime now
		BSF		PORTA,3			; Chime on
		DECF	CHIME,F
WAIT    BTFSS   INTCON,T0IF     ; wait for TMR0 to roll over
		GOTO    WAIT
		CLRF    INTCON
		CALL    CHKSW           ; check for button press
		MOVF	TICKS,W
		XORLW	D'20'			;Check for 20 ticks
		BTFSS	STATUS,Z
		GOTO	J1
		CLRF	PORTB			;Turn off Display at 100/120 ticks
		CLRF	PORTA
J1		DECFSZ  TICKS,F
		GOTO    WAIT
		GOTO    MAIN            ; get here every second


	;*********************************;
	;  Convert digit to segment form  ;
	;*********************************;

SEGTAB  ANDLW   0FH 
	ADDWF   PCL,F

	DT      .1,.2,.4,.8,.16,.32,.64,00,00,00,00 ; 0 to 6 Port B

SEGTABA  ANDLW   0FH 
	ADDWF   PCL,F

	DT      00,00,00,00,0,0,0,.1,.2,.4,0 ; 7 to 9 Port A

	;*********************************;
	;  Real-time clock algorithm      ;
	;*********************************;

CLOCK   MOVLW   TCK0            ; increment digits as appropriate
	MOVWF   TICKS           ; and define number of ticks per
	INCF    SEC,F           ; second for next second
	MOVF    SEC,W
	SUBLW   9
	BTFSC   STATUS,C
	 RETURN

	MOVLW   TCK1			;per 10 sec
	MOVWF   TICKS
	CLRF    SEC				;clear seconds, add 10 seconds
	INCF    SEC10,F
	MOVF    SEC10,W
	SUBLW   5				;check for a 6
	BTFSC   STATUS,C
	 RETURN

	MOVLW   TCK2			;per min
	MOVWF   TICKS
	CLRF    SEC10			;clear 10sec, add 1 minute
	INCF    MIN,F
	MOVF    MIN,W
	SUBLW   9				;check for 10
	BTFSC   STATUS,C
	 RETURN

	MOVLW   TCK3			;per 10 minutes
	MOVWF   TICKS
	CLRF    MIN				;clear minute, add 10 minute
	INCF    MIN10,F
	MOVF    MIN10,W
	SUBLW   5
	BTFSC   STATUS,C
	 RETURN

	MOVLW   TCK4
	MOVWF   TICKS
	CLRF    MIN10
	MOVF    HOUR10,W
	SUBLW   1
	BTFSC   STATUS,C
	 GOTO   INCHR
	INCF    HOUR,F
	MOVF    HOUR,W
	SUBLW   3
	BTFSC   STATUS,C
	goto SETCHIME

	MOVLW   TCK6
	MOVWF   TICKS
	CLRF    HOUR
	CLRF    HOUR10
	goto SETCHIME


INCHR   INCF    HOUR,F		;Add to single digit hour
		MOVF    HOUR,W
		SUBLW   9			; did it go from 9 to 10 ?
		BTFSC   STATUS,C
		goto SETCHIME				; no, it's  less than 10

		MOVLW   TCK5		;deal with 9 to 10 carry
		MOVWF   TICKS		;each 10 hour
		CLRF    HOUR
		INCF    HOUR10,F
		GOTO SETCHIME

SETCHIME MOVF	HOUR,W		;On hour change set chimes
		MOVWF	CHIME
		MOVF	HOUR10,F
		BZ		J2
		MOVLW	D'10'
		ADDWF	CHIME,F
J2		RETURN
	;*********************************;
	; Displays the time digit by digit;
	;*********************************;

SHOW    CLRF    HHMM            
		INCF    FRAME,F         ; increment place in frame
		MOVF    FRAME,W
		SUBLW   D'06'			; Display cycle time
		BTFSS   STATUS,C
		CLRF    FRAME
		MOVF    FRAME,W
		XORLW   1               
		BTFSC   STATUS,Z
		GOTO    DHOUR10        ; display 10s of hours when frame is 1
		XORLW   1^2
		BTFSC   STATUS,Z
		GOTO    DHOUR          ; display hour when frame is 2
		XORLW   2^3
		BTFSC   STATUS,Z
		GOTO    DMIN10         ; display 10s of mins when frame is 3
		XORLW   3^4
		BTFSC   STATUS,Z
		GOTO    DMIN           ; display mins when frame is 4 
		MOVLW   H'00'              ; otherwise blank display
		MOVWF   PORTB
		MOVLW   H'00'
		MOVWF   PORTA
		RETURN

DHOUR10 BSF     HHMM,3
		MOVF    HOUR10,W
		BTFSS	STATUS,Z		;check for leading zero
		GOTO    DISPLAY        
		RETURN					;skip display of zero

DHOUR   BSF     HHMM,2
		MOVF    HOUR,W
		GOTO    DISPLAY

DMIN10  BSF     HHMM,1
		MOVF    MIN10,W
		GOTO    DISPLAY

DMIN    BSF     HHMM,0
		MOVF    MIN,W           ; falls through to DISPLAY

	
	;*********************************;
	;       Displays digit in W       ;
	;*********************************;

DISPLAY MOVWF   DIGIT           ; save number to be displayed in DIGIT
	CALL    SEGTAB          ; convert to segment form
	MOVWF   PORTB           ; and display 0-6
	MOVF	DIGIT,W
	CALL	SEGTABA
	MOVWF   PORTA           ; and display  7-9
	RETURN


	;*********************************;
	; Checks for a switch press and   ;
	; updates digit if displayed      ;
	;*********************************;

CHKSW   BTFSC   PORTB,7         ; switch closed?
		RETURN                 ; no
		MOVF    HHMM,F
		BTFSC   STATUS,Z        ; digit displayed?
		RETURN                 ; no

INCDIG  INCF    DIGIT,F         ; DIGIT is the currently displayed number
		MOVF    DIGIT,W
		SUBLW   9
		BTFSS   STATUS,C
		CLRF    DIGIT
		MOVF    DIGIT,W
		CALL    DISPLAY
		CALL    DELAY           ; wait for switch to settle
CHKSW0  BTFSS   PORTB,7         ; switch open?
		GOTO    CHKSW0         ; no
		CALL    DELAY
		BTFSS   PORTB,7         ; still open?
		GOTO    CHKSW0         ; no
		MOVLW   D'20'
		MOVWF   COUNT
CHKSW1  BTFSS   PORTB,7         ; switch open?
		GOTO    INCDIG         ; no
		CALL    DELAY
		DECFSZ  COUNT,F
		GOTO    CHKSW1
		MOVF    DIGIT,W         ; switch was open for around 2 secs
		CLRF    FRAME  
		CLRF    SEC10
		CLRF    SEC
		BTFSC   HHMM,3          ; update correct digit
		MOVWF  HOUR10
		BTFSC   HHMM,2
		MOVWF  HOUR
		BTFSC   HHMM,1
		MOVWF  MIN10
		BTFSC   HHMM,0
		MOVWF   MIN
		GOTO    MAIN            ; restart the program


	;*********************************;
	; Delay used by switch routine    ;
	;*********************************;

DELAY   MOVLW   D'12'           ; roughly 100ms delay
		MOVWF   TICKS
DEL1    BTFSS   INTCON,T0IF     ; wait for TMR0 to roll over
	 	GOTO    DEL1
		CLRF    INTCON
		DECFSZ  TICKS,F
	 	GOTO    DEL1
		RETURN

TEST	CLRF	COUNT			;exercise Nixie by cycling through
		MOVF	COUNT,W			;all numbers
		CALL	DISPLAY
		CALL	DELAY
		CALL	DELAY		;1 second delay
		INCF	COUNT,F
		MOVF	COUNT,W
		XORLW   D'10'			;Test for 10             
		BTFSS   STATUS,Z
		GOTO    TEST+1
		GOTO	TEST   		;Reset COUNT to 0 
		END


