DTMF декодер

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

Reply to
Eugene Soloshenko
Loading thread data ...

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.