; darkroom enlarger timer based on the PIC 16C84 ; three seven-segment displays driven by a 7447, ; multiplexed ; time measured with TMR0 interrupts pc equ 02 ; program counter ; our registers save_w equ 0x0D ; for saving w save_s equ 0x0E ; for saving status ; minute equ 0x10 ; current minute value tensec equ 0x11 ; current tens of seconds second equ 0x12 ; current seconds minset equ 0x13 ; minutes set tenset equ 0x14 ; ten seconds set secset equ 0x15 ; seconds set ; count equ 0x16 ; tmr0 overflow count #define factor .61 ; how many times/sec should tmr0 overflow dlcount equ 0x17 ; delay counter ; myflags equ 0x18 ; various flags #define secsf myflags,0 ; doing seconds flag #define tensf myflags,1 ; doing tens flag #define minsf myflags,2 ; doing minutes flag #define zerof myflags,3 ; zero time flag #define dobeepf myflags,4 ; should we beep? #define dolongf myflags,5 ; should we beep? ; oidx equ 4 ; which bit is on/off button? sidx equ 5 ; which bit is minutes button? tidx equ 6 ; which bit is tens button? midx equ 7 ; which bit is seconds button? #define relport porta,0 ; relay is porta,0 #define secport porta,1 ; seconds is porta,1 #define tenport porta,3 ; ten seconds is porta,3 #define minport porta,2 ; minutes is porta,2 #define obport porta,oidx ; start/stop is porta,4 #define mbport portb,midx ; minutes set is portb,5 #define tbport portb,tidx ; tens set is portb,6 #define sbport portb,sidx ; seconds set is portb,7 #define amask b'00010000' ; mask for port a buttons #define bmask b'11100000' ; mask for port b buttons #define omask b'00010000' ; mask for on/off button #define mmask b'00100000' ; mask for minutes button #define tmask b'01000000' ; mask for tens button #define smask b'10000000' ; mask for seconds button ; temp1 equ 0x19 ; general purpose counter temp2 equ 0x1a ; general purpose counter temp3 equ 0x1b ; general purpose counter ; stuff for button scan #define dbcount .10 ; how many times should debounce be checked mdbcnt equ 0x1c ; minutes button debounce counter tdbcnt equ 0x1d ; tens button debounce counter sdbcnt equ 0x1e ; seconds button debounce counter odbcnt equ 0x1f ; on/off button debounce counter now equ 0x21 ; current key settings dbing equ 0x22 ; are we debouncing? steady equ 0x23 ; on if didn't change value equ 0x24 ; current debounced value prev equ 0x25 ; previous debounced value changed equ 0x26 ; on if debounced value changed ; -------------------------------------------- ; normal entry point org 0 call init call reset goto loop ; -------------------------------------------- ; interrupt routine org 0x04 movwf save_w ; save w and status swapf status,w movwf save_s ; do the work here - check where interrupt comes from ; just to be safe, even though we only enable the timer btfss intcon,t0if goto out ; now handle tmr0 overflow bcf intcon,t0if ; clear tmr0 flag clrf tmr0 decfsz count goto out bsf dobeepf movlw factor ; delay factor movwf count movf second,f ; test for zero btfsc status,z goto decten ; zero seconds decf second,f movf second,f ; see if we have zeroes btfss status,z goto out movf tensec,f btfss status,z goto out movf minute,f btfss status,z goto out goto finish decten movlw 9 movwf second movf tensec,f btfsc status,z goto decmin ; zero tens decf tensec,f goto out decmin movlw 5 movwf tensec movf minute,f btfsc status,z goto finish ; zero minutes, should never happen decf minute,f goto out finish ; reset the display call distmr bcf relport ; shut off the relay bsf dolongf movf minset,w movwf minute movf tenset,w movwf tensec movf secset,w movwf second goto out out swapf save_s,w ; restore status and w movwf status swapf save_w,f swapf save_w,w retfie ; -------------------------------------------- beep ; send square wave into rb4 movlw .20 movwf temp1 bloop bcf portb,4 call delay2 bsf portb,4 call delay2 decfsz temp1 goto bloop return ; -------------------------------------------- dlybeep ; keep silent movlw .22 movwf temp1 dbloop nop call delay2 nop call delay2 decfsz temp1 goto dbloop return ; -------------------------------------------- longbeep ; send square wave into rb4 movlw .250 movwf temp1 lbloop bcf portb,4 call delay2 bsf portb,4 call delay2 decfsz temp1 goto lbloop return ; -------------------------------------------- delay movwf dlcount dl_loop decfsz dlcount,f goto dl_loop ; w is not changed, so delay can return ; be recalled without reloading ; -------------------------------------------- sdelay movlw .5 movwf temp2 dl_s call delay2 decfsz temp2 goto dl_s retlw 0 ; -------------------------------------------- sdelay1 movlw .10 movwf temp2 dl_s1 call delay2 decfsz temp2 goto dl_s1 retlw 0 ; -------------------------------------------- delay1 movlw .25 movwf temp2 dl_1 call delay2 decfsz temp2 goto dl_1 retlw 0 ; -------------------------------------------- delay2 movlw .40 movwf temp3 dl_2 decfsz temp3 goto dl_2 retlw 0 ; -------------------------------------------- setdisplay addwf pc ; return into W the right retlw 0x00 ; set of segments (-BCD) retlw 0x01 ; to be turned on retlw 0x08 retlw 0x09 retlw 0x04 retlw 0x05 retlw 0x0c retlw 0x0d retlw 0x02 retlw 0x03 ; -------------------------------------------- distmr bcf intcon,t0ie ; disable tmr0 btfsc intcon,t0ie goto distmr bcf intcon,t0if ; clear tmr0 flag clrf tmr0 return ; -------------------------------------------- scanbtns movf value,w ; save old values movwf prev movlw amask ; mask for port a andwf porta,w ; we go to this trouble because movwf now ; the buttons are on different ports movlw bmask ; mask for port b andwf portb,w xorwf now,f ; we should have all four in now ; on/off button btfsc dbing,oidx goto odb ; just wait movf value,w ; see if changed xorwf now,w ; we have diffs andlw omask btfsc status,z ; since bit test w doesn't work... goto mscan ; no change bsf dbing,oidx ; set debouncing flag movlw dbcount movwf odbcnt ; loaded the counter goto mscan odb decfsz odbcnt ; did we reach zero? goto mscan ; no bcf dbing,oidx movf now,w ; check if still different value xorwf value,w andlw omask btfsc status,z goto mscan ; no change, do nothing movlw omask xorwf value,f ; toggle oidx bit ; mscan ; minutes button btfsc dbing,midx goto mdb ; just wait movf value,w ; see if changed xorwf now,w ; we have diffs andlw mmask btfsc status,z ; since bit test w doesn't work... goto tscan ; no change bsf dbing,midx ; set debouncing flag movlw dbcount movwf mdbcnt ; loaded the counter goto tscan mdb decfsz mdbcnt ; did we reach zero? goto tscan ; no bcf dbing,midx movf now,w ; check if still different value xorwf value,w andlw mmask btfsc status,z goto tscan ; no change, do nothing movlw mmask xorwf value,f ; toggle oidx bit ; tscan ; tens button btfsc dbing,tidx goto tdb ; just wait movf value,w ; see if changed xorwf now,w ; we have diffs andlw tmask btfsc status,z ; since bit test w doesn't work... goto sscan ; no change bsf dbing,tidx ; set debouncing flag movlw dbcount movwf tdbcnt ; loaded the counter goto sscan tdb decfsz tdbcnt ; did we reach zero? goto sscan ; no bcf dbing,tidx movf now,w ; check if still different value xorwf value,w andlw tmask btfsc status,z goto sscan ; no change, do nothing movlw tmask xorwf value,f ; toggle oidx bit ; sscan ; seconds button btfsc dbing,sidx goto sdb ; just wait movf value,w ; see if changed xorwf now,w ; we have diffs andlw smask btfsc status,z ; since bit test w doesn't work... goto scandone ; no change bsf dbing,sidx ; set debouncing flag movlw dbcount movwf sdbcnt ; loaded the counter goto scandone sdb decfsz sdbcnt ; did we reach zero? goto scandone ; no bcf dbing,sidx movf now,w ; check if still different value xorwf value,w andlw smask btfsc status,z goto scandone ; no change, do nothing movlw smask xorwf value,f ; toggle oidx bit ; scandone ; set up the changed flags movf prev,w ; find debounced delta xorwf value,w iorwf changed,f ; clear these in the main loop! return ; -------------------------------------------- loop ; the main display loop ; call sdelay ; strobe delay, let it shine! btfsc dobeepf ; should we beep? goto bp call dlybeep goto btns bp bcf dobeepf btfsc dolongf ; long or normal? goto lbp call beep goto btns lbp bcf dolongf call longbeep ; btns call scanbtns ; get the keypress values btfss changed,oidx goto chkm bcf changed,oidx btfsc value,oidx ; ports are normally on! goto displ btfsc intcon,t0ie ; on/off pressed goto stop call starttmr goto displ stop call reset goto displ ; chkm btfss changed,midx goto chkt bcf changed,midx btfsc value,midx ; ports are normally on! goto chkt btfss intcon,t0ie ; is timer running? call incmins goto chkt ; chkt btfss changed,tidx goto chks bcf changed,tidx btfsc value,tidx ; ports are normally on! goto chks btfss intcon,t0ie ; is timer running? call inctens goto chks ; chks btfss changed,sidx goto displ bcf changed,sidx btfsc value,sidx ; ports are normally on! goto displ btfss intcon,t0ie ; is timer running? call incsecs goto displ ; displ movlw b'11110001' ; mask for strobes andwf porta,f ; shut off the strobes call sdelay1 btfsc minsf goto dotens btfsc tensf goto dosecs btfsc secsf ; one cycle doesn't matter, but to goto domins ; keep things uniform do this even ; though it's silly goto domins ; dotens ; display the tens digit movlw 0xf0 andwf portb,f ; clear the BCD outputs movf tensec,w call setdisplay xorwf portb,f ; set the BCD values bsf tenport bcf minsf bsf tensf goto loop ; domins ; display the minutes digit movlw 0xf0 andwf portb,f ; clear the BCD outputs movf minute,w call setdisplay xorwf portb,f ; set the BCD values movf minute,w ; blank leading zero? btfss status,z bsf minport bcf secsf bsf minsf goto loop ; dosecs ; display the seconds digit movlw 0xf0 andwf portb,f ; clear the BCD outputs movf second,w call setdisplay xorwf portb,f ; set the BCD values bsf secport bcf tensf bsf secsf goto loop ; -------------------------------------------- reset ; clear the registers and all call distmr bcf gie bcf relport movf secset,w movwf second movf tenset,w movwf tensec movf minset,w movwf minute clrf myflags clrf now clrf dbing clrf value clrf prev clrf changed return ; -------------------------------------------- starttmr ; start the timer ; first check if time is non-zero bsf zerof ; set and check minutes movf minset,w btfss status,z bcf zerof movwf minute ; tens movf tenset,w btfss status,z bcf zerof movwf tensec ; seconds movf secset,w btfss status,z bcf zerof movwf second ; the settings are prepared ; now see if non-zero and go ; otherwise complain btfss zerof goto timer ; time was set to zero bsf dobeepf bsf dolongf return timer ; time is OK, enable tmr0 movlw factor ; delay factor (# of tmr0 cycles) movwf count bcf intcon,t0if ; clear tmr0 flag bsf intcon,t0ie ; enable tmr0 bsf intcon,gie ; enable interrupts bsf relport ; turn on the relay return ; we should be running now ; -------------------------------------------- init ; should only be called at startup ; clrf minset ; clrf tenset ; clrf secset ; for testing: movlw .0 movwf minset movlw .0 movwf tenset movlw .0 movwf secset bsf status,rp0 ; select bank 1 movlw 0x10 ; A0-A3 out, A4 in movwf porta movlw 0xe0 ; B0-B4 out, B5-7 in movwf portb bcf option,t0cs ; internal tmr0 clock bsf option,ps0 ; set prescaler bcf option,ps1 bsf option,ps2 bcf option,psa bcf status,rp0 ; select bank 0 return ;============ stuff for buttons? ========= incmins incf minset,w movwf minset movwf minute movlw .10 xorwf minset,w btfss status,z return movlw .0 movwf minset movwf minute return ; inctens incf tenset,w movwf tenset movwf tensec movlw .6 xorwf tenset,w btfss status,z return movlw .0 movwf tenset movwf tensec return ; incsecs incf secset,w movwf secset movwf second movlw .10 xorwf secset,w btfss status,z return movlw .0 movwf secset movwf second return