;----------------------------------------------------------------------;
; EGGTIM4M.ASM A 3 minute countdown timer for boiling eggs, 4 MHz osc;
; Pushbutton on RB4 starts countdown. Displays minutes and tens of ;
; seconds in binary on LEDs. Zero represented by all leds lit. ;
; A second pushbutton can be added to cycle through starting times. ;
;----------------------------------------------------------------------;
; .-----------.
; -|RA2 RA1|- V+ = 4.5 or 5 Volts
; -|RA3 RA0|- X = 4 MHz cer. res.
; -|RA4 OSC1|--|X|___ gnd
; -{r}- = 470 ohm V+ ---|MCLR OSC2|--|X|
; -|<- = LED gnd ---|Vss Vdd|--- V+
; gnd ---|<--{r}--|RB0 RB7|-
; gnd ---|<--{r}--|RB1 RB6|-
; gnd ---|<--{r}--|RB2 RB5|---[PB]--- gnd
; gnd ---|<--{r}--|RB3 RB4|---[PB]--- gnd
; '-----------'
; PIC16F84 -[PB]- pushbutton
LIST P=16F84 ; tells which processor is used
INCLUDE "p16f84.inc" ; defines various registers etc. Look
ERRORLEVEL -224 ; suppress annoying message from tris
__CONFIG _PWRTE_ON & _XT_OSC & _WDT_OFF ; config. switches
#DEFINE button1 PORTB, 4 ; RB4 pushbutton to ground
#DEFINE button2 PORTB, 5 ; RB5 pushbutton to ground
;----------------------------------------------------------------------;
; Here we set up the user defined registers ;
;----------------------------------------------------------------------;
CBLOCK H'0C' ; first free register address is 12
sec ; keeps track of seconds
sec10 ; keeps track of tens of seconds
mins ; keeps track of minutes
cntmsec ; counter used in millisecond delays
counter ; general counter
ENDC
ORG 0 ; start a program memory location zero
goto main ; jump over the interrupt routine
;----------------------------------------------------------------------;
; initialize the ports, set up interrupts etc: ;
;----------------------------------------------------------------------;
init:
movlw B'00000000' ; all outputs
tris PORTA ; on PORT A
movlw B'00110000' ; RB4 & RB5 inputs, all others outputs
tris PORTB ; on PORT B
movlw B'00000000' ; port B pull-ups active
option
clrf sec ; sec = 0
clrf sec10 ; sec10 = 0
movlw D'3' ; and minutes = 3
movwf mins
movlw D'10' ; initialize counter to 10
movwf counter
return
;----------------------------------------------------------------------;
; Wait for pushbutton. Start countdown when pressed. ;
;----------------------------------------------------------------------;
waitpushbutton:
movf mins, W ; display minutes on LEDs at start
movwf PORTB
; to add a pushbutton on RB5 to select starting minutes uncomment the
; next two instructions
; btfss button2 ; button2 pressed? skip if not
; call selectstart ; select starting number of mins 1-16
btfsc button1 ; switch closed, (gives 0)?
goto waitpushbutton ; not yet
; switch has been detected closed
; ( no debounce necessary )
clrf PORTB ; lights out
return
;----------------------------------------------------------------------;
; Select the starting number of minutes 1-15 ;
;----------------------------------------------------------------------;
selectstart:
incf mins, W ; increment minutes
andlw H'0F' ; limit to 15
movwf mins ; store in mins
waitup:
movlw 10 ; delay for 10 msec (debounce press)
call nmsec
btfss button2 ; button 2 up yet?
goto waitup ; no, keep checking
return
;----------------------------------------------------------------------;
; This is the main program ;
;----------------------------------------------------------------------;
main:
call init ; set up ports, initialize registers
call waitpushbutton ; wait for button to be pressed
loop:
decfsz counter, f ; show time every tenth time
goto $ +2 ; skip over next instruction
goto showtime ; display time, (lasts 1 sec)
call onesecond ; delay for one second
nextsec:
decf sec, f ; down one sec
movlw H'FF' ; check for underflow
subwf sec, W ; will give zero if underflow
btfss STATUS, Z ; skip if underflow
goto loop ; else continue
movlw D'9' ; sec to 9
movwf sec
decf sec10, f ; same for sec10 register
movlw H'FF' ; check for underflow
subwf sec10, W ; gives zero if underflow
btfss STATUS, Z ; skip if underflow
goto loop ; else continue
movlw D'5' ; sec10 to 5
movwf sec10
decf mins, f ; now minutes
movlw H'FF' ; check for underflow
subwf mins, W ; gives zero if underflow
btfss STATUS, Z ; skip if underflow
goto loop ; else continue
; come here when the countdown is over
finished:
movlw H'0F' ; turn on all leds indicating finish
movwf PORTB
movlw D'40' ; wait for 10 seconds
movwf counter
call msec250 ; 1/4 sec delay
decfsz counter, f ; finished?
goto $ -2 ; not yet
goto main ; start all over again
showtime: ; this lasts approximately one second
; usec instructions are insignificant compared to 100's of msec
movf mins, W ; display minutes
btfsc STATUS, Z ; skip if not zero
movlw H'0F' ; else all LEDs on
movwf PORTB ; turn on LEDs
call msec250 ; on for 400 msec
movlw D'150'
call nmsec
clrf PORTB ; blank briefly
movlw D'200'
call nmsec
movf sec10, W ; now the same with sec10
btfsc STATUS, Z ; skip if not zero
movlw H'0F' ; else all LEDs on
movwf PORTB ; show 10's of seconds
call msec250 ; on for 400 msec
movlw D'150'
call nmsec
clrf PORTB ; blank
movlw D'10' ; reset counter to 10
movwf counter
goto nextsec
;----------------------------------------------------------------------;
; time delay routines ;
;----------------------------------------------------------------------;
micro4 addlw H'FF' ; subtract 1 from 'W'
btfss STATUS,Z ; skip when you reach zero
goto micro4 ; more loops
return
;*** N millisecond delay routine ***
msec250: movlw D'250' ; 250 millisecond delay
nmsec: movwf cntmsec ; delay for N (in W) millisec
msecloop: movlw D'248' ; 1 usec for load
call micro4 ; this instruction is 995 usec
nop ; 1 usec
decfsz cntmsec,f ; 1 usec, (2 if skip taken)
goto msecloop ; 2 usec, loop = 995+5 = 1 msec
return
onesecond: call msec250 ; delay for one second
call msec250
call msec250
call msec250
return
end ; end of program
; Note: This program differs from eggtimer.asm (used a 32 kHz xtal).
; That program has errors due to subtitle interaction of the isr and main
; program. The easiest fix is do not use a interrupt subroutine.