विषयसूची:
वीडियो: डीटीएमएफ डिटेक्टर: 4 कदम
2024 लेखक: John Day | [email protected]. अंतिम बार संशोधित: 2024-01-30 09:22
अवलोकन
मुझे डिजिटल सिग्नल प्रोसेसिंग ऑनलाइन पाठ्यक्रम पर एक होम असाइनमेंट द्वारा इस उपकरण को बनाने के लिए प्रेरित किया गया था। यह एक 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: स्कीमैटिक्स
निम्नलिखित कनेक्शन किए जाने चाहिए:
माइक से 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 है तो वांछित आवृत्तियाँ विवेकीकरण ग्रिड के साथ मेल खाती हैं। उसके लिए एडीसी का उपयोग टाइमर ओवरफ्लो मोड में किया जाना चाहिए।
सिफारिश की:
डीटीएमएफ वीडियो स्ट्रीमिंग रोवर: 3 कदम
डीटीएमएफ वीडियो स्ट्रीमिंग रोवर: हाय मेरे लिनक्स टर्मिनल नियंत्रित रोवर और वाईफ़ाई डीटीएमएफ पीसी नियंत्रित रोबोट के बाद यह मेरा तीसरा रोबोट है। और अन्य दो की तरह यहां भी मैंने इसे सरल और आसान बनाने के लिए किसी भी माइक्रोकंट्रोलर या प्रोग्रामिंग का उपयोग नहीं किया। यह वाईफाई पर लाइव वीडियो भी स्ट्रीम करता है
एक साधारण डीटीएमएफ (टोन) फोन लाइन डिकोडर कैसे बनाएं: 3 कदम
एक साधारण डीटीएमएफ (टोन) फोन लाइन डिकोडर कैसे बनाएं: यह एक साधारण परियोजना है जो आपको मूल रूप से किसी भी फोन लाइन पर डीटीएमएफ संकेतों को डीकोड करने देती है। इस ट्यूटोरियल में, हम डिकोडर MT8870D का उपयोग कर रहे हैं। हम एक प्रीबिल्ट टोन डिकोडर का उपयोग कर रहे हैं क्योंकि, मेरा विश्वास करो, यह कोशिश करने और इसे करने के लिए पीछे की ओर दर्द है
वाईफ़ाई डीटीएमएफ रोबोट: 5 कदम
वाईफ़ाई डीटीएमएफ रोबोट: हाय इस ट्यूटोरियल में मैं आपको दिखाने जा रहा हूं कि आप माइक्रो कंट्रोलर का उपयोग किए बिना पीसी नियंत्रित रोवर कैसे बना सकते हैं, इसका मतलब है कि इस परियोजना में कोई उच्च स्तरीय कोड शामिल नहीं है, आपको एचटीएमएल पेज बनाने के बारे में बुनियादी ज्ञान की आवश्यकता है। पूरा देख सकते हैं
मोबाइल नियंत्रित रोबोट कैसे बनाये - डीटीएमएफ आधारित - माइक्रोकंट्रोलर और प्रोग्रामिंग के बिना - दुनिया में कहीं से भी नियंत्रण - रोबोजीक्स: १५ कदम
मोबाइल नियंत्रित रोबोट कैसे बनाये | डीटीएमएफ आधारित | माइक्रोकंट्रोलर और प्रोग्रामिंग के बिना | दुनिया में कहीं से भी नियंत्रण | RoboGeeks: एक ऐसा रोबोट बनाना चाहते हैं जिसे दुनिया में कहीं से भी नियंत्रित किया जा सकता है, आइए इसे करते हैं
डीटीएमएफ नियंत्रित कार। मोबाइल फ़ोन की आवश्यकता नहीं: 3 कदम
DTMF नियंत्रित कार। मोबाइल फोन की आवश्यकता नहीं: रोबोट और रोबो कार अनिवार्य रूप से दुनिया भर के तकनीकी उत्साही और वैज्ञानिकों दोनों के लिए नए दिन के खिलौने हैं। वे हर जगह आवेदन पाते हैं। यहां इस ट्यूटोरियल में मैं आपको समझाऊंगा कि कैसे arduino का उपयोग करके DTMF नियंत्रित रोबोटिक कार बनाई जाती है और