DTMF декодер

Nov 26, 2003 1 Replies

Hi, All!



Кто там просил исходники на С для двухчастнотного анализа? Получите :) Железяка даже работала когда-то. Комментарии и замечания приветствуются.



=== main.c === /* * Title : Multi Frequency Tranceiver (1-bit verison) * Version : 0.43 * Last Update : 7 March 2003 * Target MCU : Atmel AVR AT90s2313 * XTAL : 8 MHz * Compiler : IAR Atmel AVR C/EC++ Compiler V2.26N/WIN * * Copyright (c) Jan 2003, Eugene Soloshenko snipped-for-privacy@mail.ru * All rights reserved. * * Description: * MF transceiver detects group of frequencies in the input signal and * returns their spectral power as a 2-byte numbers. At once transceiver can * analyse the following groups of frequencies: * a) AON (subscriber id, "2 from 6" protocol R1.5) * 700, 900, 1100, 1300, 1500, 1700 Hz * b) 425, 700, 1000, 2600 Hz * * For frequency detection is used 1-bit correlation (just a xor) between * input signal from comparator and reference frequency from table. */



#include <io2313.h>



#include <ina90.h>



#include "macros.h" #include "bit.h" #include "hardw.h"



/* * Global variables */



#define SAMPLE_CONST 443 // XTAL/(SAMPLE_CONST+1) = 8e6/444 = 18.018 kHz



uchar __flash copyright[]="(c) Eugene Soloshenko snipped-for-privacy@mal.ru"; uchar gen_time; // <signal duration> * 5mS uchar id; // id = fqCode + flag single/dual fq (bit7)



uint sp_pwr[6]; // spectral power for frequencies uchar *spwr_ptr; // ptr to spectral power array



uchar flags; // get_port() #define prev_STB 0 #define now_STB 1



#define CompNow 2 /* Sampled value from comparator */ #define NewCompSampl 3 /* flag to tell main that we've got new value*/



/* * Function prototypes */ void generate(void); void detect_AON (void); void detect_tone (void); uchar get_port (void);



/************************************************************************** * Interface section. Interface with external master **************************************************************************/



// RW_PIN logic #define WR 0 #define RD 1



// Commands from master - 4 commands implemented // // 00xx xxxx - GEN_AON // 01xx xxxx - GEN_TONE // 10xx xxxx - DET_AON // 11xx xxxx - DET_TONE // ||| | // ||`-----`--- parameters // ``---------- command type



#define GEN_AON 0x00 // 0b00000000 - generate AON "2 from 6" #define GEN_TONE 0x40 // 0b01000000 - generate single tone #define DET_AON 0x80 // 0b10000000 - detect AON "2 from 6" #define DET_TONE 0xC0 // 0b11000000 - detect single tone



#define CMD_MASK 0xC0 // 11000000b - parameters mask



/*************************************************************************** * Main ***************************************************************************/ __C_task void main (void) {



init_port(); /* set init directions & levels */



TCNT1H = TCNT1L = 0; OCR1 = SAMPLE_CONST;



SETBIT(TCCR1B,CTC1); // enable tmr clear on compare



/* Enable interrupt from tmr1_compare */ __enable_interrupt(); SETBIT(TIMSK,OCIE1A);



/* Start WDT */ #ifdef WDT_ON WDTCR = _WDT_REG; // enable WDT (see hardw.h) #endif



// on(BUSY); // busy now on(SMPL_TEST); // Main loop for (;;) {



uchar cmd; uchar tmp;



#ifdef WDT_ON __watchdog_reset(); #endif



tmp = cmd = get_port(); tmp &= CMD_MASK; // mask parameters to decode command // command in bits B7,B6



if (tmp == GEN_AON) {



id = cmd & 0x0F; // 00001111b params = 4 lower bits SETBIT(id,7); // flag dual-fq generation gen_time = get_port(); // get generation time generate();



} else if (tmp == GEN_TONE) {



id = cmd & 0x07; // 00000111b param = 3 lower bits gen_time = get_port(); // get generation time generate();



}

else if (tmp == DET_AON) { detect_AON(); spwr_ptr = (uchar *)(sp_pwr); /* update ptr to spectral summ */ }



else if (tmp == DET_TONE) { detect_tone(); spwr_ptr = (uchar *)(sp_pwr); /* update ptr to spectral summ */ }



} // end for(;;) }



/**************************************************************************** * Generate section - not implemented ****************************************************************************/ void generate (void) {



}

/**************************************************************************** * Detect section ****************************************************************************/



/* Number of sampled points. This value defines the length of the capture window. Twin = POINTS * 1/Fsample.



!!!NB no more than 170 points is allowed, cause array index has uchar-size so 1.5bytes/point => 170*1.5 = 255) */ #define POINTS 144 /* Twin = 8 mS for Fsample=18.018 kHz */



/* * Detect AON ("2 from 6") */ void detect_AON (void) {



/* Accum indexes. S- sin, C- cos */ enum {S_700, C_700, S_900, C_900, S_1100, C_1100, S_1300, C_1300, S_1500, C_1500, S_1700, C_1700};



/* * Table of frequencies being detected - sin/cos 700..1700 Hz * Fs = 18.018 kHz, 180 points */ static __flash uchar fq_tbl [] = {



0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xAF,0xAA,0xEA,0x8A,0x80,0xA8,0x1A,0x01, 0xA0,0x58,0x17,0x81,0x70,0x5F,0x07,0xE0,0x7E,0x17,0x81,0xF8,0x1E,0x81,0xE1, 0x5E,0x17,0x81,0x78,0x77,0x87,0x78,0x67,0x1E,0xE1,0xEE,0x1C,0xE3,0x8E,0x78, 0xE7,0x9C,0x71,0xC6,0x38,0xE3,0x8E,0x78,0xC6,0x9C,0x69,0x8E,0x98,0xC1,0x9C, 0x19,0x93,0x19,0x33,0x93,0x33,0x33,0x33,0x33,0x66,0x66,0x66,0x66,0x46,0x4C, 0x6C,0xC4,0xCD,0xCD,0x9C,0xDB,0xC9,0xBC,0x93,0xDB,0x2D,0xB2,0x93,0x69,0x24, 0x92,0x4B,0x2D,0xB6,0xDB,0x4D,0xB4,0xB3,0x4B,0x2D,0xB2,0xD2,0x2D,0x22,0xD0, 0x2B,0x44,0xB4,0x4B,0x54,0xAD,0x42,0xD4,0x2F,0x52,0xB5,0x0A,0xD4,0xAD,0x42, 0xD5,0x0F,0x50,0xFD,0x4F,0xD5,0xBF,0x5B,0xFF,0xAB,0xFA,0xAF,0xAA,0xAA,0xAA, 0xAA,0xA0,0x00,0x00,0x00,0x01,0x01,0x50,0x55,0x15,0x75,0x5F,0x57,0xF5,0xFE, 0x5F,0xA7,0xE8,0x7E,0x8F,0xA0,0xF8,0x1F,0x81,0xE8,0x7E,0x07,0xE1,0x7E,0x1E, 0xA1,0xE8,0x7E,0x87,0x88,0x78,0x87,0x98,0xE1,0x1E,0x11,0xE3,0x1C,0x71,0x87, 0x18,0x63,0x8E,0x39,0xC7,0x1C,0x71,0x87,0x39,0x63,0x96,0x71,0x67,0x3E,0x63, 0xE6,0x6C,0x66,0xCC,0x6C,0xCC,0xCC,0xCC,0xCC,0x99,0x99,0x99,0x99,0xB9,0xB3, 0x93,0x3B,0x32,0x33,0x63,0x26,0x36,0x43,0x6C,0x24,0xD2,0x4D,0x2C,0x96,0xDB, 0x6D,0xB4,0xD3,0x49,0x24,0xB2,0x4B,0x4C,0xB4,0xD2,0x4D,0x2D,0xD2,0xDD,0x2F, 0xD4,0xBB,0x4B,0xB4,0xAB,0x52,0xBD,0x2B,0xD0,0xAD,0x4A,0xF5,0x2B,0x52,0xBD, 0x2A,0xF0,0xAF,0x02,0xB0,0x2A,0x40,0xA4,0x00,0x50,0x05,0x50,0x55,0x55,0x55

};



uchar sum[12]; /* accum array: sin700,cos700,sin900, ... */



uchar k; uchar i_t; /* index through fq table */ uint tbl_i; /* data from table for _all_ freqs being detected for current sample - 12 bits */



/* Clear accum */ k = 11; do { sum[k] = 0; } while (k-- != 0);



i_t = 0;



TCCR1B |= 1; // start tmr1 w/o prescaling CLEARBIT(flags,NewCompSampl);



/* Calculate correlation for current sample */ for (k = 0; k != POINTS; k++) {



/* wait for new sample from comparator */ while (!TESTBIT(flags,NewCompSampl)) ;



CLEARBIT(flags,NewCompSampl);



BYTE(tbl_i,WHI) = fq_tbl[i_t++]; BYTE(tbl_i,WLO) = fq_tbl[i_t];



if ( TESTBIT(flags,CompNow) ) { tbl_i = ~tbl_i; }



if ( TESTBIT(k,0) ) { /* for odd samples shift to left edge, even samples already at left edge */ i_t++; tbl_i<<=4; }



/* Proccess from left to right */ if ( TESTBIT(BYTE(tbl_i,WHI),7) ) sum[S_700]++;



if ( TESTBIT(BYTE(tbl_i,WHI),6) ) sum[C_700]++;



if ( TESTBIT(BYTE(tbl_i,WHI),5) ) sum[S_900]++;



if ( TESTBIT(BYTE(tbl_i,WHI),4) ) sum[C_900]++;



if ( TESTBIT(BYTE(tbl_i,WHI),3) ) sum[S_1100]++;



if ( TESTBIT(BYTE(tbl_i,WHI),2) ) sum[C_1100]++;



if ( TESTBIT(BYTE(tbl_i,WHI),1) ) sum[S_1300]++;



if ( TESTBIT(BYTE(tbl_i,WHI),0) ) sum[C_1300]++;



if ( TESTBIT(BYTE(tbl_i,WLO),7) ) sum[S_1500]++;



if ( TESTBIT(BYTE(tbl_i,WLO),6) ) sum[C_1500]++;



if ( TESTBIT(BYTE(tbl_i,WLO),5) ) sum[S_1700]++;



if ( TESTBIT(BYTE(tbl_i,WLO),4) ) sum[C_1700]++;



} /* end fq checking for current sample */



/* Normalize accumulators */ k = 11; do {



if (sum[k] < POINTS/2) sum[k]=~(sum[k]-POINTS/2); else sum[k] -= POINTS/2;



} while (k-- != 0);



/* Calculate spectral power */ for (k=0; k != 6; k++) { sp_pwr[k] = sum[k*2]*sum[k*2] + sum[k*2+1]*sum[k*2+1]; }



TCCR1B &= 0xF8; // 11111000b stop tmr1 }



/* * Detet tones (425, 700, 100, 2600 Hz) */ void detect_tone (void) {



/* Accum indexes. S- sin, C- cos */ enum {S_425, C_425, S_700, C_700, S_1000, C_1000, S_2600, C_2600 };



/* * Table of frequencies being detected - sin/cos 425, 700, 1000, 2600 * Fs = 18.018 kHz, 180 points */ static uchar __flash fq_tbl [] = {



0xFF,0xFF,0xFE,0xFE,0xFC,0xF8,0xF9,0xEB,0xEB,0xEA,0xE2,0xA0,0xA0,0x81,0x87, 0x87,0x86,0x86,0x84,0x8C,0x9D,0x9F,0x1F,0x1A,0x1A,0x18,0x39,0x39,0x33,0x33, 0x32,0x32,0x74,0x65,0x65,0x67,0x67,0x6E,0x6E,0x4C,0x4D,0x49,0x4B,0xCB,0xCA, 0xCA,0xD0,0xD1,0xD1,0xD3,0xD7,0xD6,0xF4,0xB4,0xB5,0xBD,0xBF,0xBF,0xAE,0xA8, 0xA8,0xA9,0xA9,0xAB,0x23,0x02,0x00,0x00,0x05,0x05,0x07,0x17,0x16,0x1C,0x1C, 0x5D,0x5D,0x5B,0x7A,0x7A,0x78,0x78,0x71,0x71,0x63,0xE2,0xE6,0xE4,0xE4,0xE5, 0xE5,0xCF,0xCE,0xCE,0xCC,0xC8,0x89,0x99,0x9B,0x9A,0x92,0x90,0x90,0xB1,0xB7, 0xB7,0x36,0x36,0x34,0x3C,0x2D,0x2F,0x2F,0x2A,0x2A,0x28,0x08,0x49,0x43,0x43, 0x42,0x42,0x44,0x54,0x55,0x57,0x57,0x5E,0xDE,0xFC,0xFD,0xF9,0xFB,0xFB,0xFA, 0xFA,0xE0,0xE1,0xA1,0xA3,0xA7,0xA6,0x86,0x84,0x85,0x8D,0x8F,0x8F,0x8E,0x18, 0x18,0x19,0x19,0x1B,0x13,0x32,0x30,0x30,0x35,0x75,0x77,0x67,0x66,0x6C,0x6C, 0x6D,0x6D,0x6B,0x4B,0x4A,0xC8,0xC8,0xC1,0xC1,0xD3,0xD2,0xD6,0xD4,0xD4,0xD5

};



uchar sum[8]; /* accum array: sin425,cos425,sin700, ... */



uchar k; uchar i_t; /* index through fq table */ uchar tbl_i; /* data from table for _all_ freqs being detected for current sample - 8 bits */



/* Clear accum */ k = 7; do { sum[k] = 0; } while (k-- != 0);



i_t = 0;



TCCR1B |= 1; // start tmr1 w/o prescaling CLEARBIT(flags,NewCompSampl);



/* Calculate correlation for current sample */ for (k = 0; k != POINTS; k++) {



/* wait for new sample from comparator */ while (!TESTBIT(flags,NewCompSampl)) ;



CLEARBIT(flags,NewCompSampl);



tbl_i = fq_tbl[i_t++];



if ( TESTBIT(flags,CompNow) ) { tbl_i = ~tbl_i; }



/* Proccess from left to right */ if ( TESTBIT(tbl_i,7) ) sum[S_425]++;



if ( TESTBIT(tbl_i,6) ) sum[C_425]++;



if ( TESTBIT(tbl_i,5) ) sum[S_700]++;



if ( TESTBIT(tbl_i,4) ) sum[C_700]++;



if ( TESTBIT(tbl_i,3) ) sum[S_1000]++;



if ( TESTBIT(tbl_i,2) ) sum[C_1000]++;



if ( TESTBIT(tbl_i,1) ) sum[S_2600]++;



if ( TESTBIT(tbl_i,0) ) sum[C_2600]++;



} /* end fq checking for current sample */



/* Normalize accumulators */ k = 7; do {



if (sum[k] < POINTS/2) sum[k]=~(sum[k]-POINTS/2); else sum[k] -= POINTS/2;



} while (k-- != 0);



/* Calculate spectral power */ for (k=0; k != 4; k++) { sp_pwr[k] = sum[k*2]*sum[k*2] + sum[k*2+1]*sum[k*2+1]; }



TCCR1B &= 0xF8; // 11111000b stop tmr1



}

/* * External interface * * Master: * - set STB = 0 * - set CS = 0 * - set RW_PIN = 0 (for write) RW_PIN = 1 (for read) * - check if slave (MFchip) availible (BUSY = 0) * Write: * - set data * - leading edge STB * Read: * - leading edge STB * - slave sets data and BUSY flag * - read data (slave hold data while STB is active) * * While master is reading (leading edge at RW_PIN = 1) - we sit in function * If master reads more than array sum[] size, then RAM after array will * be read. * Exit when command from master is reaceived (leading edge at RW_PIN = 0) */



uchar get_port (void) {



uchar res;



/* sample current STB level: now_STB = STB_PIN */ if ( signal(STB) ) { SETBIT(flags,now_STB); } else { CLEARBIT(flags,now_STB); }



wait_CS:



/* Data bus as input */ DDRB = _DIRB_IN; DDRD = _DIRD_Z; // off busy



while ( signal(CS) ) { ; // wait for CS == 0 #ifdef WDT_ON __watchdog_reset(); #endif }



DDRD = _DIRD_IN; // off busy off (BUSY); // tell to master that we are ready



// Wait STB leading edge and check CS do {



#ifdef WDT_ON __watchdog_reset(); #endif



if (signal(CS)) // CS==1 => urgent exit goto wait_CS;



// store prev state : prev_STB = now_STB if (TESTBIT(flags,now_STB)) { SETBIT(flags,prev_STB); } else { CLEARBIT(flags,prev_STB); }



/* sample current STB level: now_STB = STB_PIN */ if ( signal(STB) ) { SETBIT(flags,now_STB); } else { CLEARBIT(flags,now_STB); }



} while (!(TESTBIT(flags,now_STB) && !TESTBIT(flags,prev_STB))); // leading edge



// Switch RD - /WD ? if ( signal(RW) ) { // RD state



DATA_L_OUT &= 0x0F; // clr data bus DATA_H_OUT &= 0xF0; // clr data bus



DATA_L_OUT |= ((*spwr_ptr)<<4); // low nibble, 0 in unsed bit coz pullup off DATA_H_OUT |= ((*spwr_ptr)>>4); // high nibble



spwr_ptr++;



/* Data bus as output */ DDRB = _DIRB_OUT; DDRD = _DIRD_OUT; on(BUSY); // set BUSY flag



/* sample current STB level: now_STB = STB_PIN */ if ( signal(STB) ) { SETBIT(flags,now_STB); } else { CLEARBIT(flags,now_STB); }



// wait for STB falling and check CS, RW. Hold data, while STB active do {



#ifdef WDT_ON __watchdog_reset(); #endif



if ( signal(CS) || !signal(RW) ) // CS==1 || RW==0 (write) goto wait_CS; // urgent exit



// store prev state : prev_STB = now_STB if (TESTBIT(flags,now_STB)) { SETBIT(flags,prev_STB); } else { CLEARBIT(flags,prev_STB); }



/* sample current STB level: now_STB = STB_PIN */ if ( signal(STB) ) { SETBIT(flags,now_STB); } else { CLEARBIT(flags,now_STB); }



} while (!(!TESTBIT(flags,now_STB) && TESTBIT(flags,prev_STB))); // drop



goto wait_CS; // sit in function // switch port to input with first cmd after goto } else { // WR state res = ((DATA_H_IN)<<4); res |= ((DATA_L_IN)>>4); on(BUSY); // set BUSY flag return (res); }



}

/* * Timer1 compare interrupt * Sampling frequency = 18.018 kHz (T = 55.5 uS ) */ #pragma vector = TIMER1_COMP1_vect __interrupt void TIMER1_COMP1_interrupt(void) {



/* sample comparator */ if ( signal(COMP) ) { SETBIT(flags,CompNow); } else { CLEARBIT(flags,CompNow); }



cpl(SMPL_TEST); // test signal



SETBIT(flags,NewCompSampl); // tell to main that we've got new sample }



=== main.c ===



wbr, eugene // solosh '\x40' mail.ru


Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required