;** Dragonfly 32768Hz crystal test (flashes LED1 @ 1Hz) ;** Button (1) Hours+1, (3) Minutes+1, (5) Seconds+1 ;** Button (6) increments Resets Seconds to zero & holds clock list p=16F886 include __CONFIG _CONFIG1, _DEBUG_ON & _WDT_OFF & _LVP_OFF & _INTOSCIO errorlevel -302,-305 cblock 0x20 Buttons ; flags for pushbuttons 1 = pressed Digit:6 Jiffy ; 1/256 second timebase HalfSec ; .5 second + seconds Minutes ; Hours ; hours DigSel ; which digit 0-5 (left to right) Tens ; 10s holder for display Ones ; 1s holder for display endc #define Rst4022 PORTC,5 ; CD4022 reset active low #define Clk4022 PORTC,2 ; CD4022 clock low to high increments #define PB_In PORTA,3 ; push buttons 1 thru 6 org 0 ; reset vector nop goto Init org 4 ; interrupt vector goto _512 ; skip the table routines _Seg addwf PCL ; 7-segment display table dt b'00111111' ; "0" dt b'00000110' ; "1" dt b'10011011' ; "2" dt b'10001111' ; "3" dt b'10100110' ; "4" dt b'10101101' ; "5" dt b'10111101' ; "6" dt b'00000111' ; "7" dt b'10111111' ; "8" dt b'10101111' ; "9" _PB addwf PCL ; byte to bit (1-6) table dt 0x02,0x04,0x08,0x10,0x20,0x40 _512 incfsz Jiffy ; 1/512 second refresh clock goto _DoDisp ; refresh display only rrf HalfSec,W ; rotate 0.5 second bit to carry bnc _Sec ; don't update keypad _KeyPad movfw Buttons bz _Sec ; nothing to update bsf PORTA,5 ; clear the power loss indicator btfsc Buttons,3 ; button 3 pressed? goto _Min ; increment 1 Minute btfsc Buttons,1 ; button 1 pressed? goto _Hrs ; increment 1 Hour btfsc Buttons,6 ; button 6 pressed? clrf HalfSec ; reset seconds and hold btfss Buttons,5 ; button 5 pressed? goto _Sec bsf HalfSec,0 ; set the 1/2 second count incf HalfSec _Sec incf HalfSec ; .5 second increments movlw .120 subwf HalfSec,w bnc _UpSec clrf HalfSec ; zero the half seconds _Min incf Minutes ; 0-59 minutes movlw .60 subwf Minutes,w bnc _UpMin clrf Minutes _Hrs incf Hours movlw .24 ; 0-23 hours subwf Hours,w skpnc clrf Hours ; reset hours _UpHrs movlw Digit ; point to hours dispay (ones) addlw .1 movwf FSR incf Hours,w ; 1-24 hours call _DecBCD ; covert byte to ones & tens decf Tens,w skpnz clrf Digit ; blank lead digit (tens of hours) _UpMin movlw Digit ; point to minutes dispay (ones) addlw .3 ; add digit offset movwf FSR ; movfw Minutes call _DecBCD ; covert byte to ones & tens btfsc Digit+2,7 ; digit 3 dp / G transpose bsf Digit+2,6 bcf Digit+2,7 _UpSec movlw Digit ; point to seconds display (ones) addlw .5 ; add digit offset movwf FSR ; clrc ; make sure carry is clear rrf HalfSec,W ; call _DecBCD ; covert byte to ones & tens btfsc Digit+5,7 ; digit 6 dp / G transpose bsf Digit+5,6 bcf Digit+5,7 _Colon bsf Digit+3,6 ; turn on digit 4 colon bcf Digit+1,6 bcf Digit+2,7 btfsc HalfSec,0 goto _DoDisp bsf Digit+1,6 ; light colon (dp segment) bsf Digit+2,7 ; light colon ;*** refresh display (Digit) and scan keyboard (Buttons) _DoDisp movfw DigSel call _PB ; convert byte to bit iorwf Buttons,f ; set to pressed btfsc PB_In ; button is not pressed? xorwf Buttons,f ; clear the button clrf PORTB ; blank display ABCDEF movlw b'00111111' ; mask off lower six bits andwf PORTA ; blank display dp G incf DigSel ; increment to 6 then reset movlw .6 ; W = 6 (number of digits) subwf DigSel,w ; is DigSel < 6 bnc _disp ; yes then proceed normally _reset bsf Rst4022 ; no then reset the 4022 counter (1) clrf DigSel ; clear the display digit count bcf Rst4022 ; enable the 4022 counter _disp bsf Clk4022 ; increment CD4022 counter (rising edge) movlw Digit ; get pointer to Digit addwf DigSel,w ; add offset (pointer) movwf FSR ; point to display charater movfw INDF ; move charater to W movwf PORTB ; move W to PORTB andlw b'11000000' ; mask off low six bits iorwf PORTA ; segment G on (normal) bcf Clk4022 ; clock low (does not incremnt clock) bcf PIR1,CCP1IF ; clear the interrupt flag retfie ;*** Decimal to BCD enter with byte 0-99 returns Ones _DecBCD movwf Ones clrf Tens _10s incf Tens movlw .10 ; load the constant 10 subwf Ones,f ; subtract 10 and save result bc _10s ; check if answer negative movlw .10 addwf Ones,w ; W = Ones + 10 call _Seg ; convert to seven segment movwf INDF ; save ones to display decf FSR ; next digit Tens (left) decf Tens,W ; W = Tens -1 call _Seg ; convert to seven segment movwf INDF ; save tens to display return ;*** initialize the Dragonfly after a reset Init movlw b'00001011' ; timer1 osc on, sync, movwf T1CON ; enable external OSC on TMR1 movwf CCP1CON ; special CCP timer compare & reset movlw low(.64-1) ; 32768 movwf CCPR1L movlw high(.64-1) movwf CCPR1H banksel ANSEL ;B3 movlw b'00000001' ; movwf ANSEL ;B3 all ports digital except RA0 banksel TRISA ;B1 movlw b'00011111' ; segments dp & G, LED RX (pwr fail) movwf TRISA ;B1 I/O direction PORTA movlw b'11000000' ; segments ABCDEF, ICD2 PGC/PGD movwf TRISB ;B1 I/O direction PORTB movlw b'11011011' ; CD4022 clock & reset movwf TRISC ;B1 I/O direction PORTC bsf PIE1,CCP1IE ;B1 enable CCP1 interupt bcf STATUS, RP0 ;B0 movlw b'11111011' ; clock low and reset high movwf PORTC ; 4022 clock low & Reset high clrf DigSel ; clrf Buttons ; bcf PORTA,5 ; set the power loss indicator movlw .120 ; cause clock to overflow on reset movwf HalfSec ; any value over 119 will overflow movwf Minutes ; any value over 59 will overflow movlw .10 ; start the clock at 12:00:00 movwf Hours movlw b'11000000' movwf INTCON ; Enable GIE PIE bcf Rst4022 ; enable the 4022 Loop goto $ ; loop forever END