Ответ: +++++
(«Телесистемы»: Конференция «Микроконтроллеры и их применение»)

миниатюрный аудио-видеорекордер mAVR

Отправлено ten 24 ноября 2003 г. 17:03
В ответ на: Может кто ткнет примерчик DTMF декодера на AVR или PIC? отправлено ИГОРЬ! 24 ноября 2003 г. 16:18

This is DTMF decoding program, provided by:
Stephen James Hardy (T/A SW Tekno) Canberra, Australia
hardy@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< 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


Составить ответ  |||  Конференция  |||  Архив

Ответы



Перейти к списку ответов  |||  Конференция  |||  Архив  |||  Главная страница  |||  Содержание  |||  Без кадра

E-mail: info@telesys.ru