विषयसूची:

डीटीएमएफ डिटेक्टर: 4 कदम
डीटीएमएफ डिटेक्टर: 4 कदम

वीडियो: डीटीएमएफ डिटेक्टर: 4 कदम

वीडियो: डीटीएमएफ डिटेक्टर: 4 कदम
वीडियो: GSM/GPRS-модуль SIM800L (#4) - все о DTMF: парсинг, управление, безопасность 2024, नवंबर
Anonim
Image
Image

अवलोकन

मुझे डिजिटल सिग्नल प्रोसेसिंग ऑनलाइन पाठ्यक्रम पर एक होम असाइनमेंट द्वारा इस उपकरण को बनाने के लिए प्रेरित किया गया था। यह एक DTMF डिकोडर है जिसे Arduino UNO के साथ लागू किया गया है, यह ध्वनि के द्वारा टोन मोड में फ़ोन कीपैड पर दबाए गए अंक का पता लगाता है।

चरण 1: एल्गोरिदम को समझना

कोड
कोड

DTMF में प्रत्येक प्रतीक चित्र पर तालिका के अनुसार दो आवृत्तियों के साथ एन्कोड किया गया है।

डिवाइस माइक्रोफ़ोन से इनपुट कैप्चर करता है और आठ आवृत्तियों के आयामों की गणना करता है। अधिकतम आयामों वाली दो आवृत्तियाँ एन्कोडेड प्रतीक की एक पंक्ति और एक स्तंभ देती हैं।

आंकड़ा अधिग्रहण

स्पेक्ट्रम विश्लेषण करने के लिए नमूनों को एक निश्चित पूर्वानुमेय आवृत्ति पर लिया जाना चाहिए। इसे प्राप्त करने के लिए मैंने अधिकतम परिशुद्धता (प्रीस्केलर 128) के साथ फ्री-रन एडीसी मोड का उपयोग किया, यह नमूना दर 9615 हर्ट्ज देता है। नीचे दिया गया कोड दिखाता है कि Arduino के ADC को कैसे कॉन्फ़िगर किया जाए।

शून्य initADC () {

// इनिट एडीसी; f = (16MHz/prescaler) / 13 चक्र/रूपांतरण ADMUX = 0; // चैनल सेल, राइट-एडज, AREF पिन ADCSRA = _BV (ADEN) का उपयोग करें | // एडीसी सक्षम _BV (ADSC) | // एडीसी प्रारंभ _BV(ADATE) | // ऑटो ट्रिगर _BV (ADIE) | // इंटरप्ट इनेबल _BV (ADPS2) | _BV(ADPS1) | _बीवी (एडीपीएस0); // 128:1 / 13 = 9615 हर्ट्ज एडीसीएसआरबी = 0; // फ्री-रन मोड DIDR0 = _BV (0); // एडीसी पिन TIMSK0 = 0 के लिए डिजिटल इनपुट बंद करें; // Timer0 off } और इंटरप्ट हैंडलर इस तरह दिखता है ISR(ADC_vect) { uint16_t sample = ADC;samples[samplePos++] = sample - 400; अगर (नमूना स्थिति> = एन) {एडीसीएसआरए और = ~_बीवी (एडीआईई); // बफर भरा हुआ, इंटरप्ट ऑफ } }

स्पेक्ट्रम विश्लेषण

नमूने एकत्र करने के बाद मैं 8 आवृत्तियों एन्कोडिंग प्रतीकों के आयामों की गणना करता हूं। मुझे इसके लिए पूर्ण FFT चलाने की आवश्यकता नहीं है, इसलिए मैंने गोएर्टज़ेल के एल्गोरिथम का उपयोग किया।

शून्य गोएर्टज़ेल (uint8_t * नमूने, फ्लोट * स्पेक्ट्रम) {

फ्लोट v_0, v_1, v_2; फ्लोट रे, आईएम, amp; के लिए (uint8_t k = 0; k <IX_LEN; k++) {फ्लोट c = pgm_read_float(&(cos_t[k])); फ्लोट एस = pgm_read_float (और (sin_t [k])); फ्लोट ए = 2. * सी; v_0 = v_1 = v_2 = 0; के लिए (uint16_t i = 0; i <N; i++) { v_0 = v_1; वी_1 = वी_2; v_2 = (फ्लोट)(नमूने) + a * v_1 - v_0; } पुनः = सी * v_2 - v_1; आईएम = एस * v_2; amp = sqrt (पुनः * पुनः + आईएम * आईएम); स्पेक्ट्रम [के] = amp; } }

चरण 2: कोड

ऊपर दी गई तस्वीर अंक 3 के एन्कोडिंग का उदाहरण दिखाती है जहां अधिकतम आयाम 697 हर्ट्ज और 1477 हर्ट्ज आवृत्तियों के अनुरूप होता है।

पूरा स्केच इस प्रकार दिखता है

/** * कनेक्शन: * [माइक टू Arduino] * - आउट -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AreF -> 3.3V * [Arduino को प्रदर्शित करें] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include

#शामिल

# सीएस_पिन 9 परिभाषित करें

#डिफाइन एन 256

#परिभाषित करें IX_LEN 8 #सीमा 20 परिभाषित करें

LEDMatrixDriver lmd(1, CS_PIN);

uint8_t नमूने [एन];

अस्थिर uint16_t नमूना स्थिति = 0;

फ्लोट स्पेक्ट्रम [IX_LEN];

// बारंबारता [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]

// ९६१५ हर्ट्ज़ २५६ नमूनों के लिए परिकलित फ्लोट cos_t [IX_LEN] PROGMEM = { ०.८९३२२४३०११९५५५५३, ०.८७००८०८६९९११०८७११५, ०.८४४८५३५६५२४९७०७१, ०.८०३२०७५३१४८०६४४९, ०.६८९५४०५४४७३७०६६९, ०.६८९९७८ ०.५५५७०२३३०१९, ०.६८९९७८ ०. const फ्लोट sin_t[IX_LEN] PROGMEM = { 0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025451, 0.88192126443;

टाइपपीफ संरचना {

चार अंक; uint8_t सूचकांक; } digit_t;

डिजिट_टी डिटेक्टेड_डिजिट;

कास्ट चार टेबल [४] [४] PROGMEM = {

{'1', '2', '3', 'ए'}, {'4', '5', '6', 'बी'}, {'7', '8', '9', ' सी'}, {'*', '0', '#', 'डी'}};

const uint8_t char_indexes[4][4] PROGMEM = {

{1, 2, 3, 10}, {4, 5, 6, 11}, {7, 8, 9, 12}, {15, 0, 14, 13} };

बाइट फ़ॉन्ट [१६] [८] = {

{0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38}, // 0 {0x04, 0x0c, 0x14, 0x24, 0x04, 0x04, 0x04, 0x04}, // 1 {0x00, 0x30, 0x48, 0x04, 0x04, 0x38, 0x40, 0x7c}, // 2 {0x00, 0x38, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38}, // 3 {0x00, 0x04, 0x0c, 0x14, 0x24, 0x7e, 0x04, 0x04 }, // 4 {0x00, 0x7c, 0x40, 0x40, 0x78, 0x04, 0x04, 0x38}, // 5 {0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38}, // 6 {0x00, 0x7c, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10}, // 7 {0x00, 0x3c, 0x44, 0x44, 0x38, 0x44, 0x44, 0x78}, // 8 {0x00, 0x38, 0x44, 0x44, 0x3c, 0x04, 0x04, 0x78}, // 9 {0x00, 0x1c, 0x22, 0x42, 0x42, 0x7e, 0x42, 0x42}, // A {0x00, 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x7c}, / / बी {0x00, 0x3c, 0x44, 0x40, 0x40, 0x40, 0x44, 0x7c}, // सी {0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78}, // डी {0x00, 0x0a, 0x7f, 0x14, 0x28, 0xfe, 0x50, 0x00}, // # {0x00, 0x10, 0x54, 0x38, 0x10, 0x38, 0x54, 0x10} // * };

शून्य initADC () {

// इनिट एडीसी; f = (16MHz/prescaler) / 13 चक्र/रूपांतरण ADMUX = 0; // चैनल सेल, राइट-एडज, AREF पिन ADCSRA = _BV (ADEN) का उपयोग करें | // एडीसी सक्षम _BV (ADSC) | // एडीसी प्रारंभ _BV(ADATE) | // ऑटो ट्रिगर _BV (ADIE) | // इंटरप्ट इनेबल _BV (ADPS2) | _BV(ADPS1) | _बीवी (एडीपीएस0); // 128:1 / 13 = 9615 हर्ट्ज एडीसीएसआरबी = 0; // फ्री-रन मोड DIDR0 = _BV (0); // एडीसी पिन TIMSK0 = 0 के लिए डिजिटल इनपुट बंद करें; // टाइमर0 बंद }

शून्य गोएर्टज़ेल (uint8_t * नमूने, फ्लोट * स्पेक्ट्रम) {

फ्लोट v_0, v_1, v_2; फ्लोट रे, आईएम, amp; के लिए (uint8_t k = 0; k <IX_LEN; k++) {फ्लोट c = pgm_read_float(&(cos_t[k])); फ्लोट एस = pgm_read_float (और (sin_t [k])); फ्लोट ए = 2. * सी; v_0 = v_1 = v_2 = 0; के लिए (uint16_t i = 0; i <N; i++) { v_0 = v_1; वी_1 = वी_2; v_2 = (फ्लोट)(नमूने) + a * v_1 - v_0; } पुनः = सी * v_2 - v_1; आईएम = एस * v_2; amp = sqrt (पुनः * पुनः + आईएम * आईएम); स्पेक्ट्रम [के] = amp; } }

फ्लोट औसत (फ्लोट * ए, uint16_t लेन) {

फ्लोट परिणाम =.0; के लिए (uint16_t i = 0; i <लेन; i++) {परिणाम += a; } वापसी परिणाम / लेन; }

int8_t get_single_index_above_threshold(float *a, uint16_t लेन, फ्लोट थ्रेशोल्ड) {

अगर (दहलीज <थ्रेशोल्ड) {रिटर्न -1; } int8_t ix = -1; के लिए (uint16_t i = 0; i थ्रेशोल्ड) { अगर (ix == -1) { ix = i; } और {वापसी -1; } } } वापसी ix; }

शून्य डिटेक्ट_डिजिट (फ्लोट * स्पेक्ट्रम) {

फ्लोट avg_row = औसत (स्पेक्ट्रम, 4); फ्लोट avg_col = avg(&spectrum[4], 4); int8_t पंक्ति = get_single_index_above_threshold (स्पेक्ट्रम, 4, avg_row); int8_t col = get_single_index_above_threshold(&spectrum[4], 4, avg_col); अगर (पंक्ति! = -1 && col! = -1 && avg_col> 200) {डिटेक्टेड_डिजिट.डिजिट = pgm_read_byte (& (टेबल [पंक्ति] [कॉल])); डिटेक्टेड_डिजिट.इंडेक्स = pgm_read_byte(&(char_indexes[row][col])); } और { डिटेक्टेड_डिजिट.डिजिट = 0; } }

शून्य ड्रॉस्प्राइट (बाइट * स्प्राइट) {

// मास्क का उपयोग स्प्राइट रो बाइट मास्क = B10000000 से कॉलम बिट प्राप्त करने के लिए किया जाता है; for(int iy = 0; iy <8; iy++) { for(int ix = 0; ix <8; ix++) { lmd.setPixel(7 - iy, ix, (bool)(sprite[iy] & mask));

// मास्क को एक पिक्सेल से दाईं ओर शिफ्ट करें

मुखौटा = मुखौटा >> 1; }

// कॉलम मास्क रीसेट करें

मुखौटा = B10000000; } }

व्यर्थ व्यवस्था() {

क्ली (); initADC (); सेई ();

सीरियल.बेगिन (115200);

lmd.setEnabled (सच); lmd.setIntensity(2); एलएमडी.क्लियर (); एलएमडी.डिस्प्ले ();

डिटेक्टेड_डिजिट.डिजिट = 0;

}

अहस्ताक्षरित लंबा z = 0;

शून्य लूप () {

जबकि (एडीसीएसआरए और _बीवी (एडीआईई)); // goertzel (नमूने, स्पेक्ट्रम) को समाप्त करने के लिए ऑडियो नमूने की प्रतीक्षा करें; डिटेक्ट_डिजिट (स्पेक्ट्रम);

अगर (पता लगाया_अंक। अंक! = 0) {

ड्रास्प्राइट (फ़ॉन्ट [डिटेक्टेड_डिजिट.इंडेक्स]); एलएमडी.डिस्प्ले (); } अगर (z% 5 == 0) { के लिए (int i = 0; i <IX_LEN; i++) { Serial.print(spectrum); सीरियल.प्रिंट ("\ t"); } सीरियल.प्रिंट्लन (); Serial.println((int)detected_digit.digit); } जेड++;

नमूना स्थिति = 0;

ADCSRA |= _BV (ADIE); // सैंपलिंग इंटरप्ट फिर से शुरू करें

}

आईएसआर (ADC_vect) {

uint16_t नमूना = एडीसी;

नमूने [नमूनापोस++] = नमूना - 400;

अगर (नमूना स्थिति> = एन) {एडीसीएसआरए और = ~_बीवी (एडीआईई); // बफर भरा हुआ, इंटरप्ट ऑफ } }

चरण 3: स्कीमैटिक्स

schematics
schematics

निम्नलिखित कनेक्शन किए जाने चाहिए:

माइक से Arduino

आउट -> ए0

Vcc -> 3.3V Gnd -> Gnd

AREF को 3.3V से जोड़ना महत्वपूर्ण है।

Arduino को प्रदर्शित करें

वीसीसी -> 5वी

Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9

चरण 4: निष्कर्ष

यहां क्या सुधार किया जा सकता है? मैंने 9615Hz की दर से N = 256 नमूनों का उपयोग किया, जिसमें कुछ स्पेक्ट्रम रिसाव है, यदि N = 205 और दर 8000Hz है तो वांछित आवृत्तियाँ विवेकीकरण ग्रिड के साथ मेल खाती हैं। उसके लिए एडीसी का उपयोग टाइमर ओवरफ्लो मोड में किया जाना चाहिए।

सिफारिश की: