; reads output from an 8870 DTMF decoder and controls a bank of relays. ; When a "*" is found, it operates an audio mute relay to prevent downstream ; equipment seeing the folowing tones. The relay releases after seeing a "#" ; or 5 seconds has elapsed, whichever happens sooner. ; Code sequences "*50#" through to "*55#" select one of six mutually exclusive ; relays. Code "*56#" and "*57#" switch one relay on and off respectively. ; Codes "*58#" and "*59#" switch a second relay on and off respectively, this ; relay will also switch off 5 minutes after *58#. ; Codes "*5A#" through "*5D#" are ignored. ; Note RB pin mapping (because of PCB layout) : ; RB 0 1 2 3 4 5 6 7 ; relay 0 1 3 2 7 6 4 5 list r=hex,p=16c84 W equ 0 same equ 1 PCL equ 02 STATUS equ 03 PORT_A equ 05 PORT_B equ 06 INTCON equ 0B OPTREG equ 01 TRIS_A equ 05 TRIS_B equ 06 relays equ 10 mfcode equ 11 cntdown equ 12 timeout equ 13 slocnt1 equ 14 slocnt2 equ 15 org 0000 ;tell assembler to start at 000H init goto start org 0004 ;interrupt vector rtc_interrupt decfsz slocnt1,same ;decrement 1st prescaler goto rtc_int_1 decfsz slocnt2,same ;decrement 2nd prescaler goto rtc_int_1 bcf relays,4 ;turn relay 6 off bcf PORT_B,4 rtc_int_1 decfsz cntdown,same ;count down and skip next if = 0 goto counting ;still counting if not reached zero bsf timeout,0 ;set timed out bit bcf INTCON,2 ;clear interrupt flag retfie ;return counting bcf timeout,0 ;clear timed out bit bcf INTCON,2 ;clear interrupt flag retfie ;return ; subroutines wait_strobe btfsc timeout,0 ;see if timed out goto set_z ;set Z flag if timeout ocurred btfss PORT_A,4 ;see if Strobe is active on RA4 goto wait_strobe ;loop until it is movfw PORT_A ;retreive the code from the 8870 movwf mfcode ;store it in mfcode bcf mfcode,4 ;ensure strobe isn't seen as data bcf STATUS,2 ;return with Z=0 if tone decoded return set_z bsf STATUS,2 ;return with Z=1 if timed out waiting return wait_no_strobe btfsc PORT_A,4 ;see if strobe is active on RA4 goto wait_no_strobe ;loop until it isn't return start_timer movlw H'44' ;software prescaler for 5 seconds movwf cntdown return start_slo_timer movlw H'10' ;set relay 6 auto turn off counters movwf slocnt2 ;to (16 * 256 * RTC interrupt) = 5 mins clrf slocnt1 return ; Start of setup and decode routines: start movlw B'00100000' ;select register page 1 movwf STATUS clrf TRIS_B ;set all port B pins to output mode movlw B'00011111' ;set all port A pins to input mode movwf TRIS_A movlw B'10000111' movwf OPTREG ;sets: pull-up on port B OFF ; RTCC counts internal clock ; prescaler connected to RTCC ; prescaler divides by 256 ; (other bits unimportant) clrw ;clear the working register movwf STATUS ;switch back to register page 0 clrf PORT_B ;all outputs off bsf PORT_B,0 ;default to relay 0=ON at start up clrf relays clrf timeout movlw B'10100000' movwf INTCON ;global and RTCC interrupts enabled decode call wait_no_strobe ;start running when no tone present bcf PORT_B,5 ;ensure audio isn't muted clrf timeout ;set timeout condition until later call wait_strobe ;wait for a tone to be received movlw H'0B' ;0B is the code for DTMF "*" subwf mfcode,W ;set zero flag if "*" was received btfsc STATUS,2 ;skip next if it was not a "*" goto got_star goto decode ;look for another one got_star call start_timer ;start time-out timer bsf PORT_B,5 ;enable mute relay call wait_no_strobe ;wait for second tone call wait_strobe btfsc STATUS,2 ;abort if timed out goto decode movlw H'05' subwf mfcode,W ;set zero flag if second tone was 5 btfsc STATUS,2 ;skip next if it was not a 5 goto got_5 goto get_# ;wait for # to end invalid sequence ; to reach here, the tone sequence "*5" has been found, now decode request ; according to the third tone but don't action it until a "#" is seen. got_5 call wait_no_strobe call wait_strobe ;wait for third tone btfsc STATUS,2 ;abort if timed out goto decode call wait_no_strobe ;wait for tone to finish movf mfcode,W ;pick up keyed digit addwf PCL,same ;jump ahead to vector goto decode ;5D (mf code 0000) goto got_51 goto got_52 goto got_53 goto got_54 goto got_55 goto got_56 goto got_57 goto got_58 goto got_59 goto got_50 goto decode ;* goto decode ;# goto decode ;5A goto decode ;5B goto decode ;5C (mf code 1111) got_50 movlw B'11110000' ;mask to keep toggle bits & mute andwf relays,same ;clear bits 3,2,1,0 bsf relays,0 ;set bit 0 goto get_# got_51 movlw B'11110000' ;mask to keep toggle bits & mute andwf relays,same ;clear bits 3,2,1,0 bsf relays,1 ;set bit 1 goto get_# got_52 movlw B'11110000' ;mask to keep toggle bits & mute andwf relays,same ;clear bits 3,2,1,0 bsf relays,3 ;set bit 3 goto get_# got_53 movlw B'11110000' ;mask to keep toggle bits & mute andwf relays,same ;clear bits 3,2,1,0 bsf relays,2 ;set bit 2 goto get_# got_54 bsf relays,7 ;set bit 7 ON goto get_# got_55 bcf relays,7 ;set bit 7 OFF goto get_# got_56 bsf relays,6 ;set bit 6 ON goto get_# got_57 bcf relays,6 ;set bit 6 OFF goto get_# got_58 bsf relays,4 ;set bit 4 ON call start_slo_timer ;start the auto turn off counter goto get_# got_59 bcf relays,4 ;set bit 4 OFF get_# call wait_strobe ;wait for 4th tone btfsc STATUS,2 ;abort if timed out goto decode movlw H'0C' ;0C is the DTMF code for "#" subwf mfcode,W ;if # received set Z flag btfsc STATUS,2 ;skip next if not a # goto got_# call wait_no_strobe goto get_# ;only # is valid, loop until found ;or timeout got_# call wait_no_strobe ;wait for the tone to finish movfw relays ;use the "relays" variable to set RB movwf PORT_B goto decode ;all done, check for new sequence retlw '(' retlw 'C' retlw ')' retlw 'G' retlw 'W' retlw '6' retlw 'B' retlw 'W' retlw 'X' end