The "dead time" in the title refers to the time period after the melody is played when button presses are ignored. This discourages (but unfortunately does not prevent) pranksters (usually kids) from playing with the door chime. Also prevents impatient visitors/mailmen/couriers/extraterrestrials from making the chime go off continuously to put you into panic mode. Moreover, the circuit cannot be fooled by taping down the button in the hopes of forcing the circuit to keep playing the tune since the microcontroller only responds to edge triggering.
VR1 = L7812 +12V voltage regulator 1000mA
VR2 = 78L05ACZ +5V voltage regulator 100mA
MCU = Microchip PIC10F202 microcontroller
PB = bell push
OC1 = Avago HCPL-817 optoisolator
A1 = S9013 NPN transistor
BR = W01M 100V 1.5A bridge rectifier
XF = 220VAC to 6VAC transformer
SPKR = 8-ohm, 250mW, 3-inch speaker
The speaker is powered with 12VDC to significantly increase the output volume. As with the door status detector, I used an old computer speaker. PB is located several meters away from the circuit board. The internal weak pull-ups of the MCU are used so no external resistors are necessary on the collector of the optotransistor. I installed this circuit over three years ago and thus far I've not had any problems. Still working like a charm.
See the door open/closed detector for the principle of operation of the melody playing routines. Debounce routine works by storing the last eight readings in one 8-bit variable. Pushbutton is deemed not bouncing if the the variable is equal to 0x00 or 0xFF. Any other value means the switch is bouncing. Upon detection of a falling edge MCU plays the melody just once. To implement the dead time a simple one-second delay routine is called several times (depending on how many seconds is specified in the constant
secdelay
) after playing the tune and before handing back control to the pushbutton polling routine. When the melody is being played and during the dead time PB is not polled therefore button pushes are ignored. Because there's only one timer in the PC10F202, timer 0 is used for both playing the
notes and for polling of the switches. The prescale values are different
for the two applications and so OPTION
register is edited accordingly when switching between the two.et.inc contains various defines and macro.
; ******************************************************************************** ; ; DOOR CHIME ; February 2009 ; ; When bell push is momentarily pressed a melody is played. ; After the melody has finished there is a delay of 15 seconds when PB presses are ignored. ; Because PB is not polled when melody is playing and during the delay, ; repeatedly pressing PB during this time does not result in any action. ; Since the circuit responds only to edge triggering keeping the bell push depressed ; will not result in any further action. ; ; MCU has debounce firmware that monitors bell push switch readings. Upon detection of a falling edge ; MCU plays a sequence of musical notes. Firmware does not react to a rising edge. ; ; MCU weak pull-ups are enabled in firmware. ; Watchdog timer is activated. WDT nominal time-out according to datasheet is 18ms (without prescaler) ; ; ******************************************************************************** processor 10F202 #include p10F202.inc #include et.inc __config _MCLRE_OFF & _CP_OFF & _WDT_ON cblock 0x08 CYCLES ; determines how long the note sounds; value of 4 makes the note sound for approx 0.3sec LENGTH:2 ; time the note will play NOTE ; note's T/2 in terms of TMR0 initial value PB_VAL ; each bit is a push button switch reading; bit0 has the latest reading; bits are shifted left during each TMR0 rollover FEN ; assortment of flag and enable bits for various purposes COUNTER:3 ; loop counters COUNTER2:2 ; loop counters endc ; ******************************************************************** ; comment out when not debugging ; #define debug ; ******************************************************************** ifdef debug #define secdelay .1 else #define secdelay .15 ; number of seconds after melody has ended before bell push can be pressed again for the chime to play again endif #define spkr GPIO,2 ; output speaker via NPN transistor #define pb GPIO,0 ; input from bell push ; macro for playing the note ; _note is the note's T/2 (half period) ; _length is the number of times the note is played key macro _note, _length movlf _note, NOTE movlf _length, LENGTH call PlayNote endm ; see wikipedia article "scientific pitch notation" for table of frequency values of notes ; B4 = ti = 493.88 Hz, period = 2.0248 ms, T/2 = 1.0124 us ; C5 = do = 523.25 Hz, period = 1.9111 ms, T/2 = 955.57 us ; D5 = re = 587.33 Hz, period = 1.7026 ms, T/2 = 851.31 us ; E5 = mi = 659.26 Hz, period = 1.5168 ms, T/2 = 758.43 us ; F5 = fa = 698.46 Hz, period = 1.4317 ms, T/2 = 715.86 us ; G5 = sol = 783.99 Hz, period = 1.2755 ms, T/2 = 637.76 us ; A5 = la = 880.00 Hz, period = 1.1364 ms, T/2 = 568.18 us ; B5 = ti = 987.77 Hz, period = 1.0124 ms, T/2 = 506.19 us ; C6 = do = 1046.5 Hz, period = 955.57 us, T/2 = 477.78 us ; D6 = re = 1174.7 Hz, period = 851.28 us, T/2 = 425.64 us ; E6 = mi = 1318.5 Hz, period = 758.44 us, T/2 = 379.22 us ; given internal clock = 4Mhz and timer0 prescaler = 1:4 ; timer zero rolls over to zero every 1microsecond x 4 x TMR0 steps ; TMR0 steps = (T/2) / (1 us x 4) ; TMR0 initial value = 256 - TMR0 steps ; the following values should be loaded into TMR0 in order to produce the above notes, respectively #define B4 .256 - .253 #define C5 .256 - .239 #define D5 .256 - .213 #define E5 .256 - .190 #define F5 .256 - .179 #define G5 .256 - .159 #define A5 .256 - .142 #define B5 .256 - .127 #define C6 .256 - .119 #define D6 .256 - .106 #define E6 .256 - .95 ; in the PlayNote subroutine LENGTH determines how many times the note will play. ; since T/2 for every note is different LENGTH must be different in order for each note to play for the same length of time ; LENGTH is computed as follows: L1 x T1 = L2 x T2 ; where L1 = length note 1, T1 = period of note 1, L2 = length of note 2, T2 = period of note2 ; arbitrarily set LENGTH for E6 = 200 (leave room for a few more higher notes) #define LB4 .75 #define LC5 .79 #define LD5 .89 #define LE5 .100 #define LF5 .106 #define LG5 .119 #define LA5 .133 #define LB5 .150 #define LC6 .159 #define LD6 .178 #define LE6 .200 #define pb_level FEN,0 ; voltage level: 1 = hi, 0 = low #define option_poll_sw b'10000011' ; value to copy to OPTION register when polling switches ; pullups enabled, prescaler to timer0, prescaler = 1:16 #define option_chime b'10000001' ; value to copy to OPTION register in chime routine ; pullups enabled, prescaler to timer0, prescaler = 1:4 #define option_no_wpu b'11000011' ; value to copy to OPTION register when polling switches but with weak pull-ups off #define tmr_init_val .11 ; initial value for timer0, given 4Mhz clock and prescaler 1:16, TMR0 will rollover every 3.92ms org 0x0 movwf OSCCAL ; calibrate the chip goto initialize ; ======================================================================================= ; subroutines ; ; 10F202 can only call subroutines if they are located in first 256 memory locations ; ======================================================================================= ; --------------------------------------------------------------------------------- ; Notes are played by switching the speaker on and off at the frequency of the note. ; the following routine also plays the note for a specified time as determined by LENGTH and CYCLES PlayNote: movff NOTE, TMR0 movff LENGTH, LENGTH+1 movff CYCLES, COUNTER bsf spkr loop_note dnxnotzero TMR0 goto loop_note movff NOTE, TMR0 toggle spkr clrwdt decfsz LENGTH+1,f goto loop_note movff LENGTH, LENGTH+1 decfsz COUNTER,f goto loop_note bcf spkr return ; --------------------------------------------------------------------------------- ; --------------------------------------------------------------------------------- OptionChime: movlw option_chime option return ; --------------------------------------------------------------------------------- ; --------------------------------------------------------------------------------- OptionPollSw: movlw option_poll_sw option return ; --------------------------------------------------------------------------------- ; --------------------------------------------------------------------------------- ; approximately one second delay Delay_onesec: clrf COUNTER clrf COUNTER+1 movlf .5, COUNTER+2 delay1sec_loop decfsz COUNTER,f goto delay1sec_loop clrwdt decfsz COUNTER+1,f goto delay1sec_loop decfsz COUNTER+2,f goto delay1sec_loop return ; --------------------------------------------------------------------------------- ; --------------------------------------------------------------------------------- ; the following melody is played when bell push is pressed (falling edge detected) SoundChime: call OptionChime movlf .4, CYCLES ; melody from the movie Close Encounters of the Third Kind ; -------------------------------------------------------- key D6, LD6 key E6, LE6 key C6, LC6 key E5, LE5 key G5, .255 ; time interval when chime has already finished playing ; and button presses are ignored movlf secdelay, COUNTER2 call Delay_onesec decfsz COUNTER2,f goto $-2 call OptionPollSw return ; --------------------------------------------------------------------------------- ; ======================================================================================= ; main program ; ======================================================================================= ; --------------------------------------------------------------------------------- initialize: movlw b'1' tris GPIO clrwdt call OptionPollSw clrf GPIO ; speaker off movlf 0xFF, PB_VAL ; all bits hi, pb contacts considered open bsf pb_level ; level = hi, pb contacts considered open movlf tmr_init_val, TMR0 ; --------------------------------------------------------------------------------- main: poll_timer0: dnxnotzero TMR0 ; poll TMR0 until it rolls over goto poll_timer0 movlf tmr_init_val, TMR0 clrwdt poll_timer0_end: ; poll and check bell push; store value in 8-bit record ; if PB_VAL = 0xFF AND pb_level = 0 then let pb_level = 1, this is a rising edge detect, do nothing ; if PB_VAL = 0x0 AND pb_level = 1 then let pb_level = 0, this is a falling edge detect and chime is sounded ; if PB_VAL > 0 AND PB_VAL < 0xFF then switch is bouncing, so do nothing ; if PB_VAL = 0xFF AND pb_level = 1 then there is no level change, so do nothing ; if PB_VAL = 0 AND pb_level = 0 then there is no level change, so do nothing check_pb: rlf PB_VAL,f ; discard oldest switch reading bcf PB_VAL,0 ; carry bit will be moved into bit zero so clear bit0 dnxbit1 pb bsf PB_VAL,0 dnxeqlit PB_VAL, 0xFF goto all_bits_hi dnxzero PB_VAL goto all_bits_lo goto check_pb_end all_bits_hi: dnxbit1 pb_level goto check_pb_end bsf pb_level ; rising edge detected goto check_pb_end all_bits_lo: dnxbit0 pb_level goto check_pb_end bcf pb_level ; falling edge detected call SoundChime check_pb_end: goto main ; --------------------------------------------------------------------------------- end
No comments:
Post a Comment