; Word Clock by Sooty
; Az alap funkciókat osszevagta Tom025
; http://bthamps.extra.hu
; Verzio 1.0

	title "Word Clock"
	list P = 16F628A
	include	<p16f628a.inc> 
	__CONFIG _CP_OFF & _XT_OSC & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _BODEN_OFF & _LVP_OFF
	errorlevel	-302		; no bank select message


;****** Variables ***************************************************
	cblock	0x20 	; pic16f628 compatibile 
	
; Variables for delay loop
teller		
teller2	        

; Variables for time-keeping
sece			; Second units
sect			; Second tens
mine			; Minute units
mint			; Minute tens
hre				; Hour units
hrt				; Hour tens

; Variables for the one second timer
bres_hi			; hi byte of our 24bit variable
bres_mid		; mid byte
bres_lo			; lo byte

; Variables to save register statusses during interrupt
temp_s		
temp_w		

; Variables for debouncing and inputs
bounce_timer		; Counter for the debounce routine
csa	
cva		
count_A		
count_B		
prev_val	

; Variables for word conversion
tar1		
nov			
tarh		
dat		
dat2
plu
ten	
	endc
		GOTO init
                ORG	0x4		; Choose starting adress

; Interrupt routine. This is called every 256 instructions.
isr		MOVWF	temp_w          ; save w register
          	MOVF	STATUS, W       ; W = STATUS
          	MOVWF	temp_s          ; save STATUS register
          	
          	; First, see if we need to call the debouncing routine
          	; We don't call the debouncing routine every interrupt, but every 10
          	;   interrupts. That's once every 2560 instructions. Because an input needs
          	;   to be the same for 4 consecutive calls to the debouncing routine, it
          	;   needs to be the same for roughly 0.01 seconds.
          	DECFSZ	bounce_timer, f	; Decrement bounce_timer, see if it's 0
		GOTO 	bookkeeping	; Not 0, skip the debouncing routine
		
		MOVLW	009h		; Bounce_timer == 0
		MOVWF	bounce_timer	; Reset bounce_timer to 9
		
		CALL	read_inputs
		CALL	debounce
		CALL	process_inputs

          	; Here comes the bookkeeping for the timer routine
bookkeeping	TSTF bres_mid		; first test for mid==0
		SKPNZ			; nz = no underflow needed
		DECF bres_hi,f		; z, so is underflow, so dec the msb

		DECFSZ bres_mid,f	; dec the mid byte (subtract 256)
		GOTO end_isr		; nz, so definitely not one second yet.

		TSTF bres_hi		; test hi for zero too
		SKPZ			; z = both hi and mid are zero, is one second!
		GOTO end_isr		; nz, so not one second yet.

		MOVLW 0x0F		; get msb value 
		MOVWF bres_hi		; load in msb
		MOVLW 0x42		; get mid value
		MOVWF bres_mid		; load in mid
		MOVLW 0x40		; lsb value to add
		ADDWF bres_lo,f		; add it to the remainder already in lsb
		SKPNC			; nc = no overflow, so mid is still ok

		INCF bres_mid,f		; c, so lsb overflowed, so inc mid

          	CALL continue		; A second has passed, increase the second count  
		CALL geteepromdata      ; get data from eeprom for a new output.    	
          	
		; End of the interrupt routine
end_isr        	BCF	INTCON, T0IF	; clear the TMR0 flag bit
		MOVF	temp_s, W	; Put STATUS and W back where they belong
          	MOVWF	STATUS
          	SWAPF	temp_w, F
          	SWAPF	temp_w, W
          	RETFIE			; Return from interrupt


; Initialisation routine
init		BSF 	STATUS,5	; Choose bank 1
		CLRF	TRISA		; All pins of port A are outputs
		CLRF	TRISB		; All pins of port B are outputs...
		BSF	TRISA, 4
		BSF	TRISA, 5	; ...except for the last two
		MOVLW	b'10001000'	; Set the options (prescaler for watchdog timer)
		MOVWF	OPTION_REG
	        BCF 	STATUS,5	; Choose bank 0

		CALL initial_vals	; Set initial values
		
		MOVLW 0x0F		; get msb value 
		MOVWF bres_hi		; put in hi
		MOVLW 0x42 +1		; get mid value (note we added 1 to it)
		MOVWF bres_mid		; put in mid
		MOVLW 0x40		; get lsb value
		MOVWF bres_lo		; put in mid
		
		CLRF	INTCON
		BSF	INTCON, T0IE
		BSF	INTCON, GIE	; Set Timer interrupt

; Routine to show the numbers on the display
shownumbers		
		
				
		movf 	dat2,w
		movwf 	PORTA
		
		btfsc 	dat2,4
		bsf		dat,7		; Set the ten's bit
		btfss 	dat2,4
		bcf		dat,7		; Clear the ten's bit

		movf 	dat,w
		MOVWF	PORTB		; Set the minute LEDs
	
		CALL delay

		GOTO shownumbers	; Just keep on showing those numbers -- the
					;   rest of the functionality is called from the interrupt
					;   routine.

; This routine is called whenever a second has passed.
continue			
		INCF	sece, 1		; Increase sece
		MOVF	sece, w
		ADDLW	0F6h		; sece > 9?
		SKPNC
		GOTO overflow_sece	; sece == 10, so increment sect
		RETURN

overflow_sece	CLRF	sece		; Set sece back to 0
		INCF	sect, 1		; Increase sect with 1
		MOVF	sect, w
		ADDLW	0FAh		; sect > 5?
		SKPNC
		GOTO overflow_sect	; sect == 5, so increment mine
		RETURN

overflow_sect	CLRF	sect		; Set sect back to 0
		CLRF	sece
		INCF	mine, 1		; Increase mine
		MOVF	mine, w
		ADDLW	0F6h		; mine > 9?
		SKPNC
		GOTO overflow_mine	; mine == 10, so increment sect
		RETURN

overflow_mine	CLRF	mine		; Set mine back to 0
		INCF	mint, 1		; Increase mint
		MOVF	mint, w
		ADDLW	0FAh		; mint > 5?
		SKPNC
		GOTO overflow_mint	; mint == 5, so increment hre
		RETURN

overflow_mint	CLRF	mint		; Reset mint to 0
incr_hre	INCF	hre, 1		; Increase hre
		MOVF	hre, w
		ADDLW	0FCh		; hre > 4?
		SKPNC
		GOTO check_hre		; hre > 4, so we need to check whether we need
					;   to overflow hrt
		RETURN

check_hre	MOVF	hrt, w
		ADDLW	0FEh		; hrt > 1?
		SKPNC
		GOTO	overflow_hre	; hrt == 2, hre == 5 -> overflow!
		MOVF	hre, w		; hrt == 1
		ADDLW	0F6h		; hre > 9?
		SKPNC
		GOTO overflow_hre	; hrt == 1, hre == 10 -> overflow!
		RETURN

overflow_hre	CLRF	hre		; Reset hre to 0
		INCF	hrt, 1		; Increase hrt
		MOVF	hrt, w
		ADDLW	0FDh		; hrt > 2?
		SKPNC
		GOTO overflow_hrt	; hrt == 2; overflow hrt (it's midnight!)
		RETURN

overflow_hrt	CLRF	sece		; Midnight, reset everything to 0!
		CLRF	sect
		CLRF	mine
		CLRF	mint
		CLRF	hre
		CLRF	hrt
		RETURN

; Sets the initial values. We start 9 seconds before midnight!
initial_vals	
				
		MOVLW	001h
		MOVWF	sece
		CLRF	sect
		CLRF	mine
		CLRF	mint
		CLRF	hre
		CLRF	hrt
		MOVLW	005h
		MOVWF	sect
		MOVLW	009h
		MOVWF	mine
		MOVLW	005h
		MOVWF	mint
		MOVLW	003h
		MOVWF	hre
		MOVLW	002h
		MOVWF	hrt
		; Also, set the variables for the counters etc.
		MOVLW	009h
		MOVWF	bounce_timer
		CLRF	csa
		CLRF	cva
		CLRF	count_A
		CLRF	count_B
		CLRF	prev_val
		RETURN

; Our delay loop. Waits roughly 1000 instructions, that's 1 msec
delay					
		MOVLW	00Ah		;10 times...
		MOVWF	teller
outerloop	MOVLW	064h		;100 times...
		MOVWF	teller2
innerloop	DECFSZ	teller2, 1
		GOTO innerloop
		DECFSZ	teller, 1
		GOTO outerloop
		RETURN

; Read the inputs
read_inputs	
		; Check minute pin, sets the appropriate bit in the csa variable
		BTFSC	PORTA, 4
		GOTO	minute_een
minute_nul	BCF	csa, 0
		GOTO	einde_minute
minute_een	BSF	csa, 0
einde_minute

		; Check hour pin, sets the appropriate bit in the csa variable
		BTFSC	PORTA, 5
		GOTO	hour_een
hour_nul	BCF	csa, 1
		GOTO	einde_hour
hour_een	BSF	csa, 1
einde_hour	RETURN

; Debounce routine
debounce
		;Increment the vertical counter
		MOVF    count_B,W
		XORWF   count_A,F
		COMF    count_B,F

		;See if any changes occurred
		MOVF    csa,W
		XORWF   cva,W

		;Reset the counter if no change has occurred
		ANDWF   count_B,F
		ANDWF   count_A,F

		;Determine the counter's state
		MOVF    count_B,W
		IORWF   count_A,W

		;Clear all bits that are filtered-or more accurately, save
		;the state of those that are being filtered
		ANDWF   cva,F
		XORLW   0xff

		;Re-write the bits that haven't changed.
		ANDWF   csa,W
		IORWF   cva,F

		RETURN

; Process the debounced inputs
; We have two variables to work with: prev_val, which contains the previous (debounced) states of the inputs;
;   and cva, the debounced current state of the inputs.
; Each input is set as a bit in both the variables.
process_inputs
		; Check the previous value of the minute-input
		BTFSS	prev_val, 0
		GOTO	minute_was_zero
minute_was_one	BTFSS	cva, 0
		BCF	prev_val, 0	; from 1 to 0 -> reset prev_val to 0
		GOTO	check_hour
minute_was_zero	BTFSC	cva, 0
		GOTO	minute_press
		GOTO	check_hour
minute_press	BSF	prev_val, 0
		CALL	overflow_sect	; from 0 to 1 -> tick!
		call 	geteepromdata
check_hour	; Check the previous value of the hour input
		BTFSS	prev_val, 1
		GOTO	hour_was_zero
hour_was_one	BTFSS	cva, 1
		BCF	prev_val, 1	; from 1 to 0 -> reset prev_val to 0
		RETURN
hour_was_zero	BTFSC	cva, 1
		GOTO	hour_press
		RETURN
hour_press	BSF	prev_val, 1
		CALL	incr_hre	; from 0 to 1 -> tick!
		call 	geteepromdata
		RETURN

getdata1				;minute dependent data from eeprom
		movf tar1,w
		BSF STATUS, RP0 ; Bank 1
		MOVWF EEADR ; Address to read
		BSF EECON1, RD ; EE Read
		MOVF EEDATA, W ; W = EEDATA
		BCF STATUS, RP0 ; Bank 0
		movwf dat
		return

getdata2				;hour dependent data from eeprom
		movf tar1,w
		ADDLW	0F6h		; tar1 > 9?
		SKPNC
		call	plus1h ;plus 1 hour
		
		movf tarh,w
		BSF STATUS, RP0 ; Bank 1
		MOVWF EEADR ; Address to read
		BSF EECON1, RD ; EE Read
		MOVF EEDATA, W ; W = EEDATA
		BCF STATUS, RP0 ; Bank 0
		movwf dat2
		return

plus1h					; +1 hour after 10 minutes (negyed n+1 óra lesz 5 perc mulva )
		movf tarh,w
		ADDLW	001h
		movwf tarh		
		return

geteepromdata

		MOVLW	000h 		; Get data from eeprom 
		movwf	nov
		movwf	tar1
		MOVF	mint,w		; Load min tens into W
		movwf	tar1
		movwf	nov
		movf	tar1,w		;10 times (mint x 10)
		addwf	nov,w			
		addwf	nov,w	
		addwf	nov,w	
		addwf	nov,w	
		addwf	nov,w	
		addwf	nov,w	
		addwf	nov,w	
		addwf	nov,w
		addwf	nov,w		
		addwf	mine,w
		movwf 	tar1

		call getdata1

			
		MOVLW	000h 
		movwf	nov
		MOVLW	000h 
		movwf	tarh
		MOVF	hrt,w		; Load hour tens into W
		movwf	tarh
		movwf	nov
		movf	tarh,w		;10 times (hrt x 10)
		addwf	nov,w
		addwf	nov,w
		addwf	nov,w
		addwf	nov,w
		addwf	nov,w
		addwf	nov,w		
		addwf	nov,w
		addwf	nov,w
		addwf	nov,w
		addwf	hre,w
		addlw	040h
		movwf 	tarh
		
		call getdata2
		
		return


; Fill up the built in EEPROM
	org 0x02100
	de	.8,.8,.8,.8,.8,.88,.88,.88,.88,.88,.50,.50,.50,.50,.50,.2,.2,.2,.2,.2
	de .82,.82,.82,.82,.82,.52,.52,.52,.52,.52,.4,.4,.4,.4,.4,.84,.84,.84,.84,.84
	de .51,.51,.51,.51,.51,.3,.3,.3,.3,.3,.83,.83,.83,.83,.83,.56,.56,.56,.56,.56,.0,.0,.0,.0
	de	.18,.1,.2,.3,.4,.5,.6,.7,.8,.9,.0,.17,.18,.1,.2,.3,.4,.5,.6,.7,.8,.9,.0,.17,.18



	END


