; ; ; Impulse Dial to DTMF tone converter ; Copyright (C) 2005 Lars Stollenwerk, LSto@gmx.de ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ; ; ; ; ************************************************************** ; ; Pinout ; ---------------------------------- ; PORTA: 0 High tone out ; 1 Low tone out ; ; 2 7 Segment Reset ; 3 Hook in ; 4 7 Segment Conunt ; ; PORTB: 0 Key in Row 1 2 3 ; 1 Key in Row 4 5 6 ; 2 Key in Row 7 8 9 ; 3 Key in Row * 0 # ; 4 Key out Col 1 4 7 * ; 5 Key out Col 2 5 8 0 ; 6 Key out Col 3 6 9 # ; 7 empty, must be input or 1 for Keypad readout ; ; ************************************************************** ; ; Osz Freq.: 4MHz ; ; set PIC type ; list p=16f84a #include ; ; bis 4 MHz: Power on Timer, no Watchdog, XT-Oscillator ; __CONFIG _PWRTE_ON & _WDT_OFF & _XT_OSC ; ; ************************************************************** ; Memory usage fWms Equ 0x0c ; Wms fWait Equ 0x0d ; Wait fNum Equ 0x0e ; DTMF, IWV, Key, Display fTimeo Equ 0x0f ; IWV fLen Equ 0x10 ; DTMF fToneH Equ 0x11 ; DTMF fToneL Equ 0x12 ; DTMF fToneHc Equ 0x13 ; DTMF fToneLc Equ 0x14 ; DTMF fDisc Equ 0x15 ; Disp fKey Equ 0x16 ; Key ; Equ 0x17 ; Equ 0x18 ; Equ 0x19 ; Equ 0x1a ; Equ 0x1b ; Equ 0x1c ; Equ 0x1d ; Equ 0x1e ; Equ 0x1f fHack Equ 0x20 ; Hack ; ************************************************************** ; Options ; Zero Hack iHack Equ 0x00 ; Use 0 hack ;iHack Equ 0xff ; Don't use 0 hack ; ************************************************************** Init ; Init hardware bsf STATUS, RP0 ; switch to bank 1 movlw B'10001111' ; Port B Keypad movwf TRISB movlw B'00001000' ; Port RA3 input, rest output movwf TRISA bcf OPTION_REG, NOT_RBPU ; Pull up for PORTB inputs bcf STATUS, RP0 ; switch bank to bank 0 clrf PORTB ; switch all outputs off clrf PORTA goto HookUp ; ************************************************************** ; DTMF tones ; ************************************************************** ; ; f =~ 1 MHz / 12 / ( n + 1 ) DTMF_L addwf PCL, F ; jump to value w nop retlw 0x75 ; 1 697 Hz 0x76 retlw 0x75 ; 2 697 Hz 0x76 retlw 0x75 ; 3 697 Hz 0x76 retlw 0x6A ; 4 770 Hz 0x6B retlw 0x6A ; 5 770 Hz 0x6B retlw 0x6A ; 6 770 Hz 0x6B retlw 0x60 ; 7 852 Hz 0x61 retlw 0x60 ; 8 852 Hz 0x61 retlw 0x60 ; 9 852 Hz 0x61 retlw 0x57 ; 0 941 Hz 0x58 retlw 0x57 ; * 941 Hz 0x58 retlw 0x57 ; # 941 Hz 0x58 DTMF_H addwf PCL, F ; jump to value w nop retlw 0x44 ; 1 1209 Hz retlw 0x3D ; 2 1336 Hz retlw 0x37 ; 3 1477 Hz retlw 0x44 ; 4 1209 Hz retlw 0x3D ; 5 1336 Hz retlw 0x37 ; 6 1477 Hz retlw 0x44 ; 7 1209 Hz retlw 0x3D ; 8 1336 Hz retlw 0x37 ; 9 1477 Hz retlw 0x3D ; 0 1336 Hz retlw 0x44 ; * 1209 Hz retlw 0x37 ; # 1477 Hz ; ************************************************************** ; Display ; ************************************************************** ; ; 01 ; 40 02 ; 80 ; 20 04 ; 10 08 DISP addwf PCL, F ; jump to value w nop retlw 0x06 ; 1 retlw 0xb3 ; 2 retlw 0x97 ; 3 retlw 0xc6 ; 4 retlw 0xd5 ; 5 retlw 0xf5 ; 6 retlw 0x07 ; 7 retlw 0xf7 ; 8 retlw 0xd7 ; 9 retlw 0x77 ; 0 retlw 0x80 ; * retlw 0xe6 ; # ; ************************************************************** ; Subroutine: Wait 1 ms ; ; Variables: fW1ms ; ************************************************************** Wms movlw D'110' ; Time constant for 1 ms movwf fWms ; Init counter Wmsa nop nop nop nop nop nop decfsz fWms, F ; time over? goto Wmsa ; -> no return ; ************************************************************** ; Subroutine: Wait ; ; Waits w ms ; Variables: fWait ; ************************************************************** Wait movwf fWait ; Init counter Waita call Wms decfsz fWait, F ; time over? goto Waita ; -> no return ; ************************************************************** ; Subroutine: Dial DTMF, Number in fNum ; ; Variables: fToneL, fToneH, fToneLc, fToneHc, fLen ; ************************************************************** DTMF movf fNum, W ; read Number and ... call DTMF_H ; ... get high tone movwf fToneH movwf fToneHc movf fNum, W ; read Number and ... call DTMF_L ; ... get low tone movwf fToneL movwf fToneLc movlw 0xa0 ; init tone length movwf fLen DTMFa decfsz fToneHc,F ; half periode of high tone finished? goto DTMFb ; no movlw B'0000001' ; y -> toggle RA0 xorwf PORTA, F movf fToneH, W ; reload tone counter movwf fToneHc DTMFb decfsz fToneLc, F ; half periode of low tone finished? goto DTMFa ; no movlw B'0000010' ; y -> toggle RA1 xorwf PORTA, F movf fToneL, W ; reload tone counter movwf fToneLc decfsz fLen, F ; tone length over? goto DTMFa ; no bcf PORTA, 0 ; both pins off .. bcf PORTA, 1 ; .. to save current return ; ************************************************************** ; Main loop ; ; ************************************************************** HookDown ; Hook is down, so certainly we'll die soon. ; But maybe not. movlw 0x08 ; display code "decimal point" .. movwf fDisc ; .. to counter HookDa bsf PORTA, 4 ; Count display nop bcf PORTA, 4 decfsz fDisc, F ; Pattern finished? goto HookDa HookDb call Wms btfsc PORTA, 3 ; Hook up again? goto HookDb ; n -> wait on ; The supply power is very insecure at the moment, undefined ; voltage levels around the CA3140 may lead to wrong pulses. ; So wait a second ... movlw d'250' ; Wait .. call Wait movlw d'250' ; .. one .. call Wait movlw d'250' ; .. whole .. call Wait movlw d'250' ; .. second call Wait HookUp movlw iHack ; init 0 hack for first number movwf fHack bsf PORTA, 2 ; reset display nop bcf PORTA, 2 Main btfsc PORTA, 3 ; Hook up? goto IWV ; y -> read number movf PORTB, W ; look at keypad.. xorlw B'10001111' ; .. row inputs btfsc STATUS, Z ; Key pressed? goto Main ; n -> wait on ; ------------------------------------------------------------- ; read Keypad ; ; Variables: fNum, fKey ; ------------------------------------------------------------- Key ; determine row movf PORTB, W ; Read keypad movwf fKey ; and save for rotation clrf fNum ; clear Number Keya incf fNum, F ; Number + 1 rrf fKey, F ; rot bit to carry btfsc STATUS, C ; Bit clear? goto Keya ; n -> search on ; row finished, test if valid movf fNum, W ; get Number addlw 0xfb ; 0xfb + 4 = 0xff btfsc STATUS, C ; fNum > 4 ? goto Main ; y -> abort ; calculate row offset decf fNum, F ; fKey in { 0, 1, 2, 3 } rlf fNum, W ; fKey * 2 .. ( C was clear ) addwf fNum, F ; .. + fKey = 3 * fkey; fKey in { 0, 3, 6, 9 } ; determine column movlw B'11110111' ; Mask with one 0 movwf fKey bsf STATUS, C ; set C, belongs to mask Keyb incf fNum, F ; Number + 1 movf fNum, W ; get Number sublw D'12' ; 12 - Number btfss STATUS, C ; Number > 12 ? goto Main ; y -> abort rlf fKey, F ; rotate Mask movf fKey, W ; test keypad with mask movwf PORTB xorwf PORTB, W ; pressed key cahnges mask btfsc STATUS, Z ; read same pattern? goto Keyb ; y -> search on ; column finished, swap * and 0 movlw D'10' ; load Number for * xorwf fNum, W btfss STATUS, Z ; got * ? goto Keyc ; n -> test 0 incf fNum, F ; write 0x0b for * goto Keyd ; number finished Keyc movlw D'11' ; load Number for 0 xorwf fNum, W btfss STATUS, Z ; got 0 ? goto Keyd ; n -> number finished decf fNum, F ; write 0x0a for 0 ; Number finished Keyd movf fNum, W ; write number ... movwf fHack ; ... to 0 Hack ; wait for key release clrf PORTB ; reset Keypad Keye movlw B'10001111' ; load all released mask xorwf PORTB, W ; test Keypad btfss STATUS, Z ; all Keys released? goto Keye ; n -> wait on goto Display ; ------------------------------------------------------------- ; Read IWV number ; ; Variables: fNum, fTimeo ; ------------------------------------------------------------- IWV movlw 0x00 ; Clear number to read movwf fNum IWVa ; begin of pulse movlw D'120' ; Pulse length max 120 ms movwf fTimeo IWVb call Wms btfss PORTA, 3 ; Hook still up? goto IWVc ; n -> end of pulse decfsz fTimeo, F ; Timeout? = pulse too long goto IWVb ; n -> wait on goto HookDown ; y -> HookDown IWVc ; end of one pulse incf fNum, F ; Increase number movlw D'120' ; gap between pulses max 120 ms movwf fTimeo IWVd call Wms ; Wait 1 ms btfsc PORTA, 3 ; Hook up again? goto IWVa ; y -> begin of pulse decfsz fTimeo, F ; Timeout? = last pulse goto IWVd ; n -> wait on ; Number is read, wait for silence ; (There are tow additional 'empty' pulses of the dial which ; might noise disturbing the tone) ;movlw D'250' ; wait 250 ms ;call Wait ; Assure number is in [ 1..9, 0 ] movlw 0xf5 ; 5f + 0a = ff addwf fNum, W ; Sum should be <= ff btfsc STATUS, C ; Number allowed? goto Main ; n -> wait in main loop ; ------------------------------------------------------------- ; Display number ; ; Variables: fNum, fDisc ; ------------------------------------------------------------- Display movf fNum, W ; get Number call DISP ; write display pattern .. movwf fDisc ; .. to counter Disa bsf PORTA, 4 ; Count display nop bcf PORTA, 4 decfsz fDisc, F ; Pattern finished? goto Disa movlw d'250' ; show pattern > 250 ms call Wait ; ------------------------------------------------------------- ; Leading 0 Hack ; ------------------------------------------------------------- Dial movf fHack, F ; Test Hack btfss STATUS, Z ; First number? goto Diala ; no -> dial number movf fNum, W ; rescue number movwf fHack movlw 0x0a ; dial leading 0 movwf fNum call DTMF movf fHack, W ; restore number movwf fNum movlw D'100' ; wait 100 ms call Wait Diala call DTMF ; dial number ; ------------------------------------------------------------- ; Switch display off ; ------------------------------------------------------------- bsf PORTA, 2 ; reset display nop bcf PORTA, 2 ; ------------------------------------------------------------- ; Number is finished ; ------------------------------------------------------------- READY ; wait for silence on line movlw D'100' ; wait 100 ms call Wait goto Main END