;**************************************************************************
;
; MODIFIED BY JON STANLEY FOR 24-HOUR CLOCK MODE
;
; Displays time on a single 7-segment display.  The timing source
; can be a 4 MHz NTSC colour burst crystal.
;
; A numitron display is attached as follows:
;
;    RA0 segment a
;    RA1 segment b
;    RA2 segment c
;    RA3 segment d
;    RA4 segment e
;    RB4 segment f
;    RB5 segment g
;
; The common anode is connected directly to VDD.  The strange allocation 
; of port bits to segments allows RB6 and RB7 to be dedicated to 
; in-circuit serial programming.
;
; The time is displayed digit by digit over a four second period
; every 15 seconds and the display is blank otherwise.  Four LEDs are 
; connected from RB3-RB0 to GND via 470 ohm resistors; these are used
; to indicate the significance of the displayed digit: 10s of hours - 
; hours - 10s of minutes - minutes.
;
; 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.
;
; To permit the PIC to be programmed in-circuit the /MCLR pin is
; connected to VDD via a 1k resistor in series with a signal diode 
; (e.g. 1N4148) with anode connected to VDD.  
;
;
; Copyright (C) 1998 David Tait (david.tait@man.ac.uk)
;
;**************************************************************************


	LIST            P=16F628 ; no need to change this for the 16C84
	ERRORLEVEL      -302    ; suppress bank selection messages
        __CONFIG   3F02H   ; _HS_OSC & _WDT_OFF & _PWRTE_ON     ; Disable watchdog, 

#DEFINE _4_00MHZ            ; clock speed


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  _4_00MHZ                ; number of ticks per second for 4 MHz:
TCK0    EQU     .122			; nominal
TCK1    EQU     .123			; every 10 secs
TCK2    EQU     .121			; every min
TCK3    EQU     .123			; every 10 mins
TCK4    EQU     .124			; every hour
TCK5    EQU     .125			; every 10 hours
TCK6    EQU     .125			; every 24 hours
#ENDIF

	CBLOCK  20H             ; define variables required

	TICKS                   ; decremented every tick (9.15 ms or 8.19 ms)
	SEGS                    ; one bit per segment: "-gfedcba"
	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

	ENDC


	;*********************************;
	;         Initialisation          ;
	;*********************************;

	ORG     0

	movlw   7                   
        movwf   1F 


INIT    CLRF    SEC
	CLRF    SEC10
	CLRF    MIN
	CLRF    MIN10
	movlw	D'2'		; 12:00 initialized here!
	movwf	HOUR
	movlw	D'1'
	movwf	HOUR10
	CLRF    FRAME
	CLRF    PORTA
	CLRF    PORTB
	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
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
	MOVLW   30              ; Turn off Display at 100/120 ticks
	MOVWF   PORTB
	MOVLW   1F
	MOVWF   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      40,79,24,30,19,12,02,78,00,10
	DT      7F,7F,7F,7F,7F,7F


	;*********************************;
	;  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
	MOVWF   TICKS
	CLRF    SEC
	INCF    SEC10,F
	MOVF    SEC10,W
	SUBLW   5
	BTFSC   STATUS,C
	 RETURN

	MOVLW   TCK2
	MOVWF   TICKS
	CLRF    SEC10
	INCF    MIN,F
	MOVF    MIN,W
	SUBLW   9
	BTFSC   STATUS,C
	 RETURN

	MOVLW   TCK3
	MOVWF   TICKS
	CLRF    MIN
	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
	  RETURN

	MOVLW   TCK6
	MOVWF   TICKS
	CLRF    HOUR
	CLRF    HOUR10
	RETURN

INCHR   INCF    HOUR,F
	MOVF    HOUR,W
	SUBLW   9
	BTFSC   STATUS,C
	 RETURN

	MOVLW   TCK5
	MOVWF   TICKS
	CLRF    HOUR
	INCF    HOUR10,F
	RETURN



	;*********************************;
	; Displays the time digit by digit;
	;*********************************;

SHOW    CLRF    HHMM            
	INCF    FRAME,F         ; increment place in frame
	MOVF    FRAME,W
	SUBLW   D'08'		; 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   30              ; otherwise blank display
	MOVWF   PORTB
	MOVLW   1F
	MOVWF   PORTA
	RETURN

DHOUR10 BSF     HHMM,3
	MOVF    HOUR10,W
	BTFSS	STATUS,Z	; check for leading zero
	GOTO    DISPLAY
	RETURN			; skip display of leading 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   SEGS            ; and store
	ANDLW   1FH             ; extract PORTA segments
	MOVWF   PORTA           ; and display
	RRF     SEGS,W
	ANDLW   30H             ; extract PORTB segments
	IORWF   HHMM,W
	MOVWF   PORTB           ; and display
	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		; If DIGIT incremented over 9
	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 Numitron 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
