;-------------------------------------------------------------------------; ; A countdown timer for Psychoanalysis ; ; ORIGINAL CODE April '99 Stan Ockers (ockers@anl.gov) ; ; Re-written by Brendon Archibald April 2007 ; ; Optimized for battery operation ; ; Moddified for use in the 16F648A uP - Use internal OSC No XTAL required ; ; My mods mostly have ;* comments original code is just ; ; ; Modifications from original code include: ; ; 1\ Auto restart when reached zero. ; ; 2\ 0 Digit blanking on least significant digits. ; ; 3\ Improved alarm noise by stopping interupts. ; ; 4\ Combined Set and Select switch functions (long press for Set) ; ; Changed set routine, now start button increments digits and ; ; 5\ select button locks in digits. ; ; 6\ Add power off feature combined with Start switch (long press) ; ; 7\ Add 2 min Auto shutdown timer when not counting. ; ; 8\ Whist in power down uP sleeps till start button pressed ; ; 9\ Remove CD4511 from original design - Use retlw table for segments ; ; Counts down from 0-99 min and 1-59 sec giving an alarm at 0 ; ; Initial counts are held in data EEPROM ; ; and can be selected and set with one button ; ; ; ; *RAO-RA3 to bases of NPN transistors connect to cathode's of displays. ; ; **RB0-RB6 to 7segment display digits a, b, c, d, e, f & g. ; ; * RA6 to Decimal Point Anode, Cathode to ground. ; ; RB7 to start pushbutton used to start countdown and power off . ; ; RA4 is an output whilst counting (Active low Open Drain) ; ; RA5 with pull-up resistor goes to PB to select from 15 starting counts ; ; RA7 go's to piezo element via 100r resistor which gives an alarm. ; ;-------------------------------------------------------------------------; list p=16f648A ; list directive to define processor #include <p16F648A.inc> ; processor specific variable definitions errorlevel -302 ; suppress message 302 from list file __CONFIG _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT ;* Config's for MPLAB ;-------------------------------------------------------------------------; ; Here we define our own personal registers and give them names ; ; *All moved to 16F6xx register locations* ; ;-------------------------------------------------------------------------; SEC EQU H'20' ; this register holds the value of seconds SEC10 EQU H'21' ; holds value of 10's of seconds MIN EQU H'22' ; holds value of minutes MIN10 EQU H'23' ; holds value of 10's of minutes DIGCTR EQU H'24' ; 8 bit counter, only 2 lowest bits actually used DIGIT EQU H'25' ; hold digit number to access table INTCNT EQU H'26' ; counts # interrupts to determine when 1 sec up FUDGE EQU H'27' ; allows slight adjustment every 7 interrupts RUNFLG EQU H'28' ; bit 0 only, tells if countdown in progress SECNT EQU H'29' ; used in counting 50, 20 msec delays for 1 sec CNTMSEC EQU H'2A' ; used in timing of milliseconds ALARM EQU H'2B' ; bit 0 used as flag for when to alarm, ALSO SETS ALARM LENGTH DISPSET EQU H'2C' ;* bit 0 tells if in SETDISP and avoid bit blanking routine NOISELP EQU H'2D' ;* USED FOR NOISE LOOP BEEPS EQU H'2E' ;* USED FOR NUMBER OF BEEPS AUTOFF EQU H'2F' ;* USED FOR AUTO OFF TIMER BEEPDUR EQU H'30' ;* TEMP REG FOR BEEP DURATION PORTA_TEMP EQU H'31' ;* temporarily holds value of PORTA (MASKED) DPLATCH EQU H'32' ;* Holds latched value for DP DPCNT EQU H'33' W_TEMP EQU H'70' ; temporarily holds value of W STATUS_TEMP EQU H'71' ; temporarily holds value of STATUS OFFSET EQU H'72' ; hold offset of address in EEPROM ;-------------------------------------------------------------------------; ; Here we give names to some numbers to make their use more clear ; ;-------------------------------------------------------------------------; #DEFINE START_PB D'7' ;#DEFINE SET_PB D'6' ;** Delete use of set button on RB6 #DEFINE SELECT_PB D'5' #DEFINE DP D'6' #DEFINE RA7 D'7' #DEFINE OUTPUT D'4' ;#DEFINE RB5 D'5' ;** Not needed anymore ;-------------------------------------------------------------------------; ; We set the start of code to orginate at location zero ; ;-------------------------------------------------------------------------; ORG 0 GOTO MAIN ; jump to the main routine NOP NOP NOP GOTO INTERRUPT ; interrupt routine ;-------------------------------------------------------------------------; ;* Lookup table for 7segment display - replaces CD/HEF4511 display driver ; ; ;-------------------------------------------------------------------------; SEGMENT ADDWF PCL,f ; Bit table data for 7 segment digits RETLW B'00111111' ; "0" _a_ RETLW B'00000110' ; "1" f| |b RETLW B'01011011' ; "2" |_g_| RETLW B'01001111' ; "3" e| |c RETLW B'01100110' ; "4" |_d_| RETLW B'01101101' ; "5" RETLW B'01111101' ; "6" g to a RETLW B'00000111' ; "7" RETLW B'01111111' ; "8" RETLW B'01101111' ; "9" RETLW B'00000000' ; "10 = blank" RETLW B'01011100' ; "11 = o" RETLW B'01110001' ; "12 = F" RETLW B'01101101' ; "13 = S" RETLW B'01111001' ; "14 = E" RETLW B'01110000' ; "15 = t" ;-------------------------------------------------------------------------; ; This table is used to get a bit pattern that will turn on a digit ; ; But only if next segment is not = 0 ie. O bit blanking ; ; Bit blanking not used if in SETDISP routine ie. DISPSET flag set ; ; I know this can be done a better way but it worked so... ; ;-------------------------------------------------------------------------; BITPAT2 ADDWF PCL,f ;* get bit pattern for transistors - NO BIT BLANKING RETLW H'01' ;* 0001 RETLW H'02' ;* 0010 RETLW H'04' ;* 0100 RETLW H'08' ;* 1000 BLANK1 MOVF MIN10,f ;* check MIN10 for zero BTFSS STATUS,Z ;* SHOWMIN RETLW H'04' ;* 0100 MOVF MIN,f ;* check MIN for zero BTFSS STATUS,Z GOTO SHOWMIN ;* NOT 0 SO SHOW BIT GOTO BLANKDIG ;* MIN10 & MIN = 0 SO BLANK BIT BLANK2 MOVF MIN10,f ;* check MIN10 for zero BTFSS STATUS,Z GOTO SHOWSEC10 MOVF MIN,f ;* check MIN for zero BTFSS STATUS,Z SHOWSEC10 RETLW H'02' ;* 0010 MOVF SEC10,f ;* check SEC10 for zero BTFSS STATUS,Z GOTO SHOWSEC10 ;* NOT 0 SO SHOW BIT GOTO BLANKDIG ;* MIN10 & MIN & SEC10 = 0 SO BLANK BIT BITPAT BTFSC DISPSET,0 ;* If in display set mode GOTO BITPAT2 ;* then goto BITBAT2 otherwise continue BITPAT1 ADDWF PCL,f ;* get bit pattern for tranys, 0 turns segment on SHOWSEC RETLW H'01' ;* 0001 Seconds never blank GOTO BLANK2 ;* SEC10 digit call - Blank if MIN & SEC10 = 0 GOTO BLANK1 ;* MIN10 digit call - Blank if MIN10 & MIN = 0 MOVF MIN10,f ;* check MIN10 for zero BTFSS STATUS,Z ;* If MIN10 = 0 Blank MIN10 Segment SHOWMIN10 RETLW H'08' ;* 1000 BLANKDIG RETLW H'00' ;* 0000 Blank DIGITS if 0 ;-------------------------------------------------------------------------; ; Initialization routine sets up ports and timer ; ;-------------------------------------------------------------------------; INIT CLRF PORTB ; initialize PORTB CLRF PORTA ; initialize PORTA MOVLW H'07' ;* 16F6XX Specific - Turn comparators off and MOVWF CMCON ;* enable pins for I/O functions BSF STATUS,RP0 ; Select Bank1 MOVLW B'10000000' ; RB7 input all others outputs MOVWF TRISB ;* Updated command from original code MOVLW B'00100000' ; Port RA5 input, others outputs MOVWF TRISA ;* Updated command from original code MOVLW H'03' ; prescaler on TMR0 and 1:16 MOVWF OPTION_REG ;* write to OPTION register * Updated command BCF STATUS,RP0 ; back to bank0 MOVLW H'A0' ; GIE & T0IE set T0IF cleared MOVWF INTCON MOVLW H'F4' ; initialize INTCNT MOVWF INTCNT MOVLW H'06' ; initialize FUDGE MOVWF FUDGE CLRF OFFSET ; initialize OFFSET MOVLW D'122' ;* initialize DPCNT MOVWF DPCNT ;* BSF PORTA,OUTPUT ;* Set OUTPUT RA4 (Counting not in Progress) RETURN ;-------------------------------------------------------------------------; ; This is the interrupt routine that is jumped to when TMR0 overflows ; ;-------------------------------------------------------------------------; INTERRUPT MOVWF W_TEMP ; save W SWAPF STATUS,W ; save status MOVWF STATUS_TEMP ; without changing flags BCF STATUS,RP0 ; return to bank 0 BCF STATUS,RP1 ; return to bank 0 (shut ric up) MOVF PORTA,W ;* Save PORTA to w reg ANDLW B'11010000' ;* Mask off RA7,RA6 & RA4 (Outputs) MOVWF PORTA_TEMP ;* Save it for later MOVWF PORTA ;* Load it back into PORTA i.e. blank digits only INCF DIGCTR,f ; next digit # MOVF DIGCTR,W ; get it into W ANDLW H'03' ; mask off 2 lowest bits MOVWF DIGIT ; save it for later ADDLW H'20' ;* point at register to display - moved due to 16F6XX MOVWF FSR ; use as pointer MOVF INDF,W ; get value of reg pointed to into W CALL SEGMENT ;* Call segment lookup, return with value in w MOVWF PORTB ; load w into portb - output to 7seg display's MOVF DIGIT,W ; recall digit # CALL BITPAT ;* get bit pattern, return with value in w ADDWF PORTA_TEMP,W ;*Add bit pattern to PORTA_TEMP keep value in W MOVWF PORTA ; load w into porta - i.e select segment/ETC DECFSZ DPCNT,f ;* Decrement and check if DPCNT = 0 GOTO CONTINT ;* Not 0 so continue interrupt COMF DPLATCH,F ;* Is 0 so invert DPLATCH ;MOVLW D'122' ;* Reset DPCNT ;MOVWF DPCNT ;* CONTINT DECFSZ INTCNT,f ; finished 1 sec ? GOTO RESTORE ; not yet, return and enable inter. CALL EVERYSEC ; go to every second routine MOVLW H'F4' ; reset INTCNT to normal value MOVWF INTCNT DECFSZ FUDGE,f ; time for fudge? GOTO RESTORE ; not yet, continue on MOVLW H'06' ; reset FUDGE to 6 MOVWF FUDGE INCF INTCNT,f ; INTCNT to 245 RESTORE SWAPF STATUS_TEMP,W ; get original status back MOVWF STATUS ; into status register SWAPF W_TEMP,f ;* old no flags trick again SWAPF W_TEMP,W ;* to restore W BCF INTCON,T0IF ; clear the TMR0 interrupt flag RETFIE ; finished ;-------------------------------------------------------------------------; ; This routine is called by the interrupt routine every second ; ;-------------------------------------------------------------------------; EVERYSEC BTFSS RUNFLG,0 ; return if runflg not set RETURN BSF DPLATCH,0 MOVLW D'122' ;* Reset DPCNT MOVWF DPCNT DECF SEC,f ; decrement seconds digit INCFSZ SEC,W ; test for underflow GOTO CKZERO MOVLW H'09' MOVWF SEC ; reset sec to 9 DECF SEC10,f ; decrement SEC10 INCFSZ SEC10,W ; check underflow GOTO CKZERO MOVLW H'05' MOVWF SEC10 ; reset SEC10 to 5 DECF MIN,f ; decrement MIN INCFSZ MIN,W ; check underflow GOTO CKZERO MOVLW H'09' MOVWF MIN ; reset MIN to 9 DECF MIN10,f ; decrement MIN10 CKZERO MOVF SEC,f ; test SEC for zero BTFSS STATUS,Z RETURN MOVF SEC10,f ; check SEC10 for zero BTFSS STATUS,Z RETURN MOVF MIN,f ; check MIN for zero BTFSS STATUS,Z RETURN MOVF MIN10,f ; check MIN10 for zero BTFSS STATUS,Z RETURN CLRF RUNFLG ; stop the countdown BCF PORTA,DP ;* clear decimal point BSF ALARM, 0 ; set the alarm flag RETURN ;-------------------------------------------------------------------------; ; This routine is called by the MAINLOOP to set or clear the DP ; ;-------------------------------------------------------------------------; DPSET BTFSC DPLATCH,0 ;* Test DPLATCH bit0 GOTO DPOFF ;* If 0 clear decimal point BSF PORTA,DP ;* If 1 turn on decimal point RETURN DPOFF BCF PORTA,DP ;* TURN OFF decimal point RETURN ;-------------------------------------------------------------------------; ; This is a routine to read a byte from the data EEPROM ; ;-------------------------------------------------------------------------; READEE BSF STATUS,RP0 ;* change to bank 1 - needed it MOVWF EEADR ; set up eeprom address from W BSF EECON1,RD ; set the read bit MOVF EEDATA,W ; return value in W BCF STATUS,RP0 ;* back to bank 0 RETURN ;-------------------------------------------------------------------------; ; This routine fills the display registers from data EEPROM ; ;-------------------------------------------------------------------------; GETEE MOVLW H'01' ; EEprom location 1 + ADDWF OFFSET,W ; offset from start CALL READEE ; into W MOVWF SEC ; into SEC register MOVLW H'02' ; location 2 + ADDWF OFFSET,W ; offset from start CALL READEE ; into W MOVWF SEC10 ; into SEC10 register MOVLW H'03' ; location 3 + ADDWF OFFSET,W ; offset from start CALL READEE ; into W MOVWF MIN ; into MIN register MOVLW H'04' ; location 4 + ADDWF OFFSET,W ; offset from start CALL READEE ; into W MOVWF MIN10 ; into MIN10 register RETURN ;-------------------------------------------------------------------------; ; This routine writes a byte to data EEPROM ; ;-------------------------------------------------------------------------; WRITECHK BCF INTCON,GIE ; clear GIE, disable interrupts WRITEEE BTFSC INTCON,GIE ;* Check if interrupt is disabled GOTO WRITECHK ;* If not disabled then do so BSF STATUS,RP0 ; Change to bank1 CLRF EECON1 BSF EECON1,WREN ; enable write MOVLW H'55' ; magic sequence MOVWF EECON2 MOVLW H'AA' MOVWF EECON2 BSF EECON1,WR ;* Write data to EEPROM EELOOP BTFSC EECON1,WR ; wait for WR to go low i.e. Finished write GOTO EELOOP ; not yet check again BCF EECON1,WREN ;* Finished write, disable write enable BCF EECON1,EEIF ; clear the interrupt flag BCF STATUS,RP0 ; return to bank0 BSF INTCON, GIE ; re-enable interrupts RETURN ;-------------------------------------------------------------------------; ; This routine puts display registers into data EEPROM ; ;-------------------------------------------------------------------------; PUTEE MOVF SEC,W BSF STATUS,RP0 ;* change to bank 1 to make it work MOVWF EEDATA MOVLW H'01' ; EEPROM location 1 + ADDWF OFFSET,W ; offset from start MOVWF EEADR CALL WRITEEE ; put SEC digit into EEprom MOVF SEC10,W BSF STATUS,RP0 ;* change to bank 1 to make it work MOVWF EEDATA MOVLW H'02' ; EEPROM location 2 + ADDWF OFFSET,W ; offset from start MOVWF EEADR CALL WRITEEE ; put SEC10 digit into EEprom MOVF MIN,W BSF STATUS,RP0 ;* change to bank 1 to make it work MOVWF EEDATA MOVLW H'03' ; EEPROM location 3 + ADDWF OFFSET,W ; offset from start MOVWF EEADR CALL WRITEEE ; put MIN digit into EEprom MOVF MIN10,W BSF STATUS,RP0 ;* change to bank 1 to make it work MOVWF EEDATA MOVLW H'04' ; EEPROM location 4 + ADDWF OFFSET,W ; offset from start MOVWF EEADR CALL WRITEEE ; put MIN10 digit into EEprom RETURN ;-------------------------------------------------------------------------; ; This is the main routine, the program starts here ; ;-------------------------------------------------------------------------; MAIN CALL INIT ; set up ports etc. ;-------------------------------------------------------------------------; ; We will return to this point when alarm is shut off. ; ;-------------------------------------------------------------------------; EE2D CALL GETEE ; put eeprom in display regs. BCF RUNFLG, 0 ; clear run flag so no countdown BCF ALARM, 0 ; clear alarm flag BCF DISPSET,0 ;* Initialise DISPSET flag (Enable Blanking) CALL WAITSTARTUP ; wait till no switches pressed CALL WAITSELECT ;-------------------------------------------------------------------------; ; This loop checks for either pushbutton and acts accordingly ; ; If however no switches are pressed for over a preset time call the ; ; SHUTOFF routine. ; ;-------------------------------------------------------------------------; ; Setup AUTOFF TIMEOUT with interrupt gives 2 min delay KEYCHKLOOP MOVLW H'78' ;* 120 INTO AUTO OFF COUNTER MOVWF AUTOFF ;* 120 X .8SEC = 96sec BEFORE AUTO OFF MOVLW H'C8' ;* 200 INTO FIRST COUNTER MOVWF SECNT ;* 200 X 4MSEC = .8SEC or so AUTOFFLOOP MOVLW H'04' ;* 4MSEC DELAY CALL NMSEC BTFSS PORTB,START_PB ; check for start pressed GOTO STARTLONG ;* yes, check for long press BTFSS PORTA,SELECT_PB ; No, check select pushbutton pressed GOTO SELLONG ;* yes, check for long press. DECFSZ SECNT,f ;* no switches, decrement secnt, check for 0 GOTO AUTOFFLOOP ;* secnt not 0 so loop DECFSZ AUTOFF,f ;* secnt is 0, decrement autoff, check for 0 GOTO AUTOFFLOOP ;* autoff not 0 so loop GOTO SHUTOFF ;* autoff is 0 so GOTO SHUTOFF ;-------------------------------------------------------------------------; ; Long Start press routine - If short press then skip to STARTCNT if long ; ; then blank display, stop interrupts and SLEEP till start pressed again. ; ; Upon Start press restart interupts and goto EE2D i.e. LIKE POWER UP ;-------------------------------------------------------------------------; STARTLONG MOVLW H'23' ;* 35 DELAYS MOVWF SECNT ;* INTO SECNT REGISTER STARTLOOP CALL DLY20 ;* CALL 20 MSEC DELAY BTFSC PORTB,START_PB ;* Check, START BUTTON GOTO STARTCNT ;* IF IT IS (i.e SHORT PRESS) START COUNT DECFSZ SECNT,f ;* IF NOT DECREMENT SECNT AND CHECK IF IT REACHES ZERO GOTO STARTLOOP ;* IF IT HASNT GO AND CHECK BUTTON AGAIN CALL SHORTBEEP ;* Make a small noise SHUTOFF MOVLW H'0A' ;* IF THE START BUTTON IS STILL DOWN AFTER 35 LOOPS MOVWF MIN10 ;* Blank 10's of minutes, MOVLW H'0B' ;* put a o in MOVWF MIN ;* minutes MOVLW H'0C' ;* Put an "F" in MOVWF SEC10 ;* 10's of seconds MOVWF SEC ;* and seconds CALL WAITSTARTUP MOVLW H'02' ;* NUMBER OF BEEPS MOVWF BEEPS ;* LOAD 5 INTO BEEPS MOVLW H'02' ;* duration of beeps MOVWF BEEPDUR ;* ETC CLRF PORTB CALL BEEP ;* CALL BEEP MOVLW D'250' CALL NMSEC BCF INTCON, GIE ;* COME BACK FROM BEEP - DISABLE INTERUPTS CLRF PORTB MOVLW B'00010000' ;* select transistors - i.e. ALL OFF MOVWF PORTA ;* MOVLW H'08' ;* Set INTCON RBIE - wake on PORTB MOVWF INTCON ;* Also GIE & T0IE & T0IF cleared CLRF TMR0 ;* and clear timer 0 - SOUNDED LIKE A GOOD IDEA? SLEEP ;* Goto sleep, wait for button NOP ;* Required delay? ;BCF INTCON, RBIF ;* DIDNT WORK AND DIDNT SEEM TO NEED IT?? CALL SHORTBEEP ;* Make a small noise MOVLW H'A0' ;* WAKE UP - GIE & T0IE set T0IF cleared MOVWF INTCON ;* i.e. restart interupts GOTO EE2D ;* Reload last eeprom & wait for start etc ;-------------------------------------------------------------------------; ; If start key has been pressed then start countdown process, ; ; I initially released this code with only the setting of the ; ; run flag included. If you think about it you must also reset ; ; TMR0 to zero. TMR0 is free running and could have any value ; ; 0-255 when the button in pressed. Also INTCNT has to be ; ; initialized because the previous count could have been cancelled. ; ;-------------------------------------------------------------------------; STARTCNT CALL SHORTBEEP ;* Make a small noise CALL WAITSTARTUP ; wait for release of start key SUBSTART MOVLW D'244' ; reset INTCNT MOVWF INTCNT CLRF DPLATCH ; reset DPLATCH CLRF TMR0 ; and clear timer 0 BSF RUNFLG, 0 ; start the countdown ;BCF PORTA,OUTPUT ;* Clear OUTPUT RA4 (Counting in Progress) ;-------------------------------------------------------------------------; ; Once started just loop looking for cancel or reaching 0000 ; ;-------------------------------------------------------------------------; MAINLOOP BTFSS PORTB,START_PB ; countdown in progress, check start GOTO STOPCNT ; Yes, Stop count CALL DPSET ;* No start switch, Set or clear decimal point BTFSS ALARM, 0 ; Reached 0000 yet? GOTO MAINLOOP ; no, ALARM = 0 continue looping BCF INTCON, GIE ; yes, ALARM = 1 disable interrupts BCF PORTA,DP ;* Clear decimal point BSF PORTA,OUTPUT ;* Set OUTPUT RA4 (Counting not in Progress) CALL SOUNDALARM ; CALL SOUNDALARM routine and come back BSF INTCON, GIE ; RE-ENABLE interrupts CALL GETEE ; put eeprom in display regs. BCF ALARM, 0 ; clear alarm flag GOTO SUBSTART ; ***Auto Restart triger point*** STOPCNT BCF PORTA,DP ;* Clear decimal point ;BSF PORTA,OUTPUT ;* Set OUTPUT RA4 (Counting not in Progress) CALL SHORTBEEP ;* Make a small noise GOTO EE2D ;-------------------------------------------------------------------------; ; This code sounds the alarm ; ; Produces 1 long 1KHz tone at end of time out - ; ;-------------------------------------------------------------------------; SOUNDALARM MOVLW B'00111111' ;* LOAD a "0" ONTO SEGMENTS MOVWF PORTB ;* Load into PORTB MOVLW H'01' ;* NUMBER OF BEEPS MOVWF BEEPS MOVLW H'14' ; ? delays of ? msec = ?sec or so into BEEPDUR reg MOVWF BEEPDUR BEEP BCF INTCON, GIE ;* DISABLE INTERUPTS T0 CLEAN UP SOUND BEEP2 MOVFW BEEPDUR ;* LOAD BEEPDUR INTO W MOVWF ALARM ; LOAD W INTO ALARM REG - lazy and use ALARM reg for tone duration NOISE MOVLW H'FF' ; 255 delays of 400 usec = 954usec or so MOVWF NOISELP ; into NOISELP register NOISELOOP MOVF PORTA,W ANDLW B'11010000' XORLW B'10000000' ;* TOGGLE PORTA RA7 (Buzzer) MOVWF PORTA MOVLW H'08' ; delay 8x10=80 microseconds (Freq of buzz) CALL N10USEC INCF DIGCTR,f ;* If RA7 is a 0 increment digit # MOVF DIGCTR,W ;* get it into W ANDLW H'03' ;* mask off 2 lowest bits CALL BITPAT2 ;* get bit pattern for transistors ADDWF PORTA,f ;* As a result gives basic multiplex display DIGDIS DECFSZ NOISELP,f ; finished delay? GOTO NOISELOOP ;* NO - DO IT AGAIN DECFSZ ALARM,f ; Check alarm reg for 0, decrement if not GOTO NOISE ;* and loop MOVLW B'00010000' ;* select transistors - i.e. ALL OFF MOVWF PORTA ;* MOVLW H'C8' ;* DELAY BETWEEN BEEPS CALL NMSEC ;* DECFSZ BEEPS,f GOTO BEEP2 STOPBEEP BSF INTCON, GIE ; RE-ENABLE interrupts RETURN SHORTBEEP MOVLW D'100' ; 100 delays of 80usec = 8msec or so MOVWF NOISELP BEEPLOOP MOVLW B'10000000' ;* XOR (TOGGLE) RA7 XORWF PORTA,1 MOVLW H'08' ; delay 8x10=80 microseconds (Freq of buzz) CALL N10USEC DECFSZ NOISELP,f ; finished delay? GOTO BEEPLOOP ;* NO - DO IT AGAIN BCF PORTA,RA7 ;* YES BEEP PROCESS FINISHED CLEAR SPEAKER PIN RETURN ;* GO BACK ;-------------------------------------------------------------------------; ; Wait for release of start button ; ;-------------------------------------------------------------------------; WAITSTARTUP BTFSS PORTB,START_PB ; wait for release GOTO WAITSTARTUP ; not released yet CALL DLY20 ; debounce release BTFSS PORTB,START_PB ; 2nd check, make sure released GOTO WAITSTARTUP ; keep checking RETURN ;-------------------------------------------------------------------------; ; Wait for release of select button ; ;-------------------------------------------------------------------------; WAITSELECT BTFSS PORTA,SELECT_PB ; wait for release GOTO WAITSELECT ; not yet CALL DLY20 ; debounce release BTFSS PORTA,SELECT_PB ; 2nd check, make sure released GOTO WAITSELECT ; keep checking RETURN ;-------------------------------------------------------------------------; ; Routine to follow sets the countdown time digit by digit ; ;-------------------------------------------------------------------------; SETDISP2 BSF DISPSET, 0 ;* set the DISPSET flag - Disable bitblanking MOVLW H'0A' ; put 10 in MOVWF MIN10 ; 10's of minutes MOVLW D'13' ; put S in MOVWF MIN ; minutes MOVLW D'14' ; put E in MOVWF SEC10 ; 10's of seconds MOVLW D'15' ; put t in MOVWF SEC ; seconds CALL SHORTBEEP ;* Make a small noise CALL WAITSELECT MOVLW H'0A' ; put 10 in digits, (no display) MOVWF MIN ; minutes MOVWF SEC10 ; 10's of seconds MOVWF SEC ; seconds STARTMIN10 CLRF MIN10 ; 0 now in MIN10 CALL WAITSELECT ;* WAIT1 BTFSS PORTB,START_PB ; set key pressed? GOTO MOREMIN10 ;* BTFSS PORTA,SELECT_PB ;* GOTO SETMIN ; yes MIN10 now set GOTO WAIT1 MOREMIN10 CALL SHORTBEEP ;* Make a small noise CALL WAITSTARTUP ; wait for release of set key INCF MIN10,f ; every increment 10's MIN MOVLW H'0A' ; reached 10? SUBWF MIN10,W BTFSC STATUS,Z ; Z set if reached 10 GOTO STARTMIN10 ; start again with 0 GOTO WAIT1 ; Check buttons again SETMIN CALL SHORTBEEP ;* Make a small noise STARTMIN CLRF MIN ; 0 into MIN CALL WAITSELECT WAIT2 BTFSS PORTB,START_PB ;* GOTO MOREMIN BTFSS PORTA,SELECT_PB ;* GOTO SETSEC10 ;* yes, finished with MIN GOTO WAIT2 ; Check buttons again MOREMIN CALL SHORTBEEP ;* Make a small noise CALL WAITSTARTUP ;* INCF MIN,f ; every second increment MIN MOVLW H'0A' ; reached 10? SUBWF MIN,W BTFSC STATUS,Z ; Z set if reached 10 GOTO STARTMIN ; put zero in if Z set GOTO WAIT2 ; Check buttons again SETSEC10 CALL SHORTBEEP ;* Make a small noise STARTSEC10 CLRF SEC10 ; 0 into SEC10 CALL WAITSELECT ;* WAIT3 BTFSS PORTB,START_PB ;* GOTO MORESEC10 ;* yes quit incrementing BTFSS PORTA,SELECT_PB ;* GOTO SETSEC GOTO WAIT3 ; continue wait MORESEC10 CALL SHORTBEEP ;* Make a small noise CALL WAITSTARTUP ;* INCF SEC10,f ; every second increment 10's SEC MOVLW H'06' ; reached 6? SUBWF SEC10,W BTFSC STATUS,Z ; Z set if reached 6 GOTO STARTSEC10 ; put zero in if Z set GOTO WAIT3 ; Check buttons again SETSEC CALL SHORTBEEP ;* Make a small noise STARTSEC CLRF SEC CALL WAITSELECT ;-------------------------------------------------------------------------; ; Subroutine to avoid a set time of 0000 ; ;-------------------------------------------------------------------------; MOVF MIN10,f ; check MIN10 for zero BTFSS STATUS,Z GOTO WAIT4 ; Zero SEC reg and continue increment MOVF MIN,f ; check MIN for zero BTFSS STATUS,Z GOTO WAIT4 ; Zero SEC reg and continue increment MOVF SEC10,f ; check SEC10 for zero BTFSS STATUS,Z GOTO WAIT4 ; Zero SEC reg and continue increment INCF SEC,f ; Put 1 in SEC reg and continue increment WAIT4 BTFSS PORTB,START_PB ;* GOTO MORESEC ;* yes finished setting digits BTFSS PORTA,SELECT_PB ;* GOTO FINSET ;* yes finished setting digits GOTO WAIT4 ; continue wait MORESEC CALL SHORTBEEP ;* Make a small noise CALL WAITSTARTUP ;* INCF SEC,f ;* increment SEC MOVLW H'0A' ; reached 10? SUBWF SEC,W BTFSC STATUS,Z ; Z set if reached 10 GOTO STARTSEC ; Return to STARTSEC and start again GOTO WAIT4 ; Not 10 continue to increment FINSET CALL SHORTBEEP ;* Make a small noise MOVLW D'100' CALL NMSEC CALL SHORTBEEP ;* Make a small noise CALL WAITSELECT ;* CALL PUTEE ; put new digits into EEPROM BCF DISPSET, 0 ;* CLEAR the DISPSET flag - Enable bitblanking GOTO KEYCHKLOOP ; start checking buttons again ;-------------------------------------------------------------------------; ; Selects starting count by incrementing OFFSET ; ;-------------------------------------------------------------------------; SELLONG MOVLW H'23' ;* 700msec delay MOVWF SECNT ;* SELLOOP CALL DLY20 ;* BTFSC PORTA,SELECT_PB ;* wait for release GOTO SETSELECT ;* is released - (short press) DECFSZ SECNT,f ;* not released, decrement SECNT check if 0 GOTO SELLOOP ;* not 0 do it again GOTO SETDISP2 ;* is 0 (long press) SETSELECT CALL SHORTBEEP MOVLW D'4' ; offset up 4 ADDWF OFFSET,F ; next offset position MOVLW D'60' ; reached 16th yet? SUBWF OFFSET,W ; will give zero if yes BTFSC STATUS,Z ; skip if not 64 CLRF OFFSET ; reset position to zero ;MOVLW 0 ; EEPROM location (LEFT ALL THIS OUT) ;MOVWF EEADR ; set up address (BECAUSE IT DIDNT WORK) ;MOVF OFFSET,W ; offset # into W (AND I FIGURED, OFFSET) ;MOVWF EEDATA ; set up data (WASNT CHANGED AFTER POWER UP) ;BCF INTCON,GIE ; clear GIE, disable interrupts (AND IT WOULD WEAR) ;CALL WRITEEE ; save # in location 0 (OUT EEPROM, AS I) ;BSF INTCON,GIE ; re-enable interrupts (WAS HAPPY TO HAVE) CALL GETEE ; get new start count into display (LAST SETTING) CALL WAITSELECT ; make sure select switch is up (TO LEAVE IT OUT) GOTO KEYCHKLOOP ; start checking buttons again ;-------------------------------------------------------------------------; ; The following are various delay routines based on instruction length. ; ; The instruction length is assumed to be 1 microsecond (4Mhz crystal). ; ;-------------------------------------------------------------------------; DLY20 MOVLW D'20' ; delay for 20 milliseconds ;*** N millisecond delay routine *** NMSEC MOVWF CNTMSEC ; delay for N (in W) milliseconds MSECLOOP MOVLW D'248' ; load takes 1 microsec CALL MICRO4 ; by itself CALL takes ... ; 2 + 247 X 4 + 3 + 2 = 995 NOP ; 1 more microsec DECFSZ CNTMSEC,f ; 1 when skip not taken, else 2 GOTO MSECLOOP ; 2 here: total 1000 per msecloop RETURN ; final time through takes 999 to here ; overhead in and out ignored ;*** 1 millisecond delay routine *** ONEMSEC MOVLW D'249' ; 1 microsec for load W ; loops below take 248 X 4 + 3 = 995 MICRO4 ADDLW H'FF' ; subtract 1 from 'W' BTFSS STATUS,Z ; skip when you reach zero GOTO MICRO4 ; loops takes 4 microsec, 3 for last RETURN ; takes 2 microsec ; call + load W + loops + return = ; 2 + 1 + 995 + 2 = 1000 microsec ;*** N 10 microsecond delay routine *** N10USEC MOVWF CNTMSEC ;* delay for N (in W) milliseconds USECLOOP MOVLW D'1' ;* load takes 1 microsec CALL MICRO4 ;* by itself CALL takes ... ;* 1 + 4 + 3 + 2 = 10 DECFSZ CNTMSEC,f ;* 1 when skip not taken, else 2 GOTO USECLOOP ;* 2 here: total 10 per usecloop RETURN ;* final time through takes 9 to here ;* overhead in and out ignored ;-------------------------------------------------------------------------; ; Here we set up the initial values of the digits in data EEPROM ; ;-------------------------------------------------------------------------; ORG H'2100' DE 0, 0, 0, 1, 0 ; 1st starting # (Should be 1 minute) DE 0, 0, 2, 0 ; 2nd starting # (Should be 2 minutes) DE 0, 0, 3, 0 ; 3rd starting # (Should be 3 minutes) DE 0, 0, 4, 0 ; 4th starting # (Should be 4 minutes) DE 0, 0, 5, 0 ; 5th starting # (Should be 5 minutes) DE 0, 0, 6, 0 ; 6th starting # 6 min DE 0, 0, 7, 0 ; 7th starting # 7 min DE 0, 0, 8, 0 ; 8th starting # 8 min DE 0, 0, 9, 0 ; 9th starting # 9 min DE 0, 0, 0, 1 ; 10th starting # 10 min DE 0, 0, 0, 2 ; 11th starting # 20 min DE 0, 0, 0, 3 ; 12th starting # 30 min DE 0, 0, 0, 4 ; 13th starting # 40 min DE 0, 0, 0, 5 ; 14th starting # 50 min DE 0, 0, 0, 6 ; 15th starting # 60 min END
file: /Techref/microchip/cntdn/cntdwn_16F648no4511_V4.asm, 39KB, , updated: 2007/4/3 17:55, local time: 2024/11/27 23:39,
18.222.20.250:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://sxlist.com/TECHREF/microchip/cntdn/cntdwn_16F648no4511_V4.asm"> microchip cntdn cntdwn_16F648no4511_V4</A> |
Did you find what you needed? |
Welcome to sxlist.com!sales, advertizing, & kind contributors just like you! Please don't rip/copy (here's why Copies of the site on CD are available at minimal cost. |
Welcome to sxlist.com! |
.