# Código detector (Decodificar)  de tonos DTMF para 16F87X



## francote (Ago 1, 2008)

Cordial saludo para todas y todos. Esta es mi primera participación.

Como lo digo en el anunciado: Necesito “código detector (Decodificar) de tonos DTMF para 16F87X”, que sea sencillo de inserta como parte del compilador Basic de Proton+ de Crownhill, para ser llamado con Call (Por ejemplo).

Encontre uno en (http://www.geocities.com/constantinescuradu/content/dtmfrem/dtmf.asm) el cual anexo, pero con o sin cambios de adaptación, da errores o se queda en el “limbo”.

Según he leido en Internet, el código debe ser preferiblemente en Assembler y el PIC debe correr a 20 Mhz para lograr una detección aceptable.

Anticipo mis agradecimientos por la ayuda. 

PD: Anexo también un programa gratuito generador de tonos DTMF con salida por la tarjeta de sonido del PC. Los tonos son bastante similares a los generados por chips.


----------



## asherar (Ago 1, 2008)

Hola, y bienvenido al foro:

Hace unos años (2002-2003) yo intenté lo mismo (detectar DTMF en asm, con un pic), y 
llegué a la conclusión que generar DTMF con PIC es relativamente sencillo pero detectarlo, 
casi imposible. Conviene toda la vida usar el 8870.
Esto tomalo "con pinzas": fue hace mas de 5 años.

Tal vez en tu tarea te exigen usar un pic.  
Hay que diferenciar dos frecuencias muy cercanas, lo que significa hacer un filtro muy 
preciso, y eso son muchas cuentas a tiempo real. 
Esto tal vez no sería tan difícil de hacer numéricamente en assembler si uno tuviera el 
desfasaje inicial ente las dos sinusoides componentes. Guardás todas las combinaciones 
ya digitalizadas y listo. Pero por desgracia la señal viene con fase aleatoria 
(lo de "listo" es un decir).

Aparte, si lo pensás homologar, las empresas telefónicas tienen estándares bastante 
apretados que cumplir. 

Es flor de problema el que te han tirado. Yo no lo encararía copiando códigos bajados de 
internet que no se sabe qué son. Más empezaría pensando en implementar algo parecido 
a una FFT reducida. 

Si, de todas maneras, igual vas a usar ese asm que tenés, yo trataría de analizarlo paso a paso con algo como el ICD2, que te permite ver en qué punto se te "cuelga". 

Éxitos !


----------



## tiopepe123 (Ago 1, 2008)

pasate por microchip hay un detector de todo por DFT que evidentemente esta en ASM, hasta hay una utilidad para hacer pruebas y como implementar.

Es un zip, te lo bajas, lo instalas y vas a la carpeta donde se ha instalado donde encontraras los tutoriales de como funciona y como implementarlo.

Leelo un poco por encima ya que s curioso el truco para detectar los tonos.


----------



## gallito (Ago 7, 2008)

hola francote.

ese codigo que mecionas trabaja muy pero en asm. en proton lo he intentado hacer pero no me a dado buenos resultados, 

en proton hay una instruccion llamada ASM Asm_Main_Program --- ENDASM dentro de ella puedes colocar el codigo asm, y llamarla con  call   Asm_Main_Program.


Pero el problema que tengo del momento es que no me esta generando la interuption.

pues para la interupction encontre esta instruccion ON INTERRUPT GOTO My_Int

pero no se, no me a dado resultado.  Intentelo ud, depronto  le encuentres el motivo.

exitos.


----------



## francote (Ago 8, 2008)

Muchas gracias por las respuestas de Alejandro Sherar, tiopepe123 y gallito.
El código del que hago mención funciona bien. Hicimos pruebas insertándole “ruido blanco” (white noise) con una amplitud del 30% respecto al tono DTMF y no tuvo problemas en reconocerlos.
Con el permiso del autor del código que menciono, empezamos a hacer las adaptaciones para insertarlo en el Basic de Proton, pero como no conocemos mucho como insertarle assembler, no lo hemos podido compilar (Nos da errores).

Gallito, veo que has alcanzado más que nosotros. De pronto nos puedes facilitar el programa que estás haciendo en Proton con la rutina en assembler incorporada? De esa forma podríamos intentar ponerla a funcionar. Gracias

En esta ocasión me permito sugerirles un programa shareware completo (Com-Tekk Tone Generator) para los que estamos en este tema. Trae generación de varios tipos de tonos (DTMF, etc) y frecuencias, Osciloscópio, Analizador de Espectro y más. Es meritório el aporte de empresas como esta. Hallí hay otros de la misma calidad. La dirección es: http://www.comtekk.us/downloads.php

  Hasta pronto


----------



## gallito (Ago 14, 2008)

Hola muchachos, este es el codigo de que esta en la web solo le hice algunas modificaciones para trabajarlo desde proton, pero como le dije anteriormente, no se por que no me esta generando la interrupcion, pues es indispensable para la toma del numero corespondiente al DTFM, mirelo y cacharielo y si encuentras el error le agradezco que me informe que era.


hay otra forma de hacer el detector DTFM, que es utilizando el algoritmo de Goertzel, hay muy buena información al respecto, es relativamente sencillo de implementar, pues en proton trae  un comando para el coseno, pero lo unico es que este comando trabaja solo para la serie 18Fxxx. 


bueno compañero cualquier cosa estamos en contacto.



```
'=======================================================================================
Device 16f876a
XTAL = 20
'=======================================================================================
ALL_DIGITAL = TRUE 
;Config  HS_OSC, CPD_OFF, CP_OFF, WDT_OFF, BODEN_OFF, PWRTE_OFF 
Clear 'IMPORTANTE. Borra toda la memmoria RAM del PIC
'=======================================================================================
'************** User Variables *********************************************************
'=======================================================================================
dim RESULT as byte
dim FLAGS as byte   
dim COUNT_ as byte
dim TIME0 as byte 	;TIMEOUT LSB
dim TIME1 as byte
dim TIME2 as byte	;TIMEOUT MSB
dim EE_Byte as byte	; variable for EEwrite

dim SAMPLEBIT as byte
dim FSR_SAVE_DTMF as byte ;DTMF START ROUTINE TEMP
dim TEMP_VAL as byte 
dim TABLECOUNTER as byte
dim TEMP_TIMES as byte
dim LOWTEMPLATE	as byte
dim HIGHTEMPLATE as byte
dim BYTE_ as byte
dim RESULT1 as byte				; DECODED DIGIT OR 0
dim PCLATH_SAVE	as byte
dim W_TEMP	as byte
dim STATUS_TEMP	as byte
dim FSR_SAVE as byte

dim A697SIN as byte
dim A697COS	as byte
dim A770SIN as byte
dim A770COS	as byte
dim A852SIN	as byte
dim A852COS	as byte ; ACC
dim A941SIN	as byte
dim A941COS	as byte ; ACC
dim A1209SIN as byte
dim A1209COS as byte
dim A1336SIN as byte
dim A1336COS as byte;ACC
dim A1447SIN as byte
dim A1447COS as byte ;ACC
dim A1633SIN as byte
dim A1633COS as byte;ACC
;======================================================================================= 
 symbol 	DONE = FLAGS.0
 symbol 	TIMEOUT	= FLAGS.1
 symbol 	BEEP = FLAGS.2
;======================================================================================= 
       
        call Asm_Macros   
        ;ON INTERRUPT GOTO My_Int    ' Enable software interrupts, and point to interrupt handler
        gosub start
        high porta.1
        ON INTERRUPT GOTO My_Int    ' Enable software interrupts, and point to interrupt handler
       ; bcf     porta,2
        call asm_TomaDato
;=======================================================================================

;=======================================================================================
DISABLE      ' Disable interrupts in the handler
My_Int: 

ASM

INTERRUPT_VECTOR	
;	ORG	0X04
;======================================================================================= 
;	CONTEXT SAVE
;======================================================================================= 
C_SAVE
    
	MOVWF	W_TEMP
	SWAPF	STATUS,W
	CLRF	STATUS		;ENSURE BANK0 SAVE
	MOVWF	STATUS_TEMP

	MOVF	PCLATH,W	; SAVE PCLATH
	MOVWF   PCLATH_SAVE

	MOVF	FSR,W
	MOVWF	FSR_SAVE

    BCF		PIR1,TMR2IF	; RESET TIMER 2 INT FLAG

    bsf     porta,2

	BTFSS	PIR1,TMR2IF	; Exit ISR if it wasn't a TMR2 Overflow
	GOTO	C_RESTORE

 	BCF		PIR1,TMR2IF	; RESET TIMER 2 INT FLAG
;     	bcf     porta,2
	BTFSC	TIMEOUT		; CHECK IF NOT TIMEOUT
	GOTO 	CONTIN1
; DECREMENT TIMEOUT COUNTER
	DECF	TIME0, F
	BTFSS	STATUS, Z
	GOTO 	CONTIN1		; TIME0<>0
	DECF	TIME1, F
	BTFSS	STATUS, Z
	GOTO 	CONTIN1		; TIME1<>0
	BSF		TIMEOUT		; SET TIMEOUT=TRUE
CONTIN1:
; BEEP COUNTER
	BTFSS	BEEP		; CHECK IF NOT BEEP
	GOTO 	CONTIN2
	DECF	scrA,F
	BTFSS	STATUS, Z
	GOTO 	CONTIN2		
	movlw	1
	xorwf	PORTC, F	; flip port C0
	MOVF	TIME2, W	; RELOAD DELAY
	MOVWF	scrA
CONTIN2:
	BTFSC	DONE
	GOTO	C_RESTORE	; Skip if done
;======================================================================================= 
	;TEST LEVEL of RC1 and set BYTE
	CLRF	BYTE_
	BTFSS	PORTC, 1	
	GOTO	CONTINUE
PIN_HIGH
	COMF	BYTE_, F
CONTINUE
;======================================================================================= 
;Get the expected Lowband Bits
;======================================================================================= 
	MOVLW	LOW	LOWBAND 
	ADDWF	TABLECOUNTER,W
	MOVLW	HIGH	LOWBAND
	BTFSC	STATUS,C
	ADDLW	1
	MOVWF	PCLATH
	
	MOVF	TABLECOUNTER,W
	CALL	LOWBAND

	CLRF	PCLATH
	MOVWF	LOWTEMPLATE
	MOVF	BYTE_,W
	XORWF	LOWTEMPLATE, F	; APPLY INPUT OVER MASK
;======================================================================================= 
;Get the expected Highband Bits 
;======================================================================================= 
	MOVLW	LOW	HIGHBAND
	ADDWF	TABLECOUNTER,W
	MOVLW	HIGH	HIGHBAND
	BTFSC	STATUS,C
	ADDLW	1
	MOVWF	PCLATH
	
	MOVF	TABLECOUNTER,W
	CALL	HIGHBAND
	
	CLRF	PCLATH
	MOVWF	HIGHTEMPLATE
	MOVF	BYTE_,W
	XORWF	HIGHTEMPLATE, F	; APPLY INPUT OVER MASK
;======================================================================================= 
;	LOWTEMPLATE AND HIGHTEMPLATE 
;	CONTAIN THE EXPECTED VALUES
;	FOR THE INCOMING BIT
;======================================================================================= 
	MOVLW	LOW A697SIN
	MOVWF	FSR		;ACCUMULATOR ADDR
	MOVLW	8
	MOVWF	SAMPLEBIT
COMPAREBITL
	RLF 	LOWTEMPLATE,F
	BTFSS	STATUS,C	
	GOTO	MATCHL
	DECF	INDF,F
	GOTO	CONTINL
MATCHL	
	INCF	INDF,F	
CONTINL
	INCF	FSR,F
	DECFSZ	SAMPLEBIT,F
	GOTO	COMPAREBITL	;FINISH THE BYTE

	MOVLW	LOW A1209SIN
	MOVWF	FSR		;ACCUMULATOR ADDR
	MOVLW	8
	MOVWF	SAMPLEBIT
COMPAREBITH
	RLF 	HIGHTEMPLATE,F
	BTFSS	STATUS,C	
	GOTO	MATCHH
	DECF	INDF,F
	GOTO	CONTINH
MATCHH	
	INCF	INDF,F	
CONTINH
	INCF	FSR,F
	DECFSZ	SAMPLEBIT,F
	GOTO	COMPAREBITH	;FINISH THE BYTE
;======================================================================================= 
; Increment Tablecounter 0..255
;======================================================================================= 
	INCF	TABLECOUNTER,F
	MOVF	TABLECOUNTER,W
	XORLW	D'255'		;This is the number of samples to test against (max 7f)
	BTFSS	STATUS,Z
	GOTO	C_RESTORE
	BSF		DONE
; DTMF DECISION ALGORITHM
; compute absolute value  acc = ABS(acc)
	MOVLW	H'30'	
	MOVWF	FSR
TESTFORNEG
	BTFSC	INDF,7
	GOTO	NEG
	GOTO	NEXT
NEG
;	SUBTRACT F FROM 0
	MOVF	INDF,W
	SUBLW	0
	MOVWF	INDF
NEXT
	INCF	FSR,F
	MOVF	FSR,W
	XORLW	H'40'
	BTFSS	STATUS,Z
	GOTO	TESTFORNEG
; add acumulator results for sin and cos
	MOVLW	H'30'
	MOVWF	FSR
MORERESULTS
	MOVF	INDF,W
	CLRF	INDF
	INCF	FSR,F
	ADDWF	INDF,F
	MOVF	FSR,W
	INCF	FSR,F
	XORLW	H'3F'
	BTFSS	STATUS,Z
	GOTO	MORERESULTS
; compare acc with 64 of 255 
	MOVLW	0X31
	MOVWF	FSR
TEMPX1
	MOVF	INDF,W
	SUBLW	D'64'		;THRESHOLD
	RRF		RESULT,F
	INCF	FSR,F
	INCF	FSR,F
	MOVF	FSR,W
	XORLW	0X41
	BTFSS	STATUS,Z
	GOTO 	TEMPX1		
	COMF	RESULT,F
;======================================================================================= 
; RESULT IS 1633/1477/1336/1209/941/852/770/697 FOR VALUE>64
; DECISION ALGORITHM : A VALUE MUST BE DETECTED AT LEAST 2-3 TIMES 
; BEFORE IS CONSIDERED VALID / 
;======================================================================================= 
	MOVF	RESULT, W
	XORWF	TEMP_VAL,W	; COMPARE RESULT WITH TEMP_VAL
	BTFSC	STATUS, Z
	GOTO 	DECI1		; ==
	
	CLRF	TEMP_TIMES	
	MOVF	RESULT,W 	; TEMP_TIMES = 0
	MOVWF	TEMP_VAL	; TEMP_VAL = RESULT
	GOTO	CLEANUP		; START AGAIN
DECI1
	MOVLW	0XFF
	XORWF	TEMP_TIMES,W	; COMPARE TEMP_TIMES/255
	BTFSC	STATUS,Z
	GOTO CLEANUP		; ==255, START AGAIN
	INCF TEMP_TIMES, F	; <> 255, INC TEMP_TIMES
DECI3	
	
	MOVLW	.1		; 2 TIMES DETECTED -1 

	XORWF	TEMP_TIMES,W
	BTFSS	STATUS,Z
	GOTO	CLEANUP		; <> START AGAIN
; GOT ONE VALUE 2 TIMES !
	CLRW
	XORWF	TEMP_VAL, W	; COMPARE TEMP_VAL / 0
	BTFSC	STATUS,Z
	GOTO CLEANUP		; ==0, START AGAIN
DECI2				; <>0
;======================================================================================= 
;..GOT ONE CHARACTER, CONVERT IT TO DECIMAL....
;======================================================================================= 
	MOVF	RESULT,W	
	XORLW	D'17'
	BTFSC	STATUS,Z
	GOTO	GOTCHA1
	MOVF	RESULT,W
	XORLW	D'33'
	BTFSC	STATUS,Z
	GOTO	GOTCHA2
	MOVF	RESULT,W
	XORLW	D'65'
	BTFSC	STATUS,Z
	GOTO	GOTCHA3
	MOVF	RESULT,W
	XORLW	D'18'
	BTFSC	STATUS,Z
	GOTO	GOTCHA4
	MOVF	RESULT,W
	XORLW	D'34'
	BTFSC	STATUS,Z
	GOTO	GOTCHA5
	MOVF	RESULT,W
	XORLW	D'66'
	BTFSC	STATUS,Z
	GOTO	GOTCHA6
	MOVF	RESULT,W
	XORLW	D'20'
	BTFSC	STATUS,Z
	GOTO	GOTCHA7
	MOVF	RESULT,W
	XORLW	D'36'
	BTFSC	STATUS,Z
	GOTO	GOTCHA8
	MOVF	RESULT,W
	XORLW	D'68'
	BTFSC	STATUS,Z
	GOTO	GOTCHA9
	MOVF	RESULT,W
	XORLW	D'40'
	BTFSC	STATUS,Z
	GOTO	GOTCHA0
	MOVF	RESULT,W
	XORLW	D'72'
	BTFSC	STATUS,Z
	GOTO	GOTCHAPOUND
	MOVF	RESULT,W
	XORLW	D'24'
	BTFSC	STATUS,Z
	GOTO	GOTCHASTAR
; GOT ONLY TRASH...
	CLRF	TEMP_TIMES
	GOTO 	CLEANUP
;======================================================================================= 
; CONVERT ASCII	
GOTCHAPOUND
	MOVLW	.11			;H'23'
	GOTO	SENDIT
GOTCHASTAR
	MOVLW	.10			;H'2A'
	GOTO	SENDIT
GOTCHA1
	MOVLW	.1			;H'31'
	GOTO	SENDIT
GOTCHA2
	MOVLW	.2			;H'32'
	GOTO	SENDIT
GOTCHA3
	MOVLW	.3			;H'33'
	GOTO	SENDIT
GOTCHA4
	MOVLW	.4			;H'34'
	GOTO	SENDIT
GOTCHA5
	MOVLW	.5			;H'35'
	GOTO	SENDIT
GOTCHA6
	MOVLW	.6			;H'36'
	GOTO	SENDIT
GOTCHA7
	MOVLW	.7			;H'37'
	GOTO	SENDIT
GOTCHA8
	MOVLW	.8			;H'38'
	GOTO	SENDIT
GOTCHA9
	MOVLW	.9			;H'39'
	GOTO	SENDIT
GOTCHA0
	MOVLW	.0			;H'30'
	GOTO	SENDIT
SENDIT
	MOVWF	RESULT1		; PLACE RECEIVED CHAR IN RESULT1
	GOTO	C_RESTORE
;======================================================================================= 
CLEANUP
	MOVLW	0X2F		; start -1
	MOVWF	FSR
TEMPXX
	INCF	FSR,F
	CLRF	INDF
	MOVF	FSR,W
	XORLW	0X3F		; CLEAR RAM FROM 0X30-0X3F
	BTFSS	STATUS,Z
	GOTO	TEMPXX
; table read pointer
	CLRF	TABLECOUNTER
	BCF		DONE		; CLEAR DONE, START 
;======================================================================================= 
; Context Restore
;======================================================================================= 
C_RESTORE
	CLRF	STATUS		;ENSURE BANK0 RESTORE
	MOVF	FSR_SAVE,W
	MOVWF	FSR
	MOVF	PCLATH_SAVE,W
	MOVWF	PCLATH		; RESTORE PCLATH
	SWAPF	STATUS_TEMP,W
	MOVWF	STATUS
	SWAPF	W_TEMP,F
	SWAPF	W_TEMP,W

	RETFIE

;RESUME                      ; Return to main program
;ENABLE 	
;=======================================================================================
	org 0x0600  ; page 0
    LOWBAND
;=======================================================================================
	ADDWF PCL,F
      RETLW B'11111111'
      RETLW B'11111111'
      RETLW B'11111010'
      RETLW B'10101010'
      RETLW B'10101010'
      RETLW B'10100000'
      RETLW B'10000000'
      RETLW B'00000001'
      RETLW B'00000101'
      RETLW B'00010101'
      RETLW B'01010111'
      RETLW B'01011111'
      RETLW B'01111110'
      RETLW B'01111110'
      RETLW B'11111010'
      RETLW B'11101000'
      RETLW B'11101000'
      RETLW B'10100000'
      RETLW B'10100001'
      RETLW B'10000001'
      RETLW B'10000111'
      RETLW B'00000111'
      RETLW B'00011111'
      RETLW B'00011110'
      RETLW B'01011110'
      RETLW B'01111000'
      RETLW B'01111000'
      RETLW B'01111000'
      RETLW B'11100001'
      RETLW B'11100001'
      RETLW B'11100001'
      RETLW B'10000111'
      RETLW B'10000111'
      RETLW B'10000110'
      RETLW B'10011110'
      RETLW B'00011110'
      RETLW B'00011100'
      RETLW B'00011000'
      RETLW B'01111001'
      RETLW B'01111001'
      RETLW B'01110001'
      RETLW B'01100011'
      RETLW B'11100111'
      RETLW B'11100111'
      RETLW B'11000110'
      RETLW B'10001110'
      RETLW B'10001100'
      RETLW B'10011100'
      RETLW B'10011000'
      RETLW B'00011001'
      RETLW B'00111001'
      RETLW B'00110011'
      RETLW B'01110011'
      RETLW B'01100011'
      RETLW B'01100110'
      RETLW B'01100110'
      RETLW B'11100110'
      RETLW B'11001100'
      RETLW B'11001100'
      RETLW B'10001101'
      RETLW B'10011001'
      RETLW B'10011001'
      RETLW B'10011011'
      RETLW B'00110011'
      RETLW B'00110010'
      RETLW B'00110110'
      RETLW B'01100110'
      RETLW B'01100100'
      RETLW B'01101100'
      RETLW B'01001100'
      RETLW B'11001101'
      RETLW B'11001001'
      RETLW B'11011011'
      RETLW B'10011011'
      RETLW B'10010011'
      RETLW B'10010010'
      RETLW B'10110010'
      RETLW B'00110100'
      RETLW B'00110100'
      RETLW B'00100100'
      RETLW B'01101101'
      RETLW B'01101101'
      RETLW B'01001101'
      RETLW B'01001011'
      RETLW B'11001011'
      RETLW B'11010010'
      RETLW B'11010010'
      RETLW B'10010010'
      RETLW B'10110100'
      RETLW B'10110100'
      RETLW B'10110101'
      RETLW B'00101101'
      RETLW B'00101101'
      RETLW B'00101111'
      RETLW B'01101011'
      RETLW B'01001010'
      RETLW B'01001010'
      RETLW B'01000010'
      RETLW B'11010000'
      RETLW B'11010000'
      RETLW B'11010100'
      RETLW B'10110101'
      RETLW B'10110101'
      RETLW B'10111111'
      RETLW B'10101111'
      RETLW B'00101111'
      RETLW B'00101010'
      RETLW B'00001010'
      RETLW B'01000000'
      RETLW B'01000000'
      RETLW B'01010000'
      RETLW B'01010101'
      RETLW B'11010101'
      RETLW B'11010101'
      RETLW B'11111111'
      RETLW B'10111111'
      RETLW B'10111110'
      RETLW B'10101010'
      RETLW B'10101010'
      RETLW B'00101000'
      RETLW B'00000000'
      RETLW B'00000001'
      RETLW B'01000001'
      RETLW B'01010101'
      RETLW B'01010111'
      RETLW B'01010111'
      RETLW B'11111111'
      RETLW B'11111110'
      RETLW B'11111010'
   RETLW B'10101000'
   RETLW B'10101000'
   RETLW B'10100000'
   RETLW B'10100001'
   RETLW B'00000001'
   RETLW B'00000111'
   RETLW B'00000111'
   RETLW B'01010111'
   RETLW B'01011110'
   RETLW B'01011110'
   RETLW B'01111110'
   RETLW B'11111000'
   RETLW B'11111000'
   RETLW B'11101001'
   RETLW B'10100001'
   RETLW B'10100001'
   RETLW B'10000011'
   RETLW B'10000111'
   RETLW B'00000110'
   RETLW B'00000110'
   RETLW B'00011110'
   RETLW B'01011100'
   RETLW B'01011000'
   RETLW B'01111000'
   RETLW B'01111001'
   RETLW B'11110001'
   RETLW B'11100011'
   RETLW B'11100011'
   RETLW B'10100111'
   RETLW B'10000110'
   RETLW B'10000110'
   RETLW B'10001100'
   RETLW B'00011100'
   RETLW B'00011100'
   RETLW B'00011001'
   RETLW B'01111001'
   RETLW B'01111001'
   RETLW B'01110011'
   RETLW B'01110011'
   RETLW B'11100010'
   RETLW B'11100110'
   RETLW B'11100110'
   RETLW B'10001100'
   RETLW B'10001100'
   RETLW B'10001101'
   RETLW B'10011001'
   RETLW B'00011001'
   RETLW B'00011011'
   RETLW B'00110011'
   RETLW B'01110011'
   RETLW B'01110010'
   RETLW B'01100110'
   RETLW B'01100100'
   RETLW B'11100100'
   RETLW B'11001100'
   RETLW B'11001101'
   RETLW B'10001101'
   RETLW B'10001011'
   RETLW B'10011011'
   RETLW B'10011011'
   RETLW B'00010010'
   RETLW B'00110010'
   RETLW B'00110100'
   RETLW B'01110100'
   RETLW B'01100100'
   RETLW B'01101101'
   RETLW B'01101101'
   RETLW B'11001101'
   RETLW B'11001011'
   RETLW B'11001011'
   RETLW B'10011010'
   RETLW B'10010010'
   RETLW B'10010010'
   RETLW B'10110000'
   RETLW B'00110100'
   RETLW B'00110101'
   RETLW B'00110101'
   RETLW B'01101101'
   RETLW B'01101111'
   RETLW B'01101111'
   RETLW B'01001011'
   RETLW B'11001010'
   RETLW B'11001010'
   RETLW B'11010000'
   RETLW B'10010000'
   RETLW B'10010100'
   RETLW B'10110101'
   RETLW B'10110101'
   RETLW B'00111111'
   RETLW B'00101111'
   RETLW B'00101111'
   RETLW B'01101010'
   RETLW B'01001010'
   RETLW B'01001010'
   RETLW B'01000000'
   RETLW B'11000000'
   RETLW B'11010001'
   RETLW B'11010101'
   RETLW B'10010101'
   RETLW B'10110111'
   RETLW B'10111111'
   RETLW B'10111110'
   RETLW B'00101110'
   RETLW B'00101010'
   RETLW B'00101000'
   RETLW B'01000000'
   RETLW B'01000000'
   RETLW B'01000001'
   RETLW B'01010101'
   RETLW B'11010111'
   RETLW B'11010111'
   RETLW B'11111111'
   RETLW B'10111110'
   RETLW B'10111110'
   RETLW B'10111000'
   RETLW B'10101000'
   RETLW B'00101000'
   RETLW B'00100001'
   RETLW B'00000001'
   RETLW B'01000001'
   RETLW B'01000111'
   RETLW B'01010111'
   RETLW B'01010110'
   RETLW B'11011110'
   RETLW B'11111110'

   RETLW B'11111100'
;=======================================================================================
	org 0x0700	; page 0 , avoid 256 boundary problem
HIGHBAND
;=======================================================================================
	ADDWF PCL,F     
      RETLW B'11111111'
      RETLW B'11101010'
      RETLW B'10101000'
      RETLW B'10000000'
      RETLW B'00000101'
      RETLW B'00010111'
      RETLW B'01011111'
      RETLW B'01111110'
      RETLW B'11111000'
      RETLW B'11100000'
      RETLW B'10000001'
      RETLW B'10000111'
      RETLW B'00010111'
      RETLW B'00011110'
      RETLW B'01111000'
      RETLW B'01111000'
      RETLW B'11100001'
      RETLW B'11100011'
      RETLW B'10000111'
      RETLW B'10001110'
      RETLW B'00011100'
      RETLW B'00111000'
      RETLW B'01111001'
      RETLW B'01100011'
      RETLW B'11100111'
      RETLW B'11000110'
      RETLW B'10001100'
      RETLW B'10011100'
      RETLW B'00011001'
      RETLW B'00110011'
      RETLW B'01110011'
      RETLW B'01100110'
      RETLW B'11000100'
      RETLW B'11001100'
      RETLW B'10011001'
      RETLW B'10011011'
      RETLW B'00110011'
      RETLW B'00110010'
      RETLW B'01100100'
      RETLW B'01101100'
      RETLW B'11001101'
      RETLW B'11001011'
      RETLW B'10010011'
      RETLW B'10110010'
      RETLW B'00110100'
      RETLW B'00100100'
      RETLW B'01101101'
      RETLW B'01001011'
      RETLW B'11001011'
      RETLW B'11010010'
      RETLW B'10010000'
      RETLW B'10110100'
      RETLW B'00101101'
      RETLW B'00101111'
      RETLW B'01001011'
      RETLW B'01001010'
      RETLW B'11010000'
      RETLW B'11010100'
      RETLW B'10110101'
      RETLW B'10111111'
      RETLW B'00101111'
      RETLW B'00101010'
      RETLW B'01000000'
      RETLW B'01010000'
      RETLW B'11010101'
      RETLW B'11110111'
      RETLW B'10111111'
      RETLW B'10101010'
      RETLW B'00101000'
      RETLW B'00000000'
      RETLW B'01000001'
      RETLW B'01010111'
      RETLW B'11011111'
      RETLW B'11111110'
      RETLW B'10101000'
      RETLW B'10101000'
      RETLW B'00000001'
      RETLW B'00000111'
      RETLW B'01010111'
      RETLW B'01011110'
      RETLW B'11111000'
      RETLW B'11111000'
      RETLW B'10100001'
      RETLW B'10100011'
      RETLW B'00000111'
      RETLW B'00011110'
      RETLW B'01011100'
      RETLW B'01111000'
      RETLW B'11111001'
      RETLW B'11100011'
      RETLW B'10100111'
      RETLW B'10000110'
      RETLW B'00001100'
      RETLW B'00011100'
      RETLW B'01011001'
      RETLW B'01110011'
      RETLW B'11100011'
      RETLW B'11100110'
      RETLW B'10000100'
      RETLW B'10001100'
      RETLW B'00011001'
      RETLW B'00011011'
      RETLW B'01110011'
      RETLW B'01110010'
      RETLW B'01100100'
      RETLW B'11001100'
      RETLW B'11001101'
      RETLW B'10011011'
      RETLW B'10011011'
      RETLW B'00110010'
      RETLW B'00110100'
      RETLW B'01100100'
      RETLW B'01101101'
      RETLW B'11001111'
      RETLW B'11001011'
      RETLW B'10010010'
      RETLW B'10110000'
      RETLW B'00110100'
      RETLW B'00100101'
      RETLW B'01101111'
      RETLW B'01001011'
      RETLW B'11001010'
      RETLW B'11010000'
      RETLW B'10010100'
      RETLW B'10110101'
      RETLW B'00111111'
   RETLW B'00101111'
   RETLW B'01001010'
   RETLW B'01000000'
   RETLW B'11010000'
   RETLW B'11010101'
   RETLW B'10110111'
   RETLW B'10111111'
   RETLW B'00101010'
   RETLW B'00101000'
   RETLW B'01000000'
   RETLW B'01000001'
   RETLW B'11010111'
   RETLW B'11111111'
   RETLW B'10111110'
   RETLW B'10101000'
   RETLW B'00101000'
   RETLW B'00000001'
   RETLW B'01000111'
   RETLW B'01010111'
   RETLW B'11011110'
   RETLW B'11111100'
   RETLW B'10111000'
   RETLW B'10100001'
   RETLW B'00000011'
   RETLW B'00000110'
   RETLW B'01010110'
   RETLW B'01011100'
   RETLW B'11111001'
   RETLW B'11111001'
   RETLW B'10100011'
   RETLW B'10100010'
   RETLW B'00000110'
   RETLW B'00011100'
   RETLW B'01011101'
   RETLW B'01111001'
   RETLW B'11110011'
   RETLW B'11100010'
   RETLW B'10100110'
   RETLW B'10000100'
   RETLW B'00001101'
   RETLW B'00011001'
   RETLW B'01011011'
   RETLW B'01110010'
   RETLW B'11100010'
   RETLW B'11100100'
   RETLW B'10001101'
   RETLW B'10001101'
   RETLW B'00011011'
   RETLW B'00011010'
   RETLW B'01110010'
   RETLW B'01110100'
   RETLW B'11100101'
   RETLW B'11101101'
   RETLW B'10001111'
   RETLW B'10011010'
   RETLW B'00010010'
   RETLW B'00110000'
   RETLW B'01110101'
   RETLW B'01100101'
   RETLW B'11101111'
   RETLW B'11001010'
   RETLW B'10001010'
   RETLW B'10010000'
   RETLW B'00010001'
   RETLW B'00110101'
   RETLW B'01101111'
   RETLW B'01101110'
   RETLW B'11001010'
   RETLW B'11001000'
   RETLW B'10010001'
   RETLW B'10010101'
   RETLW B'00110111'
   RETLW B'00111110'
   RETLW B'01101110'
   RETLW B'01101000'
   RETLW B'11000001'
   RETLW B'11010001'
   RETLW B'10010111'
   RETLW B'10111110'
   RETLW B'00111110'
   RETLW B'00101000'
   RETLW B'01101001'
   RETLW B'01000001'
   RETLW B'01000111'
   RETLW B'11010110'
   RETLW B'11111110'
   RETLW B'10111100'
   RETLW B'10101001'
   RETLW B'00100001'
   RETLW B'00000011'
   RETLW B'01000110'
   RETLW B'01010110'
   RETLW B'11011100'
   RETLW B'11111001'
   RETLW B'10111001'
   RETLW B'10100011'
   RETLW B'00000010'
   RETLW B'00000110'
   RETLW B'01011100'
   RETLW B'01011101'
   RETLW B'11111001'
   RETLW B'11111011'
   RETLW B'10100010'
   RETLW B'10100110'
   RETLW B'00000100'
   RETLW B'00001101'
   RETLW B'01011101'
   RETLW B'01111011'
   RETLW B'11110010'
   RETLW B'11100010'
   RETLW B'10100100'
   RETLW B'10000101'
   RETLW B'00001101'
   RETLW B'00011011'
   RETLW B'01011010'
   RETLW B'01110010'
   RETLW B'11110100'
   RETLW B'11100101'
   RETLW B'10001101'
   RETLW B'10001111'
   RETLW B'00011010'
   RETLW B'00010010'
   RETLW B'01110000'
   RETLW B'01110101'
   RETLW B'11100101'
   RETLW B'11101111'
   RETLW B'10001010'
   RETLW B'10001010'
   RETLW B'00010000'
;=======================================================================================
  ENDASM 		
;RESUME                      ; Return to main program
;ENABLE 
;=======================================================================================	

;======================================================================================= 
ASM 
 Asm_Macros 
;======================================================================================= 
;User Variables
;======================================================================================= 
	CBLOCK 0x50
	scrA:	1	; scratch pad	0X50
	scrB:	1
	scrC:	1	
	scrD:	1
	count_1:1	; counter lsb
	count_2:1
	count_3:1
	count_4:1	; counter msb

	PSS0:		1	;PASSWORD 
    ENDC

	CBLOCK 0x72	; variables for all the RAM pages
	comA:	1
	comB:	1
	comC:	1
	comD:	1
	ENDC
return	
;=======================================================================================	
ENDASM 
;=======================================================================================

;=======================================================================================	
;************** Main Program ***********************************************************
;=======================================================================================	
START:
            
	TRISB = 0		; PORT B 0-3 OUTPUTS
	TRISa = 0
	TIMEOUT = 0		; KEEP THE TIMEOUT STOPPED
	BEEP = 0		; SILENCE...
	TIME0 = 0		; INIT TIMEOUT COUNTER
	TIME1 = 0
	TIME2 = 0
	DONE = 0		; DO NOT START DTMF DETECTOR....

; INIT ROUTINE	
	PORTC = 0		; CLEAR PORTC
	TRISC =	%00000011	;port C0=Input for now/out, C1=INPUT, C2,3 OUT
	
	T2CON =	%00001100	; X,1/2 postscale, timer 2 ON ~9.6khz sample rate	
	
	PR2 = 0XFF		; TIMER 2 PERIOD REGISTER
	
    PIR1.1 = 0     ;TMR2IF	; CLEAR TIMER 2 INT FLAG
	PIE1.1 = 1   ;TMR2IE	; START INT FOR TIMER 2
	iNTCON.6 = 1   ;PEIE 	; START PERIPHERAL INT
	INTCON.7 = 1    ;GIE	; START GLOBAL INT

	cCP1CON	= %00001100	;PWM 1 ON
	TRISC.2 = 0		; RC2 = PWM 1 OUT
	CCPR1L= 128		; 50 DUTY CYCLE ~18KHZ

	TEMP_VAL = 0
	TEMP_TIMES = 0
	COUNT_= 0		; NR CHAR FOR DISPLAY

    high     porta.0
return	       
;=======================================================================================

;=======================================================================================	
ASM 
 Asm_TomaDato	
;=======================================================================================	
;***************** MAIN LOOP ***********************************************************
;=======================================================================================	
	CALL 	BEEPOK
	CALL	BEEPERR
    ; FIRSRT READ #PASS#, WHERE PASS HAS 10 DIGITS
MAINDTMF:
	CALL 	START_DTMF 
	CALL	CLRTIMEOUT
MAIN0:

ciclo
	CALL	START_DTMF	; GET A NEW DIGIT
	CALL	CLRTIMEOUT	; START TIMEUOT 
	MOVLW	LOW PSS0	; POINTER RAM
	MOVWF	FSR
	MOVLW	.10		; 10 DIGIT PASS
	MOVWF	EE_Byte		; COUNTER
MAIN1:
            
	BTFSC	TIMEOUT
	GOTO	TIMEO		; TIMEOUT ERROR, RESTART
				 
	; WAIT A DIGIT
	
    BTFSS	DONE
	GOTO	MAIN1
	
    bsf     porta,3 
	MOVF	RESULT1,W
	MOVWF	INDF		; PUT DIGIT IN PSS0-9, RAM
	;debug
	movwf	PORTB
	goto ciclo
	
    ;return
	
;=======================================================================================	
TIMEO:
	; TIMEOUT + TIMEOUT BEEP
	
	BSF	   DONE	;STOP DTMF DECODER
	CALL   BEEPERR	; TIMEOUT BEEP, TWO LOW BEEPS
	CALL   BEEPPAUSE
	CALL   BEEPERR
TIMEO1:	
	BSF	   DONE	;STOP DTMF DECODER
	BCF	   PORTC,3		; BEEP OFF
	GOTO   MAINDTMF	;RESTART
; ****** END MAIN LOOP
;START DTMF DECODER
START_DTMF
	BSF	    DONE		; STOP DTMF INT ROUTINE
	MOVF	FSR,W
	MOVWF	FSR_SAVE_DTMF	; SAVE FSR
	MOVLW	0X2F		; start -1
	MOVWF	FSR
TEMPXX1
	INCF	FSR,F
	CLRF	INDF
	MOVF	FSR,W
	XORLW	0X3F		; CLEAR RAM FROM 0X30-0X3F
	BTFSS	STATUS,Z
	GOTO	TEMPXX1
; table read pointer
	CLRF	TABLECOUNTER
	CLRF	RESULT1		; CLEAR RESULT DIGIT
	MOVF	FSR_SAVE_DTMF, W
	MOVWF	FSR		; RESTORE FSR
	BCF    	DONE		; CLEAR DONE, START DTMD INT ROUTINE
	RETURN
;=======================================================================================
; BEEP ON ERROR, DESTROY scrA!
BEEPERR:
	MOVLW	.16
	GOTO  	BEEP1

; BEEP WHEN OK, DESTROY scrA!
BEEPOK:
	MOVLW	.4

BEEP1:	
	MOVWF	TIME2		; BEEP PITCH
	MOVWF	scrA	
	BANKSEL TRISC
	BCF		TRISC,0		; PORTC 0 = OUT
	BANKSEL	PORTC		; BACK TO BANK 0
	BSF		BEEP		; START INT BEEP ROUTINE
	BSF		TIMEOUT		; STOP TIMEOUT ROUTINE
	CLRF	TIME0		; INIT TIMEOUT COUNTER
	MOVLW	.25
	MOVWF	TIME1
	BCF		TIMEOUT		; START TIMEOUT	
BEEPWAIT:
	BTFSS	TIMEOUT
;	GOTO BEEPWAIT
	BCF 	BEEP		; STOP INT BEEP ROUTINE
	BCF 	PORTC,0		; SET OUTPUT TO 0 VOLTS
	BANKSEL TRISC
	BSF		TRISC,0		; PORTC 0 = INPUT / HIGH z
	BANKSEL	PORTC		; BACK TO BANK 0	
	RETURN
; BEEPPAUSE WAIT A LITTLE BIT....
BEEPPAUSE:
	BSF		TIMEOUT		; STOP TIMEOUT ROUTINE
	CLRF	TIME0		; INIT TIMEOUT COUNTER
	MOVLW	.10
	MOVWF	TIME1
	BCF		TIMEOUT		; START TIMEOUT	
BEEPWAIT1:
	BTFSS	TIMEOUT
	GOTO 	BEEPWAIT1
	RETURN
 ;=======================================================================================
; CLEAR TIMEOUT TIMER
CLRTIMEOUT:	; CLEAR TIMEOUT TIMER ( ~6.7 SECONDS)

	BCF	   TIMEOUT		; STOP INT TIMEOUT ROUTINE
	CLRF   TIME0		; INIT TIMEOUT COUNTER
	CLRF   TIME1
	BCF	   TIMEOUT		; START INT TIMEOUT ROUTINE	
	RETURN

; PRINT PASSWORD IN EEPROM
TESTPASS:
	MOVLW	.8
	MOVWF	EE_Byte
TESTPASS1:	
	MOVF	EE_Byte,W
	CALL 	EE_READ_BYTE
	;CALL send_c	; PRINT DIGIT
	INCF	EE_Byte,F
	MOVLW	0X12	; END OF PASS+1
	XORWF	EE_Byte, W
	BTFSS	STATUS, Z
	GOTO	TESTPASS1
	;CALL 	cur_h1
	RETURN
;=======================================================================================
; EE_READ_BYTE - Routine to read a byte from ee ram 
; Adress in W, byte will be delivered in W
;=======================================================================================
EE_READ_BYTE
	bcf STATUS, RP0
	bsf STATUS, RP1    ;bank 2
	MOVWF	EEADR		; put in adress reg.
	BSF	STATUS,RP0	; bank3 !
	BCF	EECON1,EEPGD	; set to read data memory
	BSF	EECON1,RD	; set bit to read
	BCF	STATUS,RP0	; bank2 !
	MOVF	EEDATA,W	; move data to W
	clrf   status ;Bank0			; Reset to BANK0 !
	RETURN			; and return
;=======================================================================================

return	
   ENDASM
```


----------



## Gudino Roberto duberlin (Jun 16, 2011)

francote dijo:


> Cordial saludo para todas y todos. Esta es mi primera participación.
> 
> Como lo digo en el anunciado: Necesito “código detector (Decodificar) de tonos DTMF para 16F87X”, que sea sencillo de inserta como parte del compilador Basic de Proton+ de Crownhill, para ser llamado con Call (Por ejemplo).
> 
> ...



Hola!  
        Hay una forma sencilla de detectar el par de tonos DTMF.
Lo 1ro. q debe hacerse es:
                                    Acondicionar la señal, que consiste en separar la misma para recuperar los tonos por separado,( puede hacerse con un simple operacional) y luego teniendo el tono puro, puede ingresarse al PIC. 
       El circuito es bastante simple, lo he armado hace un tiempo y me dio excelentes resultados. Con respecto al PIC no necesariamente debe ser rapido, con que trabaje a 4Mhz a cristal, sobra velocidad!!!.


----------



## wilfretronic (Oct 12, 2013)

Gudino Roberto duberlin dijo:


> Hola!
> Hay una forma sencilla de detectar el par de tonos DTMF.
> Lo 1ro. q debe hacerse es:
> Acondicionar la señal, que consiste en separar la misma para recuperar los tonos por separado,( puede hacerse con un simple operacional) y luego teniendo el tono puro, puede ingresarse al PIC.
> El circuito es bastante simple, lo he armado hace un tiempo y me dio excelentes resultados. Con respecto al PIC no necesariamente debe ser rapido, con que trabaje a 4Mhz a cristal, sobra velocidad!!!.



Amigo... buena pero podrías aclarar mas sobre como usar un opamp si fuera posible una imagen... gracias


----------

