;
;2modbl_1.asm

;3/29/01 many minor changes. Hands in analog mode are wider (stay on longer)
;	 mode switching somewhat improved
	
;Switch modes using a Hall Effect sensor

;based on Bob Blick's propellor clock
;
;Analog and demo modes by Don Zehnder
;
;mode 0: 	digital
;mode 1:	analog
;mode 2:	switches between analog and digital. Demo mode
;
;Assignments on portb, LEDs logic 0 = on. 
;BIT	LED (from center=0 to edge=6)
;0	0
;1	1
;2	2
;3	3
;4	4
;5	5
;6	6
;7	unused
;
;Assignments on portA
;0	index		external pull-up (normally high)
;1	outermost LED	logic 0 = on
;2	time setting	external pull-up (normally high)
;3	mode switch	external pull-up (normally high)
;4	inner LEDs	logic 0 = on, switched w/ a transistor. Better to have put this on any
;			other port to avoid need for a biasing resistor
;
;Analog Hands, portb bits:
;hours bit 0,1,2,3  plus portA,4
;min bit 0,1,2,3,4,5  plus portA,4
;seconds bit 7

;10 MHz crystal. Timings given are for 10.00000 Mhz, can adjust for accuracy
;
;Motor runs counterclockwise at >1150 RPM. Index sensor is triggered at the 3 o'clock position.

	list	p=16f84
	include "p16f84.inc"
	__FUSES _CP_OFF & _WDT_ON & _HS_OSC & _PWRTE_ON 

	cblock	0x0c
;----unique to analog---		
	  DIVISOR1	;these are to count # of interrupts 
	  DIVISOR2	;required to increment ZSEC, decrement DSEC 
	  DSEC		;There are 256 DSECs in a minute (1 rev of hands)
	  ZSEC		;When this rolls over, decrement DMIN
	  DMIN		;There are 256 DMINs in an hour (1 rev of hands)
	  ZMIN		;When this rolls over, decrement DHOUR
	  DHOUR		;There are 256 DHOURs in 12 hours (1 rev of hands)
	  mulcnd       	; 8 bit multiplicand
	  H_byte       	; High byte of the 16 bit result
	  L_byte       	; Low byte of the 16 bit result - (unused result)
	  TEMP		; part of routine for setting hands when period=0
	  HOLDFLAGS	;flags to determine on/off status of hands 
	  sec_on_cnt	;counters for number of interrupts since hands were turned on
	  min_on_cnt
	  hour_on_cnt

	     
;----unique to digital---
          dot_index       ;which column is being displayed
          digit_index     ;which digit is being displayed
          hours           ;in display format, not hex(01-12)
          minutes         ;00 to 59
          bigtick_dbl     ;incremented each interrupt
          bigtick_hi
          bigtick_lo
          scratch         ;scratch value
          tick            ;used by delay
	  COUNTER2	  ;used as secondary counter to slow time set
	  ADJUST	  ;fine adjust on timing. See time adjustment notes or spreadsheet
			  ;corrects for observed crystal error to get most accurate time
	  
;----common--------------
	  COUNTER	;used to slow time set
      	  PERIOD_CNT	;incremented every other interrupt
	  PERIOD 	;stable period after hysteresis calc.
 	  safe_w	;copy of W safe from interrupt
	  safe_s	;copy of STATUS safe from interrupt
	  period_dup	;copy of period_count safe from interrupt
	  flags         ;b2=int, b1=minute, b0=prev_flag, b3=mode_bit, b4=toggle for period_count
	  mode		;0=digital, 1=analog, 2=demo
	  mode_debounce	;counters used to control response to mode switch sensor
	  mode_debounce1
	  mode_debounce2	;controls sensitivity only when displaying analog clock	
	  MODE_TIMER
	endc

;----ANALOG-----
#define divisor1_val  	d'147'		;roll-over at 109 (256-109)=147
#define divisor2_val  	d'235'		;roll-over at 21
#define zsec_val	d'196'		;min hand moves 1/60 fast as sec hand
#define zmin_val	d'244'		;hour hand moves 1/12 fast as min hand


;-------------------ADJUST AS REQUIRED FOR ACCURACY-make sure to change the corresponding
;-------------------operation to add or subtract as required-----------------------------

#define nths_adj_div2	d'0'		;these can be adjusted to correct
#define nths_adj_zsec	d'11'		;for observed crystal error in analog mode
#define	nths_adj_zmin	d'1'		;time is kept similarly to AN590

#define sec_flag	HOLDFLAGS,0
#define min_flag	HOLDFLAGS,1
#define hour_flag	HOLDFLAGS,2
#define hand_on_cnt_val	d'2'		;how many interrupts to keep each hand lit

;-----COMMON-------
#define	in_bit		PORTA,0		;using phototransistor connect to ground
#define	time_set	PORTA,3		;Hall-effect, externally pulled-up
#define mode_switch	PORTA,2		;Hall-effect, externally pulled-up
#define prev_flag	flags,0		;whether or not index sense was detected on prev iteration
#define mode_bit	flags,3		;applies to mode 3 (demo) 1=analog, 0=digital
#define	debounce_val	d'50'		;determines how sensitive the mode switching is
#define	debounce_val2	d'20'		;determines how sensitive the mode switching is from analog display

;-----DIGITAL------
#define OVERHEAD_VAL	d'35'		;overhead that is subtracted to make delay work out right
					
	org	0x00 		
	goto	Start

;----------------------------------------------
;---INTERRUPT ROUTINE--------------------------
	org     0x04            ;interrupt vector
Int  	movwf   safe_w          ;save w
   	swapf   STATUS,w        ;swap status, w
	movwf   safe_s          ;save status(nibble swap, remember)
	
;--------------------------------------
; Keep digital time--------------------   
; 585937.5 interrupts every minute. Increment the bigtick each time.
                incf    bigtick_lo,f
                btfsc   STATUS,Z
                incf    bigtick_hi,f
                btfsc   STATUS,Z
                incfsz  bigtick_dbl,f
                goto    Bigtick_out
;--------
; here? bigtick has rolled over to zero and one minute has passed.
; reload bigtick and set a flag for the main counter
;--------
		movlw   0xf7            ;these timings for no prescale
                movwf   bigtick_dbl     ;and 10Mhz crystal
                movlw   0x0f		;not corrected for observed error
                movwf   bigtick_hi	
                movlw   0x2f		
                movwf   bigtick_lo
                bsf     flags,1         ;notify Keep_time

		incfsz	ADJUST,1	;make correction every 256 minutes
		goto	Bigtick_out
		movlw	d'128'		;****adjust for accuracy here
		addwf	bigtick_lo,f	;****add or subtact as required
Bigtick_out	
	
;--------------------------------
;analog main time keeping code
;--------------------------------
	incfsz	DIVISOR1,1
	goto	exit
	movlw	divisor1_val	;reset DIVISOR1 every time it rolls over
	movwf	DIVISOR1		
	incfsz	DIVISOR2,1
	goto 	exit
	movlw	divisor2_val	;reset DIVISOR2 each time it rolls
	movwf	DIVISOR2
	movlw	nths_adj_div2	;adj-roll later (plus sign in time calculation spreadsheet)
	subwf	DIVISOR1,1	;****MANUALLY CHANGE THIS TO ADD OR SUBTRACT AS REQUIRED
	decf	DSEC,1		;decrement: reverses direction of display. get here 256 times/minute
	
	decfsz	MODE_TIMER,1	;toggle the mode_bit. Determines analog or digital when in demo mode
	goto 	no_mode
	movlw	d'25'		;about 6 seconds
	movwf	MODE_TIMER	;reload it
	movlw	b'00001000'
	xorwf	flags,1		;mode flag (bit 3) . toggle it.
			
no_mode	incfsz	ZSEC,1
	goto	exit
	movlw	zsec_val	;reset ZSEC when it rolls
	movwf	ZSEC
	movlw	nths_adj_zsec	;earlier (minus)
	addwf	DIVISOR1,1	;****zsec, MANUALLY CHANGE THIS TO ADD OR SUBTRACT AS REQUIRED
	decf	DMIN,1
	incfsz	ZMIN,1
	goto	exit
	movlw	zmin_val	;reset ZMIN when it rolls
	movwf	ZMIN
	movlw	nths_adj_zmin
	subwf	DIVISOR1,1	;****zmin, MANUALLY CHANGE THIS TO ADD OR SUBTRACT AS REQUIRED	
	decf	DHOUR,1
exit

;---------NOW take action depending on mode it is in-----------		
test_mode			
	movf	mode,f
	btfsc	STATUS,Z
	goto	i_digital		;if mode=0
	movlw	d'1'
	xorwf	mode,w
	btfsc	STATUS,Z
	goto	i_analog		;if mode = 1
	btfss	mode_bit		;mode=2, (demo)

	goto	i_digital		;if mode=2 and bit clear, do digital
	goto	i_analog		;else analog

;-Analog mode--------------
i_analog
	movlw	b'11111111'	;make all outputs high
	movwf	PORTB		;to turn off all the LEDs
	bsf	PORTA,4		;turn off the inner LEDs
	movf	PERIOD,W	;some junk is here to fix problem
	movwf	TEMP		;where hands turn off when PERIOD_CNT is 0
	movlw	d'2'
	subwf	TEMP,1		;TEMP=PERIOD-2

;-start setting hands on the clock based on time in the registers
;seconds--------
	movf	DSEC,W				
	movwf	mulcnd	     
	call	mpy_F		;do the math->PERIOD x time/256 = H_byte

	movf	H_byte,W	;if H_byte>PERIOD-2 and
	subwf	TEMP,W		
	btfsc	STATUS,C
	goto	ng
	movf	PERIOD_CNT,1	;if PERIOD_CNT=0 turn on LED
	btfsc	STATUS,Z
	goto	sec_on
ng	movf	PERIOD_CNT,W	;compare result of the calculation to PERIOD_CNT
	xorwf	H_byte,W		
	btfss	STATUS,Z	;turn on LED if PERIOD_CNT matches calculated value
	goto 	not_sec_on		
	
sec_on	bcf	PORTB,6 	
	bsf 	sec_flag	;set the flag that controls whether or not hand will light on next interrupt
	clrf	sec_on_cnt
	goto	i_min
	
not_sec_on
	btfss	sec_flag	;no math match, but turn on if it it has not timed out yet	
	goto	i_min
	bcf	PORTB,6		;on
	incf 	sec_on_cnt,1
	movlw	hand_on_cnt_val		
	xorwf	sec_on_cnt,W
	btfsc	STATUS,Z
	bcf	sec_flag	;clear flag so it won't go on at next interrupt
	
;minutes--------
i_min	movf	DMIN,W		;most everything is the same as for seconds
	movwf	mulcnd		
	call	mpy_F	

	movf	H_byte,W
	subwf	TEMP,W		
	btfsc	STATUS,C
	goto	ngm
	movf	PERIOD_CNT,1	
	btfsc	STATUS,Z
	goto	min_on

ngm	movf	PERIOD_CNT,W
	xorwf	H_byte,W	
	btfss	STATUS,Z	
	goto	not_min_on

min_on	bcf	PORTA,4		;turn inner LEDs on
	movlw	b'11000000'	;this is the pattern for this hand
	andwf	PORTB,1		;turn it on
	bsf 	min_flag
	clrf	min_on_cnt
	goto	i_hour

not_min_on

	btfss	min_flag
	goto	i_hour
	bcf	PORTA,4
	movlw	b'11000000'	;this is the pattern for this hand
	andwf	PORTB,1		;turn it on
	incf 	min_on_cnt,1
	movlw	hand_on_cnt_val
	xorwf	min_on_cnt,W
	btfsc	STATUS,Z
	bcf	min_flag

;hours-------------------------
i_hour	movf	DHOUR,W		;everything is the same as for minutes
	movwf	mulcnd		
	call	mpy_F	

	movf	H_byte,W	
	subwf	TEMP,W		
	btfsc	STATUS,C
	goto	ngh
	movf	PERIOD_CNT,1
	btfsc	STATUS,Z
	goto	hour_on
	
ngh	movf	PERIOD_CNT,W
	xorwf	H_byte,W	

	btfss	STATUS,Z
	goto	not_hour_on

hour_on	bcf	PORTA,4
	movlw	b'11110000'
	andwf	PORTB,1
	bsf 	hour_flag
	clrf	hour_on_cnt
	goto	end_int

not_hour_on

	btfss	hour_flag		
	goto	end_int
	bcf	PORTA,4
	movlw	b'11110000'
	andwf	PORTB,1
	incf 	hour_on_cnt,1
	movlw	hand_on_cnt_val
	xorwf	hour_on_cnt,W
	btfsc	STATUS,Z
	bcf	hour_flag

;-----digital------
i_digital				;don't need to do anything
	
;------------------
end_int		btfsc	flags,4		;increment PERIOD_CNT only every other
		incf	PERIOD_CNT,1	;interrupt. Since hand position can only
					;be determined to the nearest interrupt,
					;this produces less hand jitter than using
					;tmr0 prescale of 2x (otherwise period_cnt will overflow at 10Mhz
					;and this RPM)
		movlw	b'00010000'
		xorwf	flags,1		;toggle bit 4 of flags
		
;restore and return--
go_there	clrwdt	
       		swapf   safe_s,w        ;fetch status, reswap nibbles
                movwf   STATUS          ;restore status
                swapf   safe_w,f        ;swap nibbles in preparation
                swapf   safe_w,w        ;for the swap restoration of w
                bcf     INTCON,2        ;clear interrupt flag before return
                retfie                  ;return from interrupt

;*******************************************************************
;Time, whether sec, min, or hour is kept as a value between 0 to 255,
;and is maintained in DSEC, DMIN and DHOUR   
;To scale the time in order to compare to the current value of PERIOD_CNT,
;multiply time*PERIOD and divide by 256, which is just the high
;byte of time*PERIOD result
;          ( Fast Version : Straight Line Code )
; Before calling the subroutine " mpy_F ", the multiplier is PERIOD
; multiplicand is " mulcnd " . The 16 bit result is stored in locations
; H_byte & L_byte.      
;*******************************************************************
;****   Define a macro for adding & right shifting  **

mult    MACRO   bit             ; Begin macro
	btfsc   PERIOD,bit
	addwf   H_byte,1
	rrf     H_byte,1
	rrf     L_byte,1
	ENDM                    ; End of macro

; *****************************         Begin Multiplier Routine
mpy_F   clrf    H_byte
	clrf    L_byte
	movf    mulcnd,W        ; move the multiplicand to W reg.
	bcf     STATUS,C        ; Clear the carry bit in the status Reg.
	mult    0
	mult    1
	mult    2
	mult    3
	mult    4
	mult    5
	mult    6
	mult    7
	retlw   0

;--initialize all RAM-digital and analog---------------------
;
Ram_init	;***digital*****		
                movlw   0x12            ;why do clocks always start
                movwf   hours           ;at 12:00 ?
                clrf    minutes
                clrf    dot_index
                clrf    digit_index
                movlw   0xFB
                movwf   bigtick_dbl
		movlw	d'5'
		movwf	COUNTER2

		;****analog*******
		movlw	divisor1_val	;initialize DIVISOR1
		movwf	DIVISOR1
		movlw	divisor2_val	;initialize DIVISOR2
		movwf	DIVISOR2
		movlw	zsec_val	;and other timekeeping
		movwf	ZSEC		;counters
		movlw	zmin_val
		movwf	ZMIN
		movlw	d'63'		;1/4 of a revolution of hands	
		movwf	DHOUR		;ensures that hands start at 12:00 position
		movwf	DSEC
		movwf	DMIN

		;****common*****
		clrf	mode
		movlw	debounce_val	;load debouce counters
		movwf	mode_debounce
		movlw	debounce_val2
		movwf	mode_debounce2

              	retlw   0
;-----------------------------------
Port_init       movlw   b'00000000'     ;all are output
                tris    PORTB           
                movlw   b'00001101'     ;porta 0 is index sensor
                tris    PORTA           ;porta 2 is timeset, porta 3 is mode switch
                retlw   0
;-----------------------------------
Timer_init      bcf     INTCON,2        ;clear TMR0 int flag
  	        bsf     INTCON,7        ;enable global interrupts
                bsf     INTCON,5        ;enable TMR0 int
                clrf    TMR0            ;clear timer
                clrwdt                  ;why is this needed? just do it..
                movlw   b'00011000'   	;set up timer. no prescale
					;portb pullups not enabled 
                option                  ;send w to option. generate warning.
                clrf    TMR0            ;start timer
		retlw   0

;------------------------------------
	org 	100 	
;---------------------------------------
;Check_index-  common to all modes
;		
;--------------------------------------
Check_index	btfss	in_bit					
		goto	no_phase
		btfsc	prev_flag
		goto	cont
		bsf	prev_flag
		movf	PERIOD_CNT,w	;make a working copy
		movwf	period_dup	;called period dup	
		clrf	PERIOD_CNT	;a fresh start for next rotation

			
	movf	mode,f
	btfsc	STATUS,Z
	goto	digex		;if mode=0
	movlw	d'1'
	xorwf	mode,w
	btfsc	STATUS,Z
	goto	not_digital		;if mode = 1
	btfss	mode_bit		;mode=2, (demo)
	goto	digex			;if mode=2 and bit clear, do digital
	goto	not_digital
	
digex					;don't need to do the delay if in analog mode
		clrf    digit_index     ;set to first digit
                clrf    dot_index       ;first column
		movlw	OVERHEAD_VAL	;For digital. do one delay 1st. To get colon at the 12:00 position
					;we make delay=1/64 of a revolution. Since display is
					;30 columns wide, putting one delay 1st ensures that
					;the colon is always centered at 12:00
		subwf	PERIOD,W	;W from F, put in W
                call    Delay           ;width of digits with this delay

not_digital

		bcf	flags,4		;clear period count toggle bit. PERIOD_CNT
		goto	cont		;will be incremented on the next interrupt
no_phase	bcf	prev_flag
; calculate a period that does not dither or jitter
; period will not be changed unless new period is really different
cont		movf	PERIOD,W
		subwf	period_dup,W	;find difference
		btfss	STATUS,C	;carry flag set means no borrow
		goto	Calc_neg	;must be other way
		sublw	2		;allowable deviation = 3
		btfss	STATUS,C	;borrow won't skip
		incf	PERIOD,1	;new value much larger than calc
		 retlw	0
Calc_neg	addlw	2		;allowable deviation = 3
		btfss	STATUS,C	;carry will skip
		decf	PERIOD,1	;no carry means it must be change

;cont		movf	period_dup,W
;		movwf	PERIOD

		retlw	0
;-------------------		
;set_analog  for adjusting time
;-------------------
Set_analog
	btfsc	time_set	;input uses pull-up- normally set
	retlw	0		;exit if no magnet near

	decfsz	COUNTER,1	;COUNTER used to take action only every 256 loops
	retlw	0		;this slows down time setting
	
	movlw	d'63'		;reset seconds hand to 12:00 position	
	movwf	DSEC		;
	decf	DMIN,1		;adjust time one minute 
	incfsz	ZMIN,1	    	;this one goes the other way
	retlw	0	    	;if ZMIN rolls, reset it and decrement DHOUR
	movlw	zmin_val
	movwf	ZMIN
	decf	DHOUR,1        
	retlw	0

;****************************************
;---Digital Code--subs below here
;****************************************
;--------
; CHARACTER LOOKUP TABLE
; set=LED off, clear=LED on
;-flipped digits upside down and mirrored

Char_tbl
   	addwf   PCL,f
	dt	0x41	,0x3E	,0x3E	,0x3E,	0x41
	dt	0x7F	,0x7E	,0x0	,0x5E,	0x7F
	dt	0x4E	,0x36	,0x3A	,0x3C,	0x5E
	dt	0x39	,0x16	,0x2E	,0x3E,	0x3D
	dt	0x7B	,0x0	,0x5B	,0x6B,	0x73
	dt	0x31	,0x2E	,0x2E	,0x2E,	0xD
	dt	0x79	,0x36	,0x36	,0x56,	0x61
	dt	0x1F	,0x2F	,0x37	,0x38,	0x3F
	dt	0x49	,0x36	,0x36	,0x36,	0x49
	dt	0x43	,0x35	,0x36	,0x36,	0x4F
	dt	0x7F	,0x7F	,0x49	,0x49,	0x7F	
Char_tbl_end

;--------
; change LED pattern based on state of digit_index and dot_index
;--------
Display_now     movlw   0x05
                xorwf   dot_index,w     ;test for end of digit
                movlw   0xFF            ;pattern for blank column
                btfsc   STATUS,Z
                goto    D_lookup_3      ;it needs a blank
                bcf     STATUS,C        ;clear carry before a rotate
                rlf     digit_index,w   ;double the index because each
		
		bcf	PCLATH,1
		bsf	PCLATH,0

                addwf   PCL,f           ;takes two instructions

D_1min          movf    minutes,w	;DZ-reversed order of display
                goto    D_lookup	;since my motor is counterclockwise
D_10min         swapf   minutes,w
                goto    D_lookup
D_colon         movlw   0x0A
                goto    D_lookup
D_1hr           movf    hours,w
                goto    D_lookup        
D_10hr          swapf   hours,w
                goto    D_lookup        
D_nothing       retlw   0

D_lookup        andlw   b'00001111'     ;strip off hi bits
                movwf   scratch         ;multiply this by 5 for lookup
                addwf   scratch,f       ;table base position
                addwf   scratch,f       ;is this cheating?
                addwf   scratch,f       ;I think not.
                addwf   scratch,f       ;I think it is conserving energy!
                btfss   STATUS,Z        ;test for zero
                goto    D_lookup_2      ;not a zero
		movlw	0x04	       ;-DZ changes for counterclockwise- 10 hours is now digit 5
		xorwf	digit_index,w  ;-if digit 5 is 0, display blank
		movlw   0xFF            ;this makes a blank LED pattern
                btfsc   STATUS,Z        ;test if it is 10 hrs digit
                goto    D_lookup_3      ;it's a trailing zero
D_lookup_2      movf    dot_index,w     ;get column
                addwf   scratch,w       ;add it to digit base

		bcf	PCLATH,1	;set to page 0x100 for lookup
		bsf	PCLATH,0	
                call    Char_tbl        ;get the dot pattern for this column
D_lookup_3      movwf   PORTB           ;send it to the LEDs		
		movlw	OVERHEAD_VAL
		subwf	PERIOD,W	;W from F, put in W
                call    Delay           ;width of digits with this delay
                incf    dot_index,f     ;increment to the next column
                movlw   0x06            ;6 columns is a digit plus space
                xorwf   dot_index,w     ;next digit test
                btfss   STATUS,Z
                retlw   0               ;not a new digit
                clrf    dot_index       ;new digit time
                incf    digit_index,f
                retlw   0               ;Display_now done.
;--------
; a short delay routine
;--------
Delay           movwf   tick
Delay_loop     	nop		       	;added 4 NOPs to increase delay
		nop			;so delay is 8 cycles * tick, or 1/64 of a revolution
		nop			;w is not damaged, so Delay can
		nop			;be recalled without reloading
		nop
		decfsz  tick,f
	        goto    Delay_loop      
                return                  
;--------
; test for magnet and adjust time if needed
;--------    
Set_digital 	btfsc	time_set	;input uses pull-up- normally set
		retlw	0		;exit if no magnet near
		decfsz	COUNTER,1	;COUNTER used to take action only every 256 loops
		retlw	0		;this slows down time setting
		decfsz	COUNTER2,1	;COUNTER2 slows things even more
		retlw	0		
		movlw	d'8'		;adjust to suit for setting speed
		movwf	COUNTER2	;reset COUNTER2 when it rolls
		call	Inc_mins	;got to here, now adjust time
		retlw	0
;--------
; increment one hour
;--------
Inc_hours       movlw   0x12
                xorwf   hours,w
                btfsc   STATUS,Z
                goto    Inc_hours_12
                movlw   0x07            ;this part gets a little sloppy
                addwf   hours,w
                movlw   0x07
                btfss   STATUS,DC
                movlw   1
                addwf   hours,f
                retlw   0
Inc_hours_12    movlw   0x01
                movwf   hours
                retlw   0
;--------
; increment the time based on flags,1 as sent by interrupt routine
; Inc_mins also used by time setting routine
;--------
Keep_time       btfss   flags,1         ;the minutes flag
                retlw   0               ;not this time
                bcf     flags,1         ;clear the minutes flag
Inc_mins        movlw   0x07            ;start incrementing time
                addwf   minutes,w       ;add 7 minutes into w
                btfsc   STATUS,DC       ;did adding 7 cause digit carry?
                goto    Sixty_mins      ;then test for an hour change
                incf    minutes,1        ;otherwise add 1 for real
                retlw   0               ;and go back
Sixty_mins      movwf   minutes         ;save the minutes
                movlw   0x60            ;test for 60
                xorwf   minutes,w       ;are minutes at 60?
                btfss   STATUS,Z
                retlw   0               ;no? go back
                clrf    minutes         ;otherwise zero minutes
                goto    Inc_hours       ;and increment hours

;--------------------
;  check_mode	reads status of the mode switching sensor to increment the mode
;--------------------
check_mode	btfsc	mode_switch
		retlw	0

		movlw	d'1'		;if we are in mode 1(analog), we need more loops
		xorwf	mode,w		;to make mode switch less sensitive since we get here more
		btfsc	STATUS,Z
		goto 	mode1
		goto	not_mode1
mode1		decfsz 	mode_debounce2,1
		retlw	0
		movlw	d'20'
		movwf	mode_debounce2
not_mode1
		decfsz	mode_debounce1,1	; used to take action only every 256 loops
		retlw	0			; this slows down mode switching
		decfsz	mode_debounce,1		; slows things even more
		retlw	0
		incf	mode,1		;increment_mode
		movlw	d'3'		;resetting to 0 if not 0, 1 or 2
		xorwf	mode,w
		btfsc	STATUS,Z	
		clrf 	mode		
		movlw	debounce_val
		movwf	mode_debounce
		retlw 	0

;--------------------
; Program starts here
;--------------------
Start  	      	call    Ram_init        ;set variables to nice values
                call    Port_init       ;set port directions	
		call    Timer_init      ;start timer based interrupt 
;--------------

circle		call    Keep_time	;for digital only, but needs to keep running regardless
		call	check_mode
		movf	mode,f
		btfsc	STATUS,Z
		goto	digital		;if mode=0
		movlw	d'1'
		xorwf	mode,w
		btfsc	STATUS,Z
		goto	analog		;if mode = 1, else mode=2

		btfss	mode_bit
		goto	digital		;case mode=2 and bit clear, do digital
		goto	analog		;else digital

analog		bcf	PORTA,1		;turn on the outer LED for ring effect
		call	Check_index		
		call	Set_analog
		goto	circle

digital 	bsf	PORTA,1		;turn OFF the outer LED (no ring effect)
		bsf	PORTA,4		;turn OFF the inner LEDs
		call    Check_index
                call    Display_now
                call    Set_digital
                goto    circle

                end