;-------------------------------------------------------------------------; ; Darkroom Timer ; ; April '99 Stan Ockers (ockers@anl.gov) ; ; circuit diagram in CNTDN.PCX ; ; further description in CNTDN.TXT ; ; ; ; Counts down from 0-99 min and 0-59 sec giving an alarm at 0 ; ; initial counts are held in data EEPROM setable with one button ; ; ; ; RBO-RB3 to bases of transistors connect to common cathode of displays. ; ; RA0-RA3 to 1,2,4,8 BCD inputs of CD4511 7 segment latch and driver. ; ; RB7 to start pushbutton used to start countdown and silence alarm. ; ; RB6 goes to time set pushbutton use to sucessively set the digits. ; ; RA4 with pull-up resistor goes to PB to select from 15 starting counts ; ; RB4 and RB5 go to speaker which gives an alarm. ; ;-------------------------------------------------------------------------; LIST P=16F84 #INCLUDE "p16f84.inc" ;-------------------------------------------------------------------------; ; Here we define our own personal registers and give them names ; ;-------------------------------------------------------------------------; SEC EQU H'0C' ; this register holds the value of seconds SEC10 EQU H'0D' ; holds value of 10's of seconds MIN EQU H'0E' ; holds value of minutes MIN10 EQU H'0F' ; holds value of 10's of minutes DIGCTR EQU H'10' ; 8 bit counter, only 2 lowest bits actually used DIGIT EQU H'11' ; hold digit number to access table INTCNT EQU H'12' ; counts # interrupts to determine when 1 sec up FUDGE EQU H'13' ; allows slight adjustment every 7 interrupts RUNFLG EQU H'14' ; bit 0 only, tells if countdown in progress W_TEMP EQU H'15' ; temporarily holds value of W STATUS_TEMP EQU H'16' ; temporarily holds value of STATUS SECNT EQU H'17' ; used in counting 50, 20 msec delays for 1 sec CNTMSEC EQU H'18' ; used in timing of milliseconds ALARM EQU H'19' ; bit 0 only, used as flag for when to alarm OFFSET EQU H'1A' ; 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' #DEFINE SELECT_PB D'4' #DEFINE RB4 D'4' #DEFINE RB5 D'5' ;-------------------------------------------------------------------------; ; We set the start of code to orginate a location zero ; ;-------------------------------------------------------------------------; ORG 0 GOTO MAIN ; jump to the main routine NOP NOP NOP GOTO INTERRUPT ; interrupt routine ;-------------------------------------------------------------------------; ; This table is used to get a bit pattern that will turn on a digit ; ;-------------------------------------------------------------------------; BITPAT ADDWF PCL,f ; get bit pattern for transistors RETLW H'0E' ; a low, (0), turns the transistor on RETLW H'0D' RETLW H'0B' RETLW H'07' ;-------------------------------------------------------------------------; ; Initialization routine sets up ports and timer ; ;-------------------------------------------------------------------------; INIT MOVLW H'C0' ; PB6 & PB7 inputs all others outputs TRIS PORTB MOVLW H'10' ; Port RA4 input, others outputs TRIS PORTA MOVLW H'03' ; prescaler on TMR0 and 1:16 OPTION 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 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 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'0C' ; point at register to display MOVWF FSR ; use as pointer MOVF INDF,W ; get value of reg pointed to into W MOVWF PORTA ; output to CD4511 MOVF DIGIT,W ; recall digit # CALL BITPAT ; get bit pattern MOVWF PORTB ; select transistor 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 STATUS_TEMP,f ; old no flags trick again SWAPF STATUS_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 DECF SEC,f ; decrement seconds digit INCFSZ SEC,W ; test for underflow GOTO CKZERO MOVLW H'09' ; reset sec to 9 MOVWF SEC DECF SEC10,f ; decrement SEC10 INCFSZ SEC10,W ; check underflow GOTO CKZERO MOVLW H'05' MOVWF SEC10 DECF MIN,f INCFSZ MIN,W GOTO CKZERO MOVLW H'09' MOVWF MIN DECF MIN10,f 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 BSF ALARM, 0 ; set the alarm flag RETURN ;-------------------------------------------------------------------------; ; This is a routine to read a byte from the data EEPROM ; ;-------------------------------------------------------------------------; READEE MOVWF EEADR ; set up eeprom address from W BSF STATUS,RP0 ; change to page 1 BSF EECON1,RD ; set the read bit BCF STATUS,RP0 ; back to page 0 MOVF EEDATA,W ; return value in W 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 ; ;-------------------------------------------------------------------------; WRITEEE BSF STATUS,RP0 ; set up EEADR and EEDATA first CLRF EECON1 BSF EECON1,WREN ; enable write MOVLW H'55' ; magic sequence MOVWF EECON2 MOVLW H'AA' MOVWF EECON2 BSF EECON1,WR EELOOP BTFSC EECON1,WR ; wait for WR to go low GOTO EELOOP ; not yet BSF EECON1,WREN BCF EECON1,EEIF ; clear the interrupt flag BCF STATUS,RP0 ; return to page 0 RETURN ;-------------------------------------------------------------------------; ; This routine puts display registers into data EEPROM ; ;-------------------------------------------------------------------------; PUTEE MOVF SEC,W ; put digit registers into EEprom MOVWF EEDATA MOVLW H'01' ; EEPROM location 1 + ADDWF OFFSET,W ; offset from start MOVWF EEADR CALL WRITEEE MOVF SEC10,W MOVWF EEDATA MOVLW H'02' ; EEPROM location 2 + ADDWF OFFSET,W ; offset from start MOVWF EEADR CALL WRITEEE MOVF MIN,W MOVWF EEDATA MOVLW H'03' ; EEPROM location 3 + ADDWF OFFSET,W ; offset from start MOVWF EEADR CALL WRITEEE MOVF MIN10,W MOVWF EEDATA MOVLW H'04' ; EEPROM location 4 + ADDWF OFFSET,W ; offset from start MOVWF EEADR CALL WRITEEE 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 CALL WAITSTARTUP ; wait till no switches pressed CALL WAITSETUP CALL WAITSELECT ;-------------------------------------------------------------------------; ; This loop checks for either pushbutton and acts accordingly ; ;-------------------------------------------------------------------------; KEYCHKLOOP BTFSS PORTB,START_PB ; check for start pressed GOTO STARTCNT ; yes, start count BTFSS PORTB,SET_PB ; check for set pressed GOTO SETDISP ; yes, set display BTFSS PORTA,SELECT_PB ; check select pushbutton pressed GOTO SETSELECT ; yes, select starting count GOTO KEYCHKLOOP ; loop to catch key press ;-------------------------------------------------------------------------; ; 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 WAITSTARTUP ; wait for release of start key MOVLW D'244' ; reset INTCNT MOVWF INTCNT CLRF TMR0 ; and clear timer 0 BSF RUNFLG, 0 ; start the countdown ;-------------------------------------------------------------------------; ; Once started just loop looking for cancel or reaching 0000 ; ;-------------------------------------------------------------------------; MAINLOOP BTFSS PORTB,START_PB ; countdown in progress, check start GOTO EE2D ; start over again if pressed BTFSC ALARM, 0 ; reached 0000 yet? GOTO SOUNDALARM ; yes, turn alarm on GOTO MAINLOOP ; no start switch, continue looping ;-------------------------------------------------------------------------; ; This code sounds the alarm and waits on start to be pressed ; ;-------------------------------------------------------------------------; SOUNDALARM FINALWAIT BCF PORTB,RB4 ; speaker leads set up BSF PORTB,RB5 ; opposite polarity MOVLW 2 ; delay 2 milliseconds CALL NMSEC BSF PORTB,RB4 ; flip the speaker leads BCF PORTB,RB5 MOVLW 2 ; another 2 msec delay CALL NMSEC BTFSC PORTB,START_PB ; start button pressed GOTO FINALWAIT ; not yet CALL DLY20 ; debounce just to make sure BTFSC PORTB,START_PB ; second look GOTO FINALWAIT ; nah, keep waiting BCF PORTB,RB4 ; speaker leads set to same polarity BCF PORTB,RB5 CALL WAITSTARTUP ; now wait for the switch up GOTO EE2D ; start all over again ;-------------------------------------------------------------------------; ; 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 set button ; ;-------------------------------------------------------------------------; WAITSETUP BTFSS PORTB,SET_PB ; wait for release GOTO WAITSETUP ; not yet CALL DLY20 ; debounce release BTFSS PORTB,SET_PB ; 2nd check, make sure released GOTO WAITSETUP ; 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 ; ;-------------------------------------------------------------------------; SETDISP CALL WAITSETUP ; wait for set key to be released MOVLW H'0A' ; put A's in digits, (no display) MOVWF MIN10 ; 10's of minutes MOVWF MIN ; minutes MOVWF SEC10 ; 10's of seconds MOVWF SEC ; seconds STARTMIN10 CLRF MIN10 ; 0 now in MIN10 MOREMIN10 MOVLW H'32' ; 50 delays of 20 msec MOVWF SECNT ; into counting register WAIT1 CALL DLY20 BTFSS PORTB,SET_PB ; set key pressed? GOTO MINSET ; yes MIN10 now set DECFSZ SECNT,f ; finished 1 sec delay? GOTO WAIT1 ; continue wait INCF MIN10,f ; every second 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 MOREMIN10 ; set up another 1 sec delay MINSET CALL WAITSETUP ; wait for release of set key STARTMIN CLRF MIN ; 0 into MIN MOREMIN MOVLW H'32' ; 50 delays of 20 msec MOVWF SECNT ; into counting register WAIT2 CALL DLY20 BTFSS PORTB,SET_PB ; set pressed? GOTO SETSEC10 ; yes, finished with MIN DECFSZ SECNT,f ; finished 1 sec delay? GOTO WAIT2 ; continue wait 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 MOREMIN ; set up another 1 sec delay SETSEC10 CALL WAITSETUP ; wait release STARTSEC10 CLRF SEC10 ; 0 into SEC10 MORESEC10 MOVLW H'32' ; 50 delays of 20 msec MOVWF SECNT ; into counting register WAIT3 CALL DLY20 BTFSS PORTB,SET_PB ; set pressed? GOTO SETSEC ; yes quit incrementing DECFSZ SECNT,f ; finished 1 sec delay? GOTO WAIT3 ; continue wait 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 MORESEC10 ; set up another 1 sec delay SETSEC CALL WAITSETUP ; wait for release STARTSEC CLRF SEC ; 0 into SEC MORESEC MOVLW H'32' ; 50 delays of 20 msec MOVWF SECNT ; into counting register WAIT4 CALL DLY20 BTFSS PORTB,SET_PB ; set button pressed? GOTO FINSET ; yes finished setting digits DECFSZ SECNT,f ; finished 1 sec delay? GOTO WAIT4 ; continue wait INCF SEC,f ; every second increment SEC MOVLW H'0A' ; reached 10? SUBWF SEC,W BTFSC STATUS,Z ; Z set if reached 10 GOTO STARTSEC ; put zero in if Z set GOTO MORESEC ; set up another 1 sec delay FINSET BCF INTCON, GIE ; disable interrupts CALL PUTEE ; put new digits into EEPROM BSF INTCON, GIE ; re-enable interrupts CALL WAITSETUP ; make sure set switch up GOTO KEYCHKLOOP ; start checking buttons again ;-------------------------------------------------------------------------; ; Selects starting count by changing EEPROM location 0 ; ;-------------------------------------------------------------------------; SETSELECT 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 MOVWF EEADR ; set up address MOVF OFFSET,W ; offset # into W MOVWF EEDATA ; set up data BCF INTCON,GIE ; clear GIE, disable interrupts CALL WRITEEE ; save # in location 0 BSF INTCON,GIE ; re-enable interrupts CALL GETEE ; get new start count into display CALL WAITSELECT ; make sure select switch is up 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 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 ;-------------------------------------------------------------------------; ; Here we set up the initial values of the digits in data EEPROM ; ;-------------------------------------------------------------------------; ORG H'2100' DE 0, 1, 0, 0, 0 ; 1st starting # DE 2, 0, 0, 0 ; 2nd starting # DE 3, 0, 0, 0 ; 3rd starting # DE 4, 0, 0, 0 ; 4th starting # DE 5, 0, 0, 0 ; 5th starting # DE 6, 0, 0, 0 ; 6th starting # DE 7, 0, 0, 0 ; 7th starting # DE 8, 0, 0, 0 ; 8th starting # DE 9, 0, 0, 0 ; 9th starting # DE 0, 1, 0, 0 ; 10th starting # DE 1, 1, 0, 0 ; 11th starting # DE 2, 1, 0, 0 ; 12th starting # DE 3, 1, 0, 0 ; 13th starting # DE 4, 1, 0, 0 ; 14th starting # DE 5, 1, 0, 0 ; 15th starting # END <P>See: <UL> <LI> </UL> <P> </BODY></HTML>
file: /Techref/microchip/cntdn/cntdn.asm, 26KB, , updated: 2013/9/8 03:28, local time: 2024/11/5 15:25,
13.59.75.169:LOG IN ©2024 PLEASE DON'T RIP! THIS SITE CLOSES OCT 28, 2024 SO LONG AND THANKS FOR ALL THE FISH!
|
©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://linistepper.com/Techref/microchip/cntdn/cntdn.asm"> microchip cntdn cntdn</A> |
Did you find what you needed? |