#include <P16F690.INC>
 __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)

 k1 equ 20   ;assign memory addresses for k1
 k2 equ 21   ;assign memory addresses for k2
 k3 equ 22   ;assign memory addresses for k3
 dum equ 23  ;dummy variable
 dum2 equ 24  ;dummy for saving status reg
 sec equ 25
 min equ 26

 org 00

 goto Start
  org 04
  goto INT_ROUTINE

Start
 bcf   STATUS,RP0  ; select bank0
 bsf   STATUS,RP1  ; select bank 2
 clrf  ANSEL   ; make portA digital
 bcf   STATUS,RP1
 bsf   STATUS,RP0  ;select bank 1
 clrf  TRISC     ; make PORTC pins all output
 clrf  TRISA     ; make all pins in portA output (except ra3)
 movlw b'10000000'
 movwf  TRISB      ; make  pin 7 input, and 4, 5 and 6 output on portb
 bcf STATUS,RP0  ; select bank 0
 movlw b'10100000' ; enables trm0 interupt
 movwf INTCON 
 bsf STATUS,RP0; sets bank 1
 movlw b'00000000'
 movwf OPTION_REG; fastest timer rate
 bcf STATUS,RP0; set bank 0
 movwf k1   ; start k1 at 0
 movwf k2   ; start k2 at 0
 movwf k3   ; start k3 at 0
 movwf TMR0 ; reset timer0  
 movlw b'00000001'
 movwf  min       ; set minutes equal to 1 min
 call minout
 clrf  sec
 call secout
 bcf PORTB,RB6  ; buzzer off

loop
 call delay1  ; delay around one second
 incf sec     ; increase the seconds
 call secout  ; output the number of seconds on led's 
 movlw b'00011110'
 subwf sec,w    ; check if 30 seconds have elapsed
 btfss STATUS,Z
 goto loop     ; if false then go back and add another second
loop1
 call delay1  ; if true delay around one sec
 decf sec     ; and decrease the seconds back to zero
 call secout
 movlw b'00000000'
 subwf sec,w   ; check if the seconds are back to zero
 btfss STATUS,Z
 goto loop1    ; if false then go back and subtract another second
 call cdown    ; if true subtract a minute
 goto loop

cdown
 decf min  ; decrease the minutes by 1
 call minout
 movlw b'00000000'
 subwf min,w   ; check if the minutes have reached zero
 btfsc STATUS,Z
 call buzzer  ; if true then call buzzer
 return        ; if false then go back to seconds loop

minout  ; outputs the number of minutes left
 btfsc min,0
 bsf PORTA,RA0
 btfss min,0
 bcf PORTA,RA0
 btfsc min,1
 bsf PORTA,RA1
 btfss min,1
 bcf PORTA,RA1
 btfsc min,2
 bsf PORTA,RA2
 btfss min,2
 bcf PORTA,RA2
 btfsc min,3
 bsf PORTC,RC0
 btfss min,3
 bcf PORTC,RC0
 btfsc min,4
 bsf PORTC,RC1
 btfss min,4
 bcf PORTC,RC1
 btfsc min,5
 bsf PORTC,RC2
 btfss min,5
 bcf PORTC,RC2
 return

secout  ; outputs the number of seconds
 btfsc sec,0
 bsf PORTA,RA5
 btfss sec,0
 bcf PORTA,RA5
 btfsc sec,1
 bsf PORTA,RA4
 btfss sec,1
 bcf PORTA,RA4
 btfsc sec,2
 bsf PORTC,RC5
 btfss sec,2
 bcf PORTC,RC5
 btfsc sec,3
 bsf PORTC,RC4
 btfss sec,3
 bcf PORTC,RC4
 btfsc sec,4
 bsf PORTC,RC3
 btfss sec,4
 bcf PORTC,RC3
 return

buzzer
loopf
 bsf PORTB,RB6  ; piezo pressure on
 call delay2  ; delay around 128 microsec (for 4 kHz)
 bcf PORTB,RB6  ; piezo pressure off
 call delay2  ; delay around 128 microsec
 goto loopf
 return

delay1
 bcf STATUS,RP0
lc1
 btfss PORTB,RB7   ; checks if button is pressed to add a minute
 call set1
 movlw b'00000111' ; the number 7
 subwf k2,w    ; subtract w from k2
 btfss STATUS,Z  ;check if k2 has reached 7
 goto lc1
lc2
 movlw b'10100001' ; the number 161 to count to 499968
 subwf k1,w   ; subtract w from k1
 btfss STATUS,Z  ;check if k1 has reached 161
 goto lc2
 CLRF k2  ; reset k2
 CLRF k1  ; reset k1
 movlw b'00000000'
 movwf TMR0 ; reset timer0
 return

delay2
 bcf STATUS,RP0
 movlw b'00000000'
 movwf TMR0 ; reset timer0
lc3
 btfss PORTB,RB7   ; checks if button is pressed to add a minute
 call set1
 movlw b'01000000'  ; the number 64 (times 2 = 128 microsec)
 subwf TMR0,w    ; subtract w from tmr0
 btfss STATUS,C  ;check if tmr0 has reached exceeded 64
 goto lc3
 return

set1   ; adds a minute when button is pressed
 incf min
 bcf PORTB,RB6  ; buzzer off
 CLRF k2
lc4
 movlw b'00000011'  ; delay for around 3/7 of a sec
 subwf k2,w    ; subtract w from k2
 btfss STATUS,Z  ;check if k2 has reached 3
 goto lc4
 CLRF sec
 CLRF k2
 CLRF k1
 movlw b'00000000'
 movwf TMR0 ; reset timer0
 call secout
 call minout
 goto loop
 return

INT_ROUTINE
   movwf dum ;save W
   movf STATUS, W ;save Status in W
   bcf STATUS,RP0 ;set bank 0
   movwf dum2   ;save status in dum2
   movlw b'11111111'
   subwf k1,W   ;subtract k1
   btfsc STATUS,Z  ;see if k1=255
   goto minute
   goto hour
minute
   movlw b'11111111'
   subwf k2,W   ;subtract k2
   btfsc STATUS,Z  ;see of k2=255
   incf k3,1
   incf k2,1  ;increment k2
hour  incf k1,1
   movf dum2, W ;returning Status to original value
   movwf STATUS
   movf dum,W ; returning dum to W
   bcf INTCON,T0IF
   retfie
 end

