Newsgroup: it.hobby.elettronica.digitale
Titolo: decoder dtmf con pic

Ho trovato questo file in rete.
E' il sorgente per un decoder dtmf per PIC.
Dice che "Written for the 16C84, but should run on most any 16Cxx"
po più avanti parla di ADC.
Io lo volevo usare con un PIC 16F84A....
ma ne il 16C84 nel il il 16f84A hanno un adc integrato: come può
funzionare il programma ?
Ciao,
grazie
This is DTMF decoding program, provided by:
Stephen James Hardy (T/A SW Tekno) Canberra, Australia
ha...@sweng.stortek.com
======== Source code ========
; Caveat: Requires tone duration of 160ms.  DTMF standard only
; requires 50ms tone.
; This source code is copyright (C) 1996 to Stephen James Hardy.
; Permission is hereby granted to reproduce, assemble and run this
code
; for non-commercial purposes providing this notice is not removed
; from source code copies.
;
; This source code is provided as-is with no warranty expressed or
; implied.  Do not use where damage to persons or property may result
; from source code failure.
;
; Written for the 16C84, but should run on most any 16Cxx...
;
; Target configuration:
;   PORTB: Sample input as unsigned binary.  With a 16C7x, change the
;          code to read the ADC instead.
;   PORTA: Connnected to 5 LEDs:
;          RA0-3 : indicate decoded tone (0-F)
;          RA4   : 0 if tone OK, 1 if tone not recognised.
;   Osc: 10MHz xtal.
;
; Assemble using MPASM /C- flag.
;
;
        list    p=pic16c84
        include "p16c84.inc"    ; Mchip standard include
        radix   dec
; NB: If the following is changed, check assembly to ensure timer
; constants (TONEL0 etc) fit in 1 byte.
CLKSPD  equ     10              ; Target clock speed (MHz)
; Register mapping:
RBASE   equ     0Ch             ; First general register.
;------------------
; Bank 0 registers.  Rather profligate use made thereof.  Could be
; reduced with a bit of twiddling.
;------------------
        cblock  RBASE
        dtmf_code1              ; Result of first trial
        dtmf_code2              ; Result of 2nd trial
        dtmf_r                  ; Result of high- or low-group trial
        dtmf_rr                 ; Temp result
        dtmf_t1l                ; Regs for correlation accumulators.
        dtmf_t1h
        dtmf_t2l
        dtmf_t2h
        dtmf_tc                 ; Tick counter for timing
        dtmf_tcc                ; Tick counter reload constant
        dtmf_sc                 ; Sample counter for 1 tone
        dtmf_st                 ; Sample state (0-3)
        dtmf_cs                 ; Latest sample
        dtmf_sl                 ; sum/avg low
        dtmf_sh                 ; sum/avg high
        dtmf_ml                 ; max low
        dtmf_mh                 ; max high
        endc
        org     0
;------------------------
; Power-up initialisation
;------------------------
pwrup   bsf     status,rp0      ; Select bank 2
; Set RB pullups, falling edge interrupt, increment t0 on instruction
cycle,
; assign prescaler to WDT (not used), prescale 1:1.
        movlw   (1<<psa)
        movwf   option_reg
        clrf    trisa           ; Set port A to outputs
        movlw   0FFh
        movwf   trisb           ; Set port B to inputs
        clrf    status          ; Back to bank 0.
demo_dtmf_listen
        bcf     intcon,GIE      ; Disable interrupts
        call    dtmf_listen     ; Do it...
; W contains code
        movwf   porta           ; Show on LEDs attached to port A.
        goto    demo_dtmf_listen        ; ...forever
;--------------------------------------------------------------
; dtmf_listen:  Detects and decodes DTMF tones applied to the ADC.
;
; Interrupts must be disabled (as written) since instruction cycle
; counting is used to perform timing.  This restriction may be removed
; if rewritten to use interrupts to perform controlled timebase
sampling.
;
; On return W contains the DTMF signal (0-15) with following
correspondence
; to standard telephone keypad:
; W     Key
; -     ---
; 0     1
; 1     4
; 2     7
; 3     *
; 4     2
; 5     5
; 6     8
; 7     0
; 8     3
; 9     6
; A     9
; B     #
; C     A
; D     B
; E     C
; F     D
; i.e the 2 LSBs of W index the low tone group, and the other 2 bits
; index the high tone group.
; In the case that no tone was reliably detected, W contains FF.
;
; Note:  8-bit ADC is used.  For maximum reliability, the DTMF tone
; should use the full range of the ADC.  However, if the low- and
; high-group tones are within 1dB of each other, it is possible to
; use a 1-bit ADC (i.e. comparator)
;
; Algorithm:
; The eight possible tones used in DTMF are searched for one-by-one.
; This approach is allowable because of the 200ms required for each
; signal.  78.2us are allocated for sampling (a total of 4*10*8
; samples; this is repeated for reliability hence sampling takes
; 156.4ms which allows the rest of the application a few ms to
determine
; whether a tone is present.
;
; Since one tone is being searched for at a time, the following method
; is appropriate:  Sample at 4 times the frequency of the search tone,
; for a total of 10 waves.  This allows correlation of the signal with
; the search tone; a high correlation indicating the tone is present.
; 10 waves are selected since the DTMF tones differ by 10% steps.  The
; other tones will thus cancel out when correlated with the search
tone
; (as a consequence of the orthogonality of the sine function basis).
;
; The 8 tones are tried in sequence.  The largest correlation from
each
; of the high and low tone groups is selected.  If the highest correl
in
; each group is greater than or equal 1.5 times the average, then
; that tone is adjudged present.  If both the high and low tone group
; is present, an initial DTMF code is decided.  The process is
repeated
; and, if the same code is present the next time, that code is
returned.
; Otherwise, the 'uncertain' code (FF) is returned.
;
;--------------------------------------------------------------
SAMPSPC equ     4               ; Sample points per tone cycle.  Don't
change!
WAVES   equ     10              ; Number of tone cycles to sample
SINTVL  equ     250000*CLKSPD/SAMPSPC ; PIC cycles between samples at
f=1Hz
                                ; - divide by tone (Hz) to get cycles.
                                ; For DTMF, will range from 897
(697Hz)
                                ; to 382 (1633Hz) at 10MHz xtal.
FIXDLAY equ     36              ; Fixed delay to make following <=
256.
       ; Select according to the formula:
       ; FIXDLAY = 29.89*CLKSPD - 263.7
       ; (round up).
SLCYCLES equ    (FIXDLAY-1)*3+29  ; PIC cycles taken in the dtmf_lp
loop
                                ; not counting the wait loop at
dtmf_wtim
                                ; Code is designed so this is
constant!
TLCYCLES equ    3               ; Number of PIC cycles per wait loop,
                                ; 1 less than this on last execution.
; Loop constants for each DTMF tone. Must be 1..256 inclusive.  TONEL0
; is the largest and should be made as close as possible to 256 by
adjusting
; the constant FIXDLAY (and hence SLCYCLES).  The smallest constant
; (TONEH3) should also be as large as possible for accuracy - this
places
; limits on the lowest clock speed that will work.  Min clock speed
should
; be around 3.7MHz.  If clock is faster than 17.3MHz, then the code
will
; need to be modified to add yet more delay since FIXDLAY will be over
256.
TONEL0  equ     (SINTVL/697-SLCYCLES)/TLCYCLES
TONEL1  equ     (SINTVL/770-SLCYCLES)/TLCYCLES
TONEL2  equ     (SINTVL/852-SLCYCLES)/TLCYCLES
TONEL3  equ     (SINTVL/941-SLCYCLES)/TLCYCLES
TONEH0  equ     (SINTVL/1209-SLCYCLES)/TLCYCLES
TONEH1  equ     (SINTVL/1336-SLCYCLES)/TLCYCLES
TONEH2  equ     (SINTVL/1477-SLCYCLES)/TLCYCLES
TONEH3  equ     (SINTVL/1633-SLCYCLES)/TLCYCLES
dtmf_listen
        call    dtmf_lg         ; Sample for low group => dtmf_r
done_lg btfsc   dtmf_r,7        ; Done lg: check result reg (0-3 or
FF)
        retlw   0FFh            ; Return if uncertain
        movf    dtmf_r,w
        movwf   dtmf_code1      ; Move to code result 1
        call    dtmf_hg         ; Sample for high group => dtmf_r
done_hg btfsc   dtmf_r,7        ; Done hg: check result
        retlw   0FFh            ; return if uncertain
        bcf     status,C
        rlf     dtmf_r
        rlf     dtmf_r,w        ; *4, into W
        iorwf   dtmf_code1,f    ; Or in low group
; Now repeat to make sure...
        call    dtmf_lg         ; Sample for low group => dtmf_r
        btfsc   dtmf_r,7        ; check result reg (0-3 or FF)
        retlw   0FFh            ; Return if uncertain
        movf    dtmf_r,w
        movwf   dtmf_code2      ; Move to code result 2
        call    dtmf_hg         ; Sample for high group => dtmf_r
        btfsc   dtmf_r,7
        retlw   0FFh            ; return if uncertain
        bcf     status,C
        rlf     dtmf_r
        rlf     dtmf_r,w        ; *4, into W
        iorwf   dtmf_code2      ; Or in low group (result in W)
; Check if both agree
        subwf   dtmf_code1,f    ; code1 = code1 - code2
        btfss   status,Z        ; equal?
        retlw   0FFh            ; no, return uncertain.
        return                  ; else return w = DTMF code.
; Sample for all low group tones, select the largest.
dtmf_lg clrf    dtmf_sl         ; Clear sum
        clrf    dtmf_sh
        clrf    dtmf_ml         ; Clear max
        clrf    dtmf_mh
        clrf    dtmf_rr         ; Tone 0
        movlw   TONEL0
        movwf   dtmf_tcc        ; Set timer constant for low tone 0.
        call    dtmf_samp       ; Sample etc.
        incf    dtmf_rr
        movlw   TONEL1
        movwf   dtmf_tcc        ; Set timer constant for low tone 1.
        call    dtmf_samp       ; Sample etc.
        incf    dtmf_rr
        movlw   TONEL2
        movwf   dtmf_tcc        ; Set timer constant for low tone 2.
        call    dtmf_samp       ; Sample etc.
        incf    dtmf_rr
        movlw   TONEL3
        movwf   dtmf_tcc        ; Set timer constant for low tone 3.
        call    dtmf_samp       ; Sample etc.
dtmf_g  bcf     status,C
        rrf     dtmf_sh         ; Div sum by 4 to get average
        rrf     dtmf_sl
dtmf_01 bcf     status,C
        rrf     dtmf_sh
        rrf     dtmf_sl
; while dtmf_mh non zero, div m and s by 2.
        movf    dtmf_mh,w
        btfsc   status,Z
        goto    dtmf_02
        bcf     status,C
        rrf     dtmf_mh
        rrf     dtmf_ml
        goto    dtmf_01
; Now results in LSB.  Mult s (avg) by 1.5
dtmf_02 bcf     status,C
        rrf     dtmf_sl,w
        addwf   dtmf_sl,w
        btfsc   status,C
        goto    dtmf_03         ; Return uncertain if carry.
; Compare with m (max).  If max is not >= 1.5*avg, then uncertain.
        subwf   dtmf_ml,w       ; w = max - 1.5*avg.  C set if >= 0
(OK)
        btfsc   status,C
        return                  ; return OK (result in dtmf_r)
dtmf_03 movlw   0FFh
        movwf   dtmf_r          ; set uncertain result
        return
; Sample for all high group tones, select the largest.
dtmf_hg clrf    dtmf_sl         ; Clear sum
        clrf    dtmf_sh
        clrf    dtmf_ml         ; Clear max
        clrf    dtmf_mh
        clrf    dtmf_rr         ; Tone 0
        movlw   TONEH0
        movwf   dtmf_tcc        ; Set timer constant for high tone 0.
        call    dtmf_samp       ; Sample etc.
        incf    dtmf_rr
        movlw   TONEH1
        movwf   dtmf_tcc        ; Set timer constant for high tone 1.
        call    dtmf_samp       ; Sample etc.
        incf    dtmf_rr
        movlw   TONEH2
        movwf   dtmf_tcc        ; Set timer constant for high tone 2.
        call    dtmf_samp       ; Sample etc.
        incf    dtmf_rr
        movlw   TONEH3
        movwf   dtmf_tcc        ; Set timer constant for high tone 3.
        call    dtmf_samp       ; Sample etc.
        goto    dtmf_g          ; Go to common processing for lo, hi
groups
;
; This routine performs all samples for a particular tone.  It selects
; the largest correlation into dtmf_t1l/h (which is the return value).
;
dtmf_samp movlw SAMPSPC*WAVES   ; Total samples
        movwf   dtmf_sc         ; move to sample counter
        clrf    dtmf_st         ; Initial state
        clrf    dtmf_t1l        ; Clear correlation accumulators
        clrf    dtmf_t1h
        clrf    dtmf_t2l
        clrf    dtmf_t2h
;
; Main sample loop.  The code is written to take a constant number of
; cycles no matter what.  This explains some of the odd things like
; seemingly unnecessary goto's.
;
dtmf_lp movf    portb,w         ; 1 - Get sample (e.g. from port B)
        movwf   dtmf_cs         ; 2 -Save it
        movlw   high dtmf_bstate ; 3
        movwf   pclath          ; 4
        movf    dtmf_st,w       ; 5 - Get current state
        addwf   pcl,f           ; 6,7 - Branch on state (0-3)
dtmf_bstate
        goto    dtmf_st0        ; 8,9 - Check asm list to make sure
all
        goto    dtmf_st1        ; of these 4 instr's on same 256-byte
page
        goto    dtmf_st2        ;
        goto    dtmf_st3        ;
dtmf_st0 movf   dtmf_cs,w       ; 10 - Get sample
        addwf   dtmf_t1l,f      ; 11 - Add to accumulator
        btfsc   status,C        ; 12,13 - Test carry out
        incf    dtmf_t1h        ; 13 - Increment high byte if carry
out
        goto    dtmf_join       ; 14,15 - continue common
dtmf_st1 movf   dtmf_cs,w       ; Get sample
        addwf   dtmf_t2l,f      ; Add to accumulator
        btfsc   status,C        ; Test carry out
        incf    dtmf_t2h        ; Increment high byte if carry out
        goto    dtmf_join       ; continue common
dtmf_st2 comf   dtmf_cs,w       ; Get 'negative' sample
        addwf   dtmf_t1l,f      ; Add to accumulator
        btfsc   status,C        ; Test carry out
        incf    dtmf_t1h        ; Increment high byte if carry out
        goto    dtmf_join       ; continue common
dtmf_st3 comf   dtmf_cs,w       ; Get 'negative' sample
        addwf   dtmf_t2l,f      ; Add to accumulator
        btfsc   status,C        ; Test carry out
        incf    dtmf_t2h        ; Increment high byte if carry out
        goto    dtmf_join       ; continue common
dtmf_join incf  dtmf_st,w       ; 16
        andlw   3               ; 17
        movwf   dtmf_st         ; 18 - Update state
        decfsz  dtmf_sc         ; 19,20 - Decrement sample count
        goto    dtmf_tmr        ; 20,21 - If not finished, sample
again
; Finished samples, select largest from dtmf_t1 and dtmf_t2 into
dtmf_t1.
; Average expected value is subtracted, abs value taken.  Avg expected
; value is WAVES in high byte, zero in low byte.
dtmf_lx movlw   WAVES
        subwf   dtmf_t1h,f      ; t1 -= expavg
        btfss   dtmf_t1h,7      ; t1 -ve?
        goto    $+3             ; no, skip next
        comf    dtmf_t1h        ; Negate (don't worry about the 1
diff!)
        comf    dtmf_t1l
        movlw   WAVES
        subwf   dtmf_t2h,f      ; t2 -= expavg
        btfss   dtmf_t2h,7      ; t2 -ve?
        goto    $+3             ; no, skip next
        comf    dtmf_t2h
        comf    dtmf_t2l
        movf    dtmf_t1h,w
        subwf   dtmf_t2h,w      ; w = t2h-t1h (C set if t1h<=t2h)
        btfss   status,C
        goto    dtmf_04         ; cont if t1 > t2
        btfss   status,Z
        goto    dtmf_swap       ; move t2->t1 if t2>t1
        movf    dtmf_t1l,w      ; high equal, test low
        subwf   dtmf_t2l,w      ; w = t2l-t1l
        btfss   status,C
        goto    dtmf_04         ; cont if t1 > t2
dtmf_swap movf  dtmf_t2h,w      ; Set t1 = t2 (return value)
        movwf   dtmf_t1h
        movf    dtmf_t2l,w
        movwf   dtmf_t1l
;
; Sum.
dtmf_04 movf    dtmf_t1l,w
        addwf   dtmf_sl,f
        movf    dtmf_t1h,w
        btfsc   status,C
        addlw   1
        addwf   dtmf_sh,f
;
; Compare with current maximum.  If greater, set new max.
dtmf_05 movf    dtmf_mh,w
        subwf   dtmf_t1h,w      ; w = t1h-mh (C set if mh<=t1h)
        btfss   status,C
        return                  ; ret if m > t1
        btfss   status,Z
        goto    dtmf_sw2        ; move t1->m if t1>m
        movf    dtmf_ml,w       ; high equal, test low
        subwf   dtmf_t1l,w      ; w = t1l-ml
        btfss   status,C
        return                  ; ret if m > t1
dtmf_sw2 movf   dtmf_t1h,w      ; Set m = t1
        movwf   dtmf_mh
        movf    dtmf_t1l,w
        movwf   dtmf_ml
        movf    dtmf_rr,w       ; Tone number
        movwf   dtmf_r          ; Set new tone number
        return
; Waste time until ready for next sample
dtmf_tmr movlw  FIXDLAY         ; 22 - Constant delay
        movwf   dtmf_tc         ; 23
        decfsz  dtmf_tc         ; 24,25
        goto    $-1             ;
        movf    dtmf_tcc,w      ; 26+3(n-1)
        movwf   dtmf_tc         ; 27 - Load tick counter constant
dtmf_wtim decfsz dtmf_tc        ; Decrement tick counter
        goto    dtmf_wtim       ; Tight loop until zero
        goto    dtmf_lp         ; 28,29 - Get next sample
        end

 
Probabilmente usa un adc esterno.
oppure altre soluzioni, bisogna vedere lo schema
 >Note:  8-bit ADC is used.  For maximum reliability, the DTMF tone
 >; should use the full range of the ADC.  However, if the low- and
 >; high-group tones are within 1dB of each other, it is possible to
 >; use a 1-bit ADC (i.e. comparator)
Ma la domanda è:
perche devi usare il pic che fa da decoder dtmf?
MEtti l'integrato apposito e risolvi il problema....
il pic16xxx è molto limitato, considera che anche avendo
a disposizione l'adc non ottieni un ottimo risultato
e poi occupi parecchie risorse del micro....
Emanuele
-- 
*** YOUR ELECTRONICS OPEN SOURCE ***
http://dev.emcelettronica.com
;---------------------------------------------------------
Progetti Completi e Risorse (Full Projects and resources)

così, per provare...
trovando quel documento pensavo di poter facilmente recuperare dei pic
per fargli fare quella funzione dato che di mt8870 ne ho solo 1 .
Emanuele ha scritto:


 funzionare il programma ?
Come ha detto Emanuele, il programma richiede un convertitore esterno
(immagino da 8 bit), collegato alla porta B.
Il sorgente suggerisce di modificare il software nel caso un
convertitore analogico/digitale sia disponibile (per esempio, nei
PIC16C7x).

grazie