TITLE "clock.asm: DCF77 clock with programmable outputs @3.6864MHz" LIST p=16C84 ERRORLEVEL 0, -302 ; The clock uses a red HDSP-2000 4 digit 5x7 led matrix display. ; It allows much nicer figures to display than a 7-segment led. ; (A green display has the disadvantage to illuminate the room) ; eeprom: 0=eebank (4 banks for endurance), x1..xF=timer settings. ; mode0: time [HHMM] key0: toggle out, beeper off; key1: next ; mode1: seconds [hmSS] key0: toggle out, beeper off; key1: next ; mode2: date [Ddat] key0: toggle out, beeper off; key1: next ; 3..4: sleep [xMMs] key0: change action; on 99--; key1: next. ; mode5: status [qb#!] key0: return to time; key1: next ; ignore next timer action, then return to time display; ; ; 8..31: timer [TnAW] key0: change action; days; key1: next. ; [ooff] key0: change time; key1: next... ; ; HH,h=hour; MM,m=minutes; SS,s=Seconds; ; D=DayOfWeek(1..7); dat=DayMonthYear; x=SleepTimer(&)/KitchenTimer(!) ; q=RxQuality(00..FF); b=Status(ls,sz,wz,ly,r,0,eebank1,eebank0); ; #=OUT0 is on; !=OUT1 is on; (- if outputs are off); ; Tn=Timer(1..3); A=Action(#,!); W=days(-,@,1..7,1..5,6..7,1,2,3,4,5,6,7) ; (- is timer off, 0 is one shot then reset to -); oo=OnTime; ff=OffTime ; ; none switch sound sleep single timer ; ; # ! &&&&& @@@ TTTTT ; # !! & & @ @ T ; # ! & & @ T ; ----- ##### ! & @@@ T ; # !!! & & @ T ; # !!!! & & @ @ T ; # !! &&&&& @@@ T ; ; ; ; ********** ********** ; * *** * ; OUT0 A2 ** 1 18 ** A1 KEY1 ; * * ; OUT1 A3 ** 2 17 ** A0 KEY0 ; * * ; DCF A4 ** 3 16 ** Xin XTAL1 ; * * ; pullup MCLR ** 4 15 ** Xout XTAL0 ; * * ; GND ** 5 14 ** VCC ; * * ; COL1 B0 ** 6 13 ** B7 BUZ ; * * ; COL2 B1 ** 7 12 ** B6 DAT ; * * ; COL3 B2 ** 8 11 ** B5 CLK ; * * ; COL4 B3 ** 9 10 ** B4 COL5 ; * PIC16C84 * ; *********************** __CONFIG H'3FFD' ; PWRTE, WDT on, XT osc __IDLOCS H'1998' RTCC EQU 1 PC EQU 2 STATUS EQU 3 FSR EQU 4 PORTA EQU 5 PORTB EQU 6 EEDATA EQU H'08' EEADR EQU H'09' PCLATH EQU H'0A' INTCON EQU H'0B' _OPTION EQU H'81' ; OPTION register in page 1 _TRISA EQU H'85' ; TRISA in page 1 _TRISB EQU H'86' ; TRISB in page 1 _EECON1 EQU H'88' ; EECON1 in page 1 _EECON2 EQU H'89' ; EECON2 in page 1 C EQU 0 DC EQU 1 Z EQU 2 P EQU 5 KEY0 EQU 0 ; Key in (Port A) KEY1 EQU 1 ; Key in (Port A) OUT0 EQU 2 ; Out (Port A) power OUT1 EQU 3 ; Out (Port A) alarm DCF EQU 4 ; DCF in (Port A) CLK EQU 5 ; display Clock (Port B) DAT EQU 6 ; display Data (Port B) BUZ EQU 7 ; buzzer output (Port B) tmp0 EQU H'0C' ; temporary storage tmp1 EQU H'0D' tmp2 EQU H'0E' tmp3 EQU H'0F' sav0 EQU H'10' ; storage for interrupt handler sav1 EQU H'11' csecs EQU H'12' ; seconds/100 secs EQU H'13' ; seconds mins EQU H'14' ; minutes hours EQU H'15' ; hours day EQU H'16' ; dcf day of week date EQU H'17' ; dcf day of month (bcd) month EQU H'18' ; dcf month (bcd) year EQU H'19' ; dcf year within century (bcd) pwidth EQU H'1A' ; dcf pulse width pdist EQU H'1B' ; dcf pulse dist pcount EQU H'1C' ; dcf pulse count dcfsta EQU H'1D' ; dcf status: 5..0=st ls sz wz ly r; timout EQU H'1E' ; timeout decremented every second dcfsyn EQU H'1F' ; minutes since dcf time ok dcfcod EQU H'20' ; dcf code: last 48 bits rtovls EQU H'26' ; rtc overflow counter (9 = 10ms) column EQU H'27' ; current display column bright EQU H'28' ; current display intensity dkey EQU H'29' ; debouncing of key switches lkey EQU H'2A' ; last key status slmin EQU H'2B' ; sleep timer minutes slsec EQU H'2C' ; sleep timer seconds flags EQU H'2D' ; 7=secchg 6=minchg 5=blink 4=kitmr 3=keylock mode EQU H'2E' ; display modus eevar EQU H'2F' ; currently edited ee location ORG H'00' ; reset GOTO init ; ORG H'04' ; interrupt GOTO intserv ; dcf77 time ORG H'08' init CLRF PORTA ; to PORTA (keys, out, dcf) CLRF PORTB ; to PORTB (display) MOVLW B'00000011' ; PCLATH to data ROM MOVWF PCLATH BSF STATUS,P ; set page 1 MOVLW B'00010011' ; A3,A2 outputs MOVWF _TRISA CLRF _TRISB ; B all outputs MOVLW B'11011111' ; no pullup, rtc internal, wdt 1:128 (2.3s) MOVWF _OPTION BCF STATUS,P ; set page 0 MOVLW H'0C' ; reset vars MOVWF FSR initvar CLRF 0 INCF FSR,F MOVLW H'30' XORWF FSR,W BTFSS STATUS,Z GOTO initvar CLRF RTCC ; reset rtcc CLRF INTCON ; clear all int flgs and enable-bits BSF INTCON,5 ; enable rtc interrupt BSF INTCON,7 ; enable interrupts main CLRWDT ; watch dog reset CALL keypol ; CALL disply ; CALL chkidl ; CALL updtim ; CALL chktmr ; CALL chkpls ; CALL chkdcf ; GOTO main ORG H'28' intserv MOVWF sav0 ; save working register MOVF STATUS,W ; save status register MOVWF sav1 BCF INTCON,2 ; clear rtc overflow flag BCF STATUS,P ; set page 0 tickint DECFSZ rtovls,F ; execute only after 36 counts GOTO buzzck ; else check buzzer MOVLW D'36' MOVWF rtovls INCF csecs,F ; inc csecs MOVLW D'100' XORWF csecs,W ; 100 csecs? BTFSS STATUS,Z GOTO intpoll ; no: done CLRF csecs BSF flags,7 ; flag new second intpoll BTFSC PORTA,DCF ; DCF Signal low GOTO inthigh ; N: outside a pulse CLRF pdist ; Y: inside a pulse INCF pwidth,F GOTO intend inthigh INCF pdist,F ; missing pulse if pdist > 100 DECF pdist,W ; end of a pulse? BTFSS STATUS,Z GOTO intend MOVF pwidth,W ; yes: pdist = pwidth MOVWF pdist BSF pwidth,7 ; flag complete pulse GOTO intend buzzck BTFSS timout,7 ; if buzzer on GOTO intend ; BTFSC csecs,3 ; and csecs 16..31 (intervall 6Hz) GOTO intend ; BSF PORTB,BUZ ; buzzer pin on buzzon BTFSS RTCC,7 ; nearly 50% duty cycle GOTO buzzon ; BCF PORTB,BUZ ; intend MOVF sav1,W ; restore status register MOVWF STATUS MOVF sav0,W ; restore working register BCF STATUS,Z BTFSC sav1,Z ; restore zero bit BSF STATUS,Z RETFIE ;;; use this routine to read eeprom (address 0..14 in W) eeread MOVWF tmp0 ; four banks for higher endurance CLRF EEADR ; active bank in eeprom at 0 BSF STATUS,P ; set page 1 BSF _EECON1,0 ; BCF STATUS,P ; set page 0 SWAPF EEDATA,W ; ANDLW H'30' ; calculate address ADDWF tmp0,W ; fall through to eerd ;;; ee read (address in W) eerd MOVWF EEADR ; select address BSF STATUS,P ; set page 1 BSF _EECON1,0 ; BCF STATUS,P ; set page 0 MOVF EEDATA,W ; data to W RETURN ; ;;; use this routine to write eeprom (address of last read) eewrit BSF STATUS,P ; set page 1 BSF _EECON1,2 ; EEPROM write enable BCF STATUS,P ; set page 0 CALL eewr ; CALL eeveri ; BSF STATUS,P ; set page 1 BCF _EECON1,2 ; EEPROM write disable BCF STATUS,P ; set page 0 RETURN ; ;;; ee write (_EECON1,2 must be set) eewr BCF INTCON,7 ; disable global interrupt BTFSC INTCON,7 ; GOTO eewrit ; MOVWF EEDATA ; W to eeprom at EEADR BSF STATUS,P ; set page 1 MOVLW H'55' ; MOVWF _EECON2 ; MOVLW H'AA' ; MOVWF _EECON2 ; BSF _EECON1,1 ; BCF STATUS,P ; set page 0 BSF INTCON,7 ; enable global interrupt BSF STATUS,P ; set page 1 eeburn BTFSC _EECON1,1 ; GOTO eeburn ; BCF STATUS,P ; set page 0 RETLW 0 ; ;;; ee verify (call immediately after write) eeveri MOVF EEDATA,W ; BSF STATUS,P ; set page 1 BSF _EECON1,0 ; BCF STATUS,P ; set page 0 XORWF EEDATA,W ; BTFSC STATUS,Z ; skip if verify failed RETURN ; W is 0 CLRF EEADR ; verify error: change eebank BSF STATUS,P ; set page 1 BSF _EECON1,0 ; BCF STATUS,P ; set page 0 DECF EEDATA,W ; next bank to W CALL eewrit ; GOTO $ ; loop here updtim BTFSS flags,7 ; update time if a new second RETLW 0 BCF flags,7 ; clear flag CALL chkslp ; check sleep timer MOVF timout,F ; dec timout until zero BTFSS STATUS,Z ; DECF timout,F ; adjtim INCF secs,F ; inc seconds MOVLW D'60' XORWF secs,W BTFSS STATUS,Z RETLW 0 BSF flags,6 ; flag new minute (for chktmr) MOVF dcfsyn,F ; dec dcfsyn until zero BTFSS STATUS,Z ; DECF dcfsyn,F ; CLRF secs INCF mins,F ; inc minutes MOVLW D'60' XORWF mins,W BTFSS STATUS,Z RETLW 0 CLRF mins INCF hours,F ; inc hours MOVLW D'24' XORWF hours,W BTFSS STATUS,Z RETLW 0 CLRF hours MOVLW 1 ; advance day of week (1..7) INCF day,F BTFSC day,3 MOVWF day RETLW 0 ; ;;; check sleep timer every second chkslp MOVF slsec,W ; if slsec = 0 BTFSS STATUS,Z GOTO decsls MOVF slmin,W ; and slmin = 0 BTFSC STATUS,Z RETLW 0 ; done decslm MOVLW D'59' ; decrement slmin MOVWF slsec DECF slmin,F RETLW 0 decsls DECFSZ slsec,F ; if slsec becomes 0 RETLW 0 MOVF slmin,W ; and slmin is already 0 BTFSS STATUS,Z RETLW 0 CLRF mode ; return to time display BTFSS flags,4 ; if sleep GOTO slpact BSF PORTA,OUT1 ; kitchen timer: set alarm pin MOVLW D'188' ; buzzer on for 60 seconds (bit7 of timout) MOVWF timout RETLW 0 slpact BCF PORTA,OUT0 ; clear out RETLW 0 ;;; check timers for action every minute (after updtim) chktmr BTFSS flags,6 ; new minute? RETLW 0 BCF flags,6 ; yes: clear flag CLRF tmp1 ; ee address chkday MOVLW D'15' ; all timers checked? SUBWF tmp1,W BTFSC STATUS,Z RETLW 0 ; yes: done CALL nextee ; read action/days MOVWF tmp2 ; store action CALL getday MOVWF tmp3 ; store day XORLW H'0E' ; single action? BTFSC STATUS,Z GOTO chkon SWAPF tmp3,W ; upper nibble "from day" = 0? ANDLW H'0F' BTFSC STATUS,Z MOVF tmp3,W ; yes: take "to day" SUBWF day,W ; C set if day >= "from day" BTFSS STATUS,C GOTO noactn MOVLW H'0F' ANDWF tmp3,F ; lower nibble "to day" MOVF day,W SUBWF tmp3,W ; C set if day <= "to day" BTFSS STATUS,C GOTO noactn chkon CALL nextee ; read hours on time INCF tmp1,F ; next ee address XORWF hours,W BTFSS STATUS,Z GOTO chkof CALL thisee ; read minutes on time XORWF mins,W BTFSS STATUS,Z GOTO chkof MOVF mode,W ; skip acton if mode = 5 XORLW 5 BTFSS STATUS,Z GOTO acton CLRF mode ; and return to mode 0 GOTO chkof acton BTFSC tmp2,4 ; alarm? GOTO acton1 BSF PORTA,OUT0 ; power on GOTO chkof acton1 BSF PORTA,OUT1 ; alarm pin on MOVLW D'188' ; buzzer on for 60 seconds (bit7 of timout) MOVWF timout chkof CALL nextee ; read hours off time INCF tmp1,F ; next ee address XORWF hours,W BTFSS STATUS,Z GOTO chkday CALL thisee ; read minutes off time XORWF mins,W BTFSS STATUS,Z GOTO chkday actof BTFSC tmp2,4 ; alarm? GOTO actof1 BCF PORTA,OUT0 ; power off GOTO actofs actof1 BCF PORTA,OUT1 ; alarm pin off actofs DECF tmp2,W ; clear day if single action ANDLW H'0F' BTFSS STATUS,Z GOTO chkday MOVLW 4 ; set ee address to action SUBWF tmp1,W CALL eeread DECF tmp2,W ; clear day in action byte CALL eewrit GOTO chkday noactn MOVLW 4 ; day does not match: skip time check ADDWF tmp1,F GOTO chkday nextee INCF tmp1,F ; increment pointer and read ee thisee MOVF tmp1,W ; read ee at tmp1 GOTO eeread ; return from there chkpls BTFSS pwidth,7 ; check dcf pulse, save pulse in dcfcod RETLW 0 BCF pwidth,7 MOVF pwidth,W MOVWF tmp0 CLRF pwidth SUBLW D'5' ; error if pulse <= 50ms BTFSC STATUS,C GOTO chkerr MOVF tmp0,W SUBLW D'25' ; error if pulse > 250ms BTFSS STATUS,C GOTO chkerr MOVLW D'15' SUBWF tmp0,W ; carry now contains data bit savpls RRF dcfcod+5,F RRF dcfcod+4,F RRF dcfcod+3,F RRF dcfcod+2,F RRF dcfcod+1,F RRF dcfcod+0,F INCF pcount,F RETLW 0 chkerr CLRF pcount RETLW 0 ;;; check the dcf telegram and transfer to time if ok ; rtc int does not write to dcfcod and may continue ; dcfcod+5 P3 Y Y Y Y Y Y Y 58..51 ; dcfcod+4 Y M M M M M D D 50..43 ; dcfcod+3 D d d d d d d P2 42..35 ; dcfcod+2 h h h h h h P1 m 34..27 ; dcfcod+1 m m m m m m 1 ls 26..19 ; dcfcod+0 sz wz ly r x x x x 18..11 chkdcf MOVF pdist,W ; no pulse for 190/100 sec? SUBLW D'190' BTFSC STATUS,C RETLW 0 MOVF pcount,W ; error if <> 59 pulses XORLW D'59' ; BTFSS STATUS,Z ; GOTO chkerr CLRF tmp3 ; used for parity check BCF STATUS,C ; clear carry CALL savpls ; shift right dcfcod MOVF dcfcod+5,W CALL updprty MOVF dcfcod+4,W CALL updprty MOVF dcfcod+3,W CALL updprty MOVF tmp3,F ; P3 ok? BTFSS STATUS,Z GOTO chkerr CALL savpls ; shift right dcfcod MOVF dcfcod+2,W ANDLW H'7F' CALL updprty MOVF tmp3,F ; P2 ok? BTFSS STATUS,Z GOTO chkerr MOVF dcfcod+1,W CALL updprty MOVF tmp3,F ; P1 ok? BTFSS STATUS,Z GOTO chkerr BTFSS dcfcod+0,7 ; is start bit set? GOTO chkerr MOVF dcfcod+2,W ; dcf telegram ok ANDLW H'3F' CALL bcdbin MOVWF hours MOVF dcfcod+1,W ANDLW H'7F' CALL bcdbin MOVWF mins MOVF dcfcod+4,W ANDLW H'1F' MOVWF month CALL savpls ; shift right dcfcod CALL savpls ; shift right dcfcod MOVF dcfcod+0,W ; dcfsta ANDLW H'3F' MOVWF dcfsta CALL savpls ; shift right dcfcod CALL savpls ; shift right dcfcod CALL savpls ; shift right dcfcod MOVF dcfcod+4,W MOVWF year MOVF dcfcod+3,W ANDLW H'07' MOVWF day CALL savpls ; shift right dcfcod CALL savpls ; shift right dcfcod MOVF dcfcod+2,W ANDLW H'3F' MOVWF date MOVLW H'FF' ; dcfsyn ok for 255 minutes MOVWF dcfsyn CLRF pcount CLRF secs BSF flags,6 ; flag new minute (for chktmr) MOVLW D'245' ; next updtim in 1.1 sec MOVWF csecs RETLW 0 updprty MOVWF tmp0 ; invert tmp3 for each bit set in acca updprt1 BCF STATUS,C ; clear carry RRF tmp0,f ; lsb to carry BTFSC STATUS,C ; skip if carry set COMF tmp3,f ; else invert tmp3 MOVF tmp0,f ; repeat until no more bits set BTFSS STATUS,Z GOTO updprt1 RETLW 0 keypol COMF PORTA,W ; get key status ANDLW H'03' ; mask off unused bytes XORWF lkey,F ; same as last key status? MOVWF lkey ; store current key BTFSS STATUS,Z ; CLRF dkey ; no: reset keys INCFSZ dkey,W ; inc dkey, saturation at 255 INCF dkey,F ; MOVLW D'06' ; accept keys at this count XORWF dkey,W ; BTFSC STATUS,Z ; GOTO ckkey ; MOVLW D'80' ; key repeat at this count XORWF dkey,W ; BTFSS STATUS,Z ; RETLW 0 ; MOVLW D'12' ; adj repeat rate here SUBWF dkey,F ; ckkey MOVF lkey,W ; BTFSC STATUS,Z ; BCF flags,3 ; no key: clear keylock BTFSC STATUS,Z ; RETLW 0 ; no key: done BTFSC flags,3 ; RETLW 0 ; keys locked: done MOVLW D'60' ; key timeout for timer settings MOVWF timout ; and buzzer off (bit 7) DECF lkey,W ; BTFSC STATUS,Z ; GOTO keyhit0 ; ADDLW H'FF' ; BTFSC STATUS,Z ; GOTO keyhit1 ; BSF flags,3 ; both keys: lock keys CLRF eevar ; reset timer setting DECF mode,W ; if sleep setting (modes 3,4) ANDLW H'FE' ; XORLW H'02' ; BTFSS STATUS,Z ; RETLW 0 ; CLRF slmin ; cancel sleep timer CLRF slsec ; BCF flags,4 ; RETLW 0 ; keyhit0 MOVF mode,W ; if mode < 3 MOVWF tmp3 ; MOVLW 3 ; SUBWF tmp3,F ; BTFSC STATUS,C ; GOTO keyh3 ; BSF flags,3 ; lock keys MOVLW B'00000100' ; toggle OUT0 unless alarm BTFSS PORTA,OUT1 ; XORWF PORTA,F ; BCF PORTA,OUT1 ; clear alarm pin RETLW 0 ; keyh3 BTFSS STATUS,Z ; if mode = 3 GOTO keyh4 ; MOVLW B'00010000' ; sleep timer / kitchen timer XORWF flags,F ; RETLW 0 ; keyh4 DECFSZ tmp3,F ; if mode = 4 GOTO keyh5 ; MOVF slsec,W ; slsec = 0 ? BTFSS STATUS,Z ; GOTO decsl ; MOVF slmin,W ; slmin = 0 ? BTFSS STATUS,Z ; GOTO decsl ; MOVLW D'59' ; slsec = 59 MOVWF slsec ; MOVLW D'99' ; slmin = 99 MOVWF slmin ; BTFSS flags,4 ; if sleep BSF PORTA,OUT0 ; set out 0 RETLW 0 decsl MOVLW D'59' ; slsec = 59 MOVWF slsec ; DECF slmin,F ; BTFSS slmin,7 ; slmin = -1 ? RETLW 0 ; CLRF slsec ; clear timer CLRF slmin ; BSF flags,3 ; keys must be released BTFSS flags,4 ; if sleep BCF PORTA,OUT0 ; clear out RETLW 0 ; keyh5 DECFSZ tmp3,F ; if mode = 5 GOTO keyh8 ; CLRF mode ; return to time display RETLW 0 ; keyh8 MOVF mode,W ; ANDLW H'06' ; BTFSS STATUS,Z ; GOTO inctmr ; BTFSC mode,0 ; GOTO incday ; incact MOVLW H'10' ; XORWF eevar,F ; RETLW 0 ; incday INCF eevar,F ; MOVF eevar,W ; ANDLW H'0F' ; XORLW D'12' ; BTFSS STATUS,Z ; RETLW 0 ; MOVLW H'F0' ; ANDWF eevar,F ; RETLW 0 ; inctmr BTFSC mode,0 ; GOTO incmin ; INCF eevar,F ; inc hours MOVLW D'24' ; XORWF eevar,W ; BTFSC STATUS,Z ; CLRF eevar ; RETLW 0 ; incmin INCF eevar,F ; inc minutes MOVLW D'60' ; XORWF eevar,W ; BTFSC STATUS,Z ; CLRF eevar ; RETLW 0 ; keyhit1 BSF flags,3 ; lock keys CALL getvar ; update ee if appropriate XORLW 0 ; BTFSC STATUS,Z ; GOTO incmod ; CALL eeread ; read sets write address XORWF eevar,W ; write if changed BTFSC STATUS,Z ; GOTO incmod ; MOVF eevar,W ; CALL eewrit ; incmod INCF mode,F ; next mode 0..31 MOVLW H'07' ; ANDWF mode,W ; XORLW H'06' ; MOVLW 2 ; BTFSC STATUS,Z ; ADDWF mode,F ; BTFSC mode,5 ; CLRF mode ; CALL getvar ; initialize eevar CALL eeread ; MOVWF eevar ; RETLW 0 ; ;;; return to mode 0 if keys idle for 60s in timer setting modes chkidl MOVLW D'08' ; mode >= 8 ? SUBWF mode,W BTFSS STATUS,C RETLW 0 MOVF timout,W ; key timeout: BTFSS STATUS,Z RETLW 0 CALL keyhit1 ; save to ee if edited CLRF mode ; and return to mode 0 RETLW 0 ;;; display 5 columns with 28 pixels disply CLRF column ; column 0..4 dsplop CLRF bright ; brightness compensation GOTO ckdisp ; ;;; ; display routine dspcol BCF STATUS,C ; RLF bright,F ; max 28 * 2 RLF bright,F ; max 28 * 4 RLF bright,F ; max 28 * 8 INCF bright,F ; min 1, max 225 MOVF column,W ; CALL decode ; display on MOVWF PORTB ; dspdly NOP ; NOP ; NOP ; NOP ; DECFSZ bright,F ; loop until bright count zero GOTO dspdly ; MOVLW B'00100000' ; display off MOVWF PORTB ; BTFSC column,2 ; last column 4 ? RETLW 0 ; INCF column,F ; advance column selector GOTO dsplop ; ;;; time: hours and minutes to display dsptim MOVF mins,W ; CALL sftdblb ; MOVF hours,W ; CALL binbcd ; MOVWF tmp3 ; ANDLW H'0F' ; CALL sftchr ; MOVLW H'0A' ; display flash/dash if not dcfsyn BTFSS PORTA,DCF ; MOVLW H'0B' ; MOVF dcfsyn,F ; BTFSS STATUS,Z ; SWAPF tmp3,W ; else display hours ANDLW H'0F' ; CALL sftchr ; GOTO dspcol ; ;;; hours, minutes and seconds dspsec MOVF secs,W ; CALL sftdblb ; MOVF mins,W ; CALL sftsmlb ; MOVF hours,W ; CALL sftsmlb ; GOTO dspcol ; ;;; date: day, month, year, day of week (1..7) dspdat MOVF year,W ; CALL sftsml ; MOVF month,W ; CALL sftsml ; MOVF date,W ; CALL sftsml ; MOVF day,W ; CALL sftchr ; GOTO dspcol ; ;;; sleep timer: action, minutes, seconds dspslp BTFSS mode,0 ; BSF flags,5 ; blink MOVF slsec,W ; CALL sftsmlb ; MOVF slmin,W ; CALL sftdblb ; BCF flags,5 ; normal BTFSC mode,0 ; BSF flags,5 ; blink MOVLW H'0D' ; hourglass (sleep) BTFSC flags,4 ; MOVLW H'0C' ; sound (kitchen timer) CALL sftchr ; BCF flags,5 ; normal GOTO dspcol ; ;;; status display: dcfsyn (FF..00), dcfsta, OUT0, OUT1 dspsta MOVLW H'0A' ; dash BTFSC PORTA,OUT0 ; MOVLW H'0B' ; flash CALL sftchr ; MOVF pcount,W ; CALL sftsmlb ; MOVLW 0 ; ee bank CALL eerd ; MOVWF tmp2 ; RLF tmp2,F ; RLF tmp2,F ; SWAPF tmp2,W ; ANDLW H'C0' ; IORWF dcfsta,W ; status: ee1 ee0 st ls sz wz ly r CALL sftsml ; MOVF dcfsyn,W ; CALL sftsml ; GOTO dspcol ; ;;; display timer n action and day setting dspact BTFSC mode,0 ; BSF flags,5 ; blink MOVF eevar,W ; CALL getday ; MOVWF tmp3 ; ANDLW H'F0' ; BTFSC STATUS,Z ; GOTO dspac0 ; MOVF tmp3,W ; CALL sftsml ; GOTO dspac1 ; dspac0 MOVF tmp3,W ; CALL sftchr ; dspac1 BCF flags,5 ; normal BTFSS mode,0 ; BSF flags,5 ; blink MOVLW D'11' ; flash BTFSC eevar,4 ; MOVLW D'12' ; sound CALL sftchr ; BCF flags,5 ; normal RLF mode,W ; timer number MOVWF tmp3 ; SWAPF tmp3,W ; ANDLW H'03' ; CALL sftchr ; MOVLW H'0F' ; T CALL sftchr ; GOTO dspcol ; ;;; display timer n output and day setting dsptmr MOVF mode,W ANDLW H'03' ; 2,3,4,5 --> 4,3,2,1 BTFSS mode,0 ADDLW 2 MOVWF tmp3 MOVLW 5 ; off minutes CALL dsptmx CALL sftsmlb MOVLW 4 ; off hours CALL dsptmx CALL sftsmlb MOVLW 3 ; on minutes CALL dsptmx CALL sftsmlb MOVLW 2 ; on hours CALL dsptmx CALL sftsmlb BCF flags,5 ; normal display GOTO dspcol ; dsptmx MOVWF tmp2 ; save offset MOVF mode,W ; calculate address ANDLW H'18' ADDWF tmp2,W CALL getvvv CALL eeread ; get ee setting BCF flags,5 ; normal display DECFSZ tmp3,F ; check for set variable RETURN BSF flags,5 ; blink display MOVF eevar,W ; replace W with eevar RETURN ;;; bcd 00..99 to binary 0..63 bcdbin MOVWF tmp0 ; 1s SWAPF tmp0,W ANDLW H'0F' MOVWF tmp1 ; 10s BCF STATUS,C RLF tmp1,F ; * 2 RLF tmp1,F ; * 4 ADDWF tmp1,F ; * 5 RLF tmp1,F ; * 10 MOVF tmp0,W ; 1s ANDLW H'0F' ADDWF tmp1,W RETURN ;;; binary 0..63 to bcd 00..99 binbcd CLRF tmp0 DECF tmp0,F binbc0 INCF tmp0,F ADDLW D'246' ; subtract 10 BTFSC STATUS,C GOTO binbc0 ADDLW D'10' ; done: undo subtract SWAPF tmp0,F ; upper digit ADDWF tmp0,W ; plus lower digit RETURN ;;; shift row of two small digits into display sftsmlb CALL binbcd ; sftsml MOVWF tmp2 ; ANDLW H'0F' ; MOVWF tmp0 ; BCF STATUS,C ; RLF tmp0,F ; A * 2 RLF tmp0,F ; A * 4 ADDWF tmp0,W ; A * 5 ADDWF column,W ; A * 5 + column CALL getsml ; MOVWF tmp1 ; SWAPF tmp1,F ; SWAPF tmp2,W ; ANDLW H'0F' ; MOVWF tmp0 ; BCF STATUS,C ; RLF tmp0,F ; A * 2 RLF tmp0,F ; A * 4 ADDWF tmp0,W ; A * 5 ADDWF column,W ; A * 5 + column CALL getsml ; IORWF tmp1,W ; GOTO sftcol ; ;;; shift column of two digits into display sftdblb CALL binbcd ; sftdbl MOVWF tmp2 ; ANDLW H'0F' ; MOVWF tmp0 ; BCF STATUS,C ; RLF tmp0,F ; A * 2 RLF tmp0,F ; A * 4 ADDWF tmp0,W ; A * 5 ADDWF column,W ; A * 5 + column CALL getchr ; CALL sftcol ; SWAPF tmp2,W ; ANDLW H'0F' ; GOTO sftchr ; ;;; shift column of one digit into display sftchr MOVWF tmp0 ; BCF STATUS,C ; RLF tmp0,F ; A * 2 RLF tmp0,F ; A * 4 ADDWF tmp0,W ; A * 5 ADDWF column,W ; A * 5 + column CALL getchr ; sftcol BTFSS flags,5 ; if blink set GOTO nblink ; BTFSS csecs,4 ; clear W in intervals CLRW nblink MOVWF tmp0 ; MOVLW 7 ; bit counter MOVWF tmp1 ; sftpix MOVLW B'00100000' ; clock high, data low MOVWF PORTB ; BTFSS tmp0,0 ; GOTO npix BSF PORTB,DAT ; data bit = 1 INCF bright,F ; additional brightness npix RRF tmp0,F ; BCF PORTB,CLK ; DECFSZ tmp1,F ; GOTO sftpix ; RETLW 0 ; ORG H'30C' wdtrap GOTO wdtrap ; trap to force watch dog time out getchr ADDWF PC,F ; 5x7 dots figures RETLW B'00111110' ; zero RETLW B'01000001' ; RETLW B'01000001' ; RETLW B'01000001' ; RETLW B'00111110' ; RETLW B'00000000' ; one RETLW B'00000001' ; RETLW B'01111111' ; RETLW B'00100001' ; RETLW B'00000000' ; RETLW B'00110001' ; two RETLW B'01001001' ; RETLW B'01000101' ; RETLW B'01000011' ; RETLW B'00100001' ; RETLW B'00110110' ; three RETLW B'01001001' ; RETLW B'01001001' ; RETLW B'01000001' ; RETLW B'00100010' ; RETLW B'00000100' ; four RETLW B'01111111' ; RETLW B'00100100' ; RETLW B'00010100' ; RETLW B'00001100' ; RETLW B'01001110' ; five RETLW B'01010001' ; RETLW B'01010001' ; RETLW B'01010001' ; RETLW B'01110010' ; RETLW B'00000110' ; six RETLW B'01001001' ; RETLW B'01001001' ; RETLW B'00101001' ; RETLW B'00011110' ; RETLW B'01100000' ; seven RETLW B'01010000' ; RETLW B'01001000' ; RETLW B'01000111' ; RETLW B'01000000' ; RETLW B'00110110' ; eight RETLW B'01001001' ; RETLW B'01001001' ; RETLW B'01001001' ; RETLW B'00110110' ; RETLW B'00111100' ; nine RETLW B'01001010' ; RETLW B'01001001' ; RETLW B'01001001' ; RETLW B'00110000' ; RETLW B'00000000' ; dash RETLW B'00001000' ; RETLW B'00001000' ; RETLW B'00001000' ; RETLW B'00000000' ; RETLW B'00001000' ; Flash RETLW B'01001100' ; RETLW B'00101010' ; RETLW B'00011001' ; RETLW B'00001000' ; RETLW B'00100000' ; Sound RETLW B'01111110' ; RETLW B'00000111' ; RETLW B'00000111' ; RETLW B'00000010' ; RETLW B'01100011' ; Hourglass RETLW B'01010101' ; RETLW B'01001001' ; RETLW B'01010101' ; RETLW B'01100011' ; RETLW B'00100110' ; S RETLW B'01001001' ; RETLW B'01001001' ; RETLW B'01001001' ; RETLW B'00110010' ; RETLW B'01000000' ; T RETLW B'01000000' ; RETLW B'01111111' ; RETLW B'01000000' ; RETLW B'01000000' ; getsml ADDWF PC,F ; 3x5 dots figures RETLW B'00000111' ; small 0 RETLW B'00000101' ; RETLW B'00000101' ; RETLW B'00000101' ; RETLW B'00000111' ; RETLW B'00000010' ; small 1 RETLW B'00000010' ; RETLW B'00000010' ; RETLW B'00000010' ; RETLW B'00000010' ; RETLW B'00000111' ; small 2 RETLW B'00000001' ; RETLW B'00000111' ; RETLW B'00000100' ; RETLW B'00000111' ; RETLW B'00000111' ; small 3 RETLW B'00000100' ; RETLW B'00000111' ; RETLW B'00000100' ; RETLW B'00000111' ; RETLW B'00000100' ; small 4 RETLW B'00000100' ; RETLW B'00000111' ; RETLW B'00000101' ; RETLW B'00000101' ; RETLW B'00000111' ; small 5 RETLW B'00000100' ; RETLW B'00000111' ; RETLW B'00000001' ; RETLW B'00000111' ; RETLW B'00000111' ; small 6 RETLW B'00000101' ; RETLW B'00000111' ; RETLW B'00000001' ; RETLW B'00000111' ; RETLW B'00000100' ; small 7 RETLW B'00000100' ; RETLW B'00000100' ; RETLW B'00000100' ; RETLW B'00000111' ; RETLW B'00000111' ; small 8 RETLW B'00000101' ; RETLW B'00000111' ; RETLW B'00000101' ; RETLW B'00000111' ; RETLW B'00000111' ; small 9 RETLW B'00000100' ; RETLW B'00000111' ; RETLW B'00000101' ; RETLW B'00000111' ; RETLW B'00000101' ; small A RETLW B'00000111' ; RETLW B'00000101' ; RETLW B'00000101' ; RETLW B'00000010' ; RETLW B'00000011' ; small B RETLW B'00000101' ; RETLW B'00000011' ; RETLW B'00000101' ; RETLW B'00000011' ; RETLW B'00000110' ; small C RETLW B'00000001' ; RETLW B'00000001' ; RETLW B'00000001' ; RETLW B'00000110' ; RETLW B'00000011' ; small D RETLW B'00000101' ; RETLW B'00000101' ; RETLW B'00000101' ; RETLW B'00000011' ; RETLW B'00000111' ; small E RETLW B'00000001' ; RETLW B'00000011' ; RETLW B'00000001' ; RETLW B'00000111' ; RETLW B'00000001' ; small F RETLW B'00000001' ; RETLW B'00000011' ; RETLW B'00000001' ; RETLW B'00000111' ; decode ADDWF PC,F ; column selector RETLW B'00110000' ; RETLW B'00101000' ; RETLW B'00100100' ; RETLW B'00100010' ; RETLW B'00100001' ; ckdisp MOVF mode,W ; BTFSC mode,4 ; IORLW H'08' ; ANDLW H'0F' ; ADDWF PC,F ; computed goto GOTO dsptim ; mode 00 GOTO dspsec ; mode 01 GOTO dspdat ; mode 02 GOTO dspslp ; mode 03 GOTO dspslp ; mode 04 GOTO dspsta ; mode 05 RETLW 0 ; mode 06 RETLW 0 ; mode 07 GOTO dspact ; mode 08,10,18 GOTO dspact ; mode 09,11,19 GOTO dsptmr ; mode 0A,12,1A GOTO dsptmr ; mode 0B,13,1B GOTO dsptmr ; mode 0C,14,1C GOTO dsptmr ; mode 0D,15,1D RETLW 0 ; mode 0E,16,1E RETLW 0 ; mode 0F,17,1F getvar MOVF mode,W ; get current address of ee variable getvvv ADDWF PC,F ; computed goto RETLW 0 ; mode 0..5: no ee variable RETLW 0 ; mode 01 RETLW 0 ; mode 02 RETLW 0 ; mode 03 RETLW 0 ; mode 04 RETLW 0 ; mode 05 RETLW 0 ; mode 06 RETLW 0 ; mode 07 RETLW D'01' ; mode 08..09: action RETLW D'01' ; mode 09 RETLW D'02' ; mode 0A: hh on RETLW D'03' ; mode 0B: mm on RETLW D'04' ; mode 0C: hh off RETLW D'05' ; mode 0D: mm off RETLW 0 ; mode 06 RETLW 0 ; mode 07 RETLW D'06' ; mode 10 RETLW D'06' ; mode 11 RETLW D'07' ; mode 12 RETLW D'08' ; mode 13 RETLW D'09' ; mode 14 RETLW D'10' ; mode 15 RETLW 0 ; mode 16 RETLW 0 ; mode 17 RETLW D'11' ; mode 18 RETLW D'11' ; mode 19 RETLW D'12' ; mode 1A RETLW D'13' ; mode 1B RETLW D'14' ; mode 1C RETLW D'15' ; mode 1D RETLW 0 ; mode 1E RETLW 0 ; mode 1F getday ANDLW H'0F' ; ADDWF PC,F ; computed goto RETLW H'0A' ; (-) no action: timer off RETLW H'0E' ; (S) single action: one shot timer RETLW H'17' ; all days (monday to sunday) RETLW H'15' ; working days (monday to friday) RETLW H'67' ; weekend (saturday to sunday) RETLW H'01' ; monday RETLW H'02' ; tuesday RETLW H'03' ; wednesday RETLW H'04' ; thursday RETLW H'05' ; friday RETLW H'06' ; saturday RETLW H'07' ; sunday RETLW 0 ; entries for uninitialized eeprom RETLW 0 ; RETLW 0 ; RETLW 0 ; ORG H'2100' ; initialize eeprom DE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 DE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 DE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 DE 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 END ;