; ****************************************
; * Main loop calls all tasks as needed *
; ****************************************
main_loop
CALL task_scan ; Scan the next LED digit.
MOVF TMR0,W ; Place current TMR0 value into W
XORWF PREVTMR0,W ; Lets see which bits have changed...
MOVWF TEMP ; All changed bits are placed in temp for test
XORWF PREVTMR0,F ; Update Previous TMR0 value.
BTFSS SECBIT ; Skip if it is not time to increment second
GOTO main_loop ; Go back to main loop if 250 mS not passed
MOVLW b'00100000' ; Bits 6 and 5 of FLAGS used as divide by 4
ADDWF FLAGS,F ; Add one to bit 5
BTFSS TIMENOW ; Check bit 7 - if four adds occur, skip
GOTO skip_timer ; One second has not passed - skip timers
CALL task_scan ; Scan the next LED digit.
BCF TIMENOW ; Clear out second passed flag
MOVLW CLK_SEC ; Place pointer to increment clock
CALL inc_time ; Increment the clock
CALL check_time ; Check for alarm or timer conditions
BTFSC EGGNOW ; Do NOT decrease timer if zero
GOTO skip_timer ; Jump out if egg timer is zero
BTFSC UPKEY ; Skip if UP key is NOT pressed
GOTO skip_timer ; Jump out if UP key is pressed
BTFSC DOWNKEY ; Skip if DOWN key is NOT pressed
GOTO skip_timer ; Jump out if DOWN key is pressed
MOVLW TMR_SEC_LD ; Place pointer to decrement timer
CALL dec_time ; Decrement countdown timer
MOVLW ALARMCYCCNT ; Place the number of alarm beeps into W
MOVWF ALARMCNT ; Move beep count to ALARMCNT
skip_timer
BTFSS ALARMOK ; Skip if this is the first pass into alarm
GOTO skip_wakeup ; Second pass - do not re-init ALARMCNT
BTFSS ALARMNOW ; Skip if this is alarm pass
GOTO skip_wakeup ; Countdown timer - do not re-init ALARMCNT
MOVLW ALARMCYCCNT ; Place the number of alarm beeps into W
MOVWF ALARMCNT ; Move beep count to ALARMCNT
BCF ALARMOK ; Clear flag for second pass
skip_wakeup
CALL task_scan ; Scan the next LED digit.
BTFSC ALARMNOW ; Skip if alarm clock is not set
GOTO send_alarm ; Blast out a beep
BTFSC EGGNOW ; Skip if countdown timer is not alarming
GOTO send_alarm ; Blast out a beep
GOTO skip_alarm ; Skip beeping and continue
send_alarm
MOVF ALARMCNT,W ; Place ALARMCNT into W
BTFSC STATUS,Z ; Skip if not zero
GOTO skip_alarm ; We are done beeping - skip and continue
DECFSZ ALARMCNT,F ; Decriment beep count and skip when zero
CALL buzz_now ; Blast out the beep!!!
skip_alarm
BTFSS FLAGS,5 ; Skip if it is time to scan the keys 1/2 sec
goto finish_update ; Jump to finish updates - don't scan
CALL scan_keys ; Scan the keys and load value into KEYPAT
CALL task_scan ; Scan the next LED digit.
BTFSS MODEKEY ; Skip if the MODEKEY is pressed
GOTO same_mode ; Not pressed so it is the same mode...
BTFSS MODEKEYCHG ; Skip if the is pressing edge
GOTO same_mode ; Button is held so it is the same mode...
INCF FLAGS,F ; Advance the mode by incrimenting bits 0,1
BCF FLAGS,2 ; Force mode to wrap-around by clearing bit 2
CALL turnon_scan ; Mode button pressed - must turn on LEDs
same_mode
call task_scan ; Scan the next LED digit.
BTFSC UPKEY ; Skip if the UP key is not pressed
GOTO serve_up_key ; UP key is pressed - jump to serve it!
BTFSC DOWNKEY ; Skip if the DOWN key is not pressed
GOTO serve_down_key ; DOWN key is pressed - jump to serve it!
MOVLW INIT_MODE_COUNT ; UP and DOWN not pressed - re-init mode count
MOVWF MODE_COUNT ; Change back to lower digits for setting
MOVF DISPONCNT,F ; Update Z bit in STATUS reg display on time
BTFSS STATUS,Z ; Skip if displays should be OFF
DECF DISPONCNT,F ; Decriment display ON counter
BTFSS STATUS,Z ; Skip if displays should be OFF
GOTO finish_update ; Displays are ON - jump to finish updates
BCF FLAGS,0 ; Restore the mode to displays OFF
BCF FLAGS,1 ; Restore the mode to displays OFF
CLRF PORTB ; Clear out segment drives on PORTB
CLRF PORTA ; Clear out common digit drives on PORTA
GOTO finish_update ; Jump to finish updates
serve_up_key
call task_scan ; Scan the next LED digit.
BTFSC FLAGS,0 ; Skip if not in TIMER or CLOCK mode
GOTO no_up_display ; Currently in TIMER or CLOCK - keep mode
BTFSC FLAGS,1 ; Skip if not in ALARM mode
GOTO no_up_display ; Currently in ALARM - keep mode
BSF FLAGS,0 ; Set to CLOCK mode
BSF FLAGS,1 ; Set to CLOCK mode
no_up_display
CLRF ALARMCNT ; A key was pressed, so turn off alarm
call turnon_scan ; Turn on the LEDs
BTFSS MODEKEY ; Skip if MODE is pressed as well
GOTO finish_update ; MODE is not pressed - jump to finish update
MOVF MODE_COUNT,W ; Update STATUS Z bit for mode count
BTFSS STATUS,Z ; Skip if we have counted down to zero
DECF MODE_COUNT,F ; Decriment the mode count
call task_scan ; Scan the next LED digit.
MOVF MODE_COUNT,W ; Update the Z bit to check for zero
BTFSS STATUS,Z ; Skip if we have incrimented for 7 times
GOTO serve_min_up ; Incriment the minutes digits
DECF FLAGS,W ; Place current mode into W
CALL mode_timer ; Look-up register RAM address for current mode
CALL inc_hour_ld ; Add one hour to the current display
GOTO finish_update ; Jump to finish updates
serve_min_up
call task_scan ; Scan the next LED digit.
DECF FLAGS,W ; Place current mode into W
CALL mode_timer ; Look-up register RAM address for current mode
CALL inc_min_ld ; Add one minute to the current display
GOTO finish_update ; Jump to finish updates
serve_down_key
call task_scan ; Scan the next LED digit.
BTFSC FLAGS,0 ; Skip if not in TIMER or CLOCK mode
GOTO no_dn_display ; Currently in TIMER or CLOCK - keep mode
BTFSC FLAGS,1 ; Skip if not in ALARM mode
GOTO no_dn_display ; Currently in ALARM - keep mode
BSF FLAGS,0 ; Set to CLOCK mode
BSF FLAGS,1 ; Set to CLOCK mode
no_dn_display
CLRF ALARMCNT ; A key was pressed, so turn off alarm
CALL turnon_scan ; Turn on the LEDs
BTFSS MODEKEY ; Skip if MODE is pressed as well
GOTO finish_update ; MODE is not pressed - jump to finish update
MOVF MODE_COUNT,W ; Update STATUS Z bit for mode count
BTFSS STATUS,Z ; Skip if we have counted down to zero
DECF MODE_COUNT,F ; Decriment the mode count
call task_scan ; Scan the next LED digit.
MOVF MODE_COUNT,W ; Update the Z bit to check for zero
BTFSS STATUS,Z ; Skip if we have incrimented for 7 times
GOTO serve_min_down ; Decriment the minutes digits
DECF FLAGS,W ; Place current mode into W
CALL mode_timer ; Look-up register RAM address for current mode
CALL dec_hour_ld ; Subtract one hour from the current display
GOTO finish_update ; Jump to finish updates
serve_min_down
DECF FLAGS,W ; Place current mode into W
CALL mode_timer ; Look-up register RAM address for current mode
CALL dec_min_ld ; Subtract one minute from the current display
finish_update
call task_scan ; Scan the next LED digit.
BTFSC FLAGS,0 ; Skip if in mode OFF or ALARM
GOTO new_display ; Jump to update LED display registers
BTFSC FLAGS,1 ; Skip if in mode OFF
GOTO new_display ; Jump to update LED display registers
CLRF DISPSEGS_A ; Clear display regs to Shut off LED display
CLRF DISPSEGS_B ; Clear display regs to Shut off LED display
CLRF DISPSEGS_C ; Clear display regs to Shut off LED display
CLRF DISPSEGS_D ; Clear display regs to Shut off LED display
GOTO main_loop ; We are done - go back and do it again!
new_display
DECF FLAGS,W ; Move current mode state into W
CALL mode_timer ; Look-up register address of value to display
CALL disp_value ; Update display registers with new values
GOTO main_loop ; We are done - go back and do it again!
; ****************************************
; * Set up and initialize the processor *
; ****************************************
init
MOVLW OPTION_SETUP ; Place option reg setup into W
OPTION ; Set up OPTION register
MOVLW PORTA ; Place beginning of RAM/Port location into W
MOVWF FSR ; Now initialize FSR with this location
clear_mem
CLRF INDADDR ; Clear the FSR pointed memory location
INCFSZ FSR,F ; Point to the next location
GOTO clear_mem ; Jump back to clear memory routine
BSF ALM_HOUR_LD,3 ; Place 8:00 into alarm register
INCF CLK_HOUR_LD,F ; Place 1:00 into clock register
MOVLW 0EEh ; Turn on display A scan line, others off
MOVWF PREVSCAN ;
CLRW
TRIS PORTB ; Make all Port B pins outputs.
TRIS PORTA ; Make all Port A pins outputs.
BSF FLAGS,1 ; Set up current mode to CLOCK, display ON
BSF FLAGS,0
BCF ALARMOK ; Don't want to trigger alarms
BCF EGGOK
BSF DISPON ; Turn on the displays
mfg_checkkey
; CALL scan_keys ; Lets see what is pressed
; BTFSS UPKEY ; Goto self-test if UP key is pressed at pwr up
GOTO main_loop ; Normal operation - Jump to the main loop
; *****************************************************************
; * Self-test code for manufacturing only - test buttons and LEDs *
; *****************************************************************
mfg_selftest
MOVLW b'01110000' ; Place all key on pattern into W
MOVWF CLK_MIN_HD ; Use CLK_MIN_HD for keystuck ON test
CLRF CLK_HOUR_HD ; Use CLK_HOUR_HD for keystuck OFF test
mfg_display
MOVF CLK_SEC,W ; Current segment display count -> W
CALL mfg_led_lookup ; Look-up the next segment pattern to display
MOVWF PORTB ; Move the pattern to PORT B to display it
mfg_timer
MOVF TMR0,W ; Place current TMR0 value into W
XORWF PREVTMR0,W ; Lets see which bits have changed...
MOVWF TEMP ; All changed bits are placed in temp for test
XORWF PREVTMR0,F ; Update Previous TMR0 value.
BTFSS TEMP,7 ; Skip if it is not time to increment second
GOTO mfg_timer ; It is not time to move to next digit - go back
INCF CLK_SEC,F ; Move to the next display pattern
mfg_check_digit
BTFSS CLK_SEC,5 ; Skip if we have timed out waiting for button
GOTO mfg_doneclk ; Jump to check for the next button press
mfg_nextdigit
CLRF CLK_SEC ; Clear out timer
CALL buzz_now ; Send out a buzzer beep!
BTFSS PREVSCAN,3 ; Skip if we have NOT tested the last digit
GOTO finish_mfg_test ; Jump to the end after last digit tested
RLF PREVSCAN,W ; Select the next digit through a rotate..
RLF PREVSCAN,F
MOVF PREVSCAN,W ; Place next digit select into W
MOVWF PORTA ; Update port A to select next digit
mfg_doneclk
CALL scan_keys ; Scan the keys to see what is pressed...
MOVF KEYPAT,W ; Place pattern into W
ANDWF CLK_MIN_HD,F ; Make shure keys are not stuck ON
IORWF CLK_HOUR_HD,F ; Make shure each key is pressed at least once
BTFSS PREVSCAN,3 ; Skip if we are NOT at the last digit
BSF KEYPAT,7 ; Set flag bit to indicate we are done!
MOVLW .8 ; Place 8 into W
SUBWF CLK_SEC,W ; CLK_SEC - W => W
BTFSS STATUS,C
CLRF KEYPAT
SWAPF KEYPAT,F
COMF PREVSCAN,W
ANDWF KEYPAT,W
BTFSS STATUS,Z
GOTO mfg_nextdigit
GOTO mfg_display
finish_mfg_test
MOVF CLK_MIN_HD,F
BTFSS STATUS,Z
GOTO bad_switch
MOVF CLK_HOUR_HD,W
XORLW 070h
BTFSS STATUS,Z
GOTO bad_switch
mfg_cleanup
CLRF CLK_HOUR_HD ; Restore temp registers to zero
CLRF CLK_MIN_HD ; Restore temp registers to zero
GOTO main_loop ; Jump to main loop
bad_switch
COMF CLK_MIN_HD,F
SWAPF CLK_MIN_HD,W
MOVWF KEYPAT
BSF CLK_HOUR_HD,7
SWAPF CLK_HOUR_HD,W
ANDWF KEYPAT,F
MOVLW 07Fh
MOVWF PORTB
CLRF CLK_MIN_LD
BSF CLK_MIN_LD,5
loop_bad_sw
CALL buzz_now_dispon ; Beep the buzzer constantly for a few secs
DECFSZ CLK_MIN_LD,F ; Decriment counter and skip when done
GOTO loop_bad_sw ; Not done buzzing - go back and do it again
GOTO mfg_cleanup ; Done buzzing - clean-up and run clock
END