جدول المحتويات:
فيديو: كاشف DTMF: 4 خطوات
2024 مؤلف: John Day | [email protected]. آخر تعديل: 2024-01-30 07:40
ملخص
لقد ألهمني تصميم هذا الجهاز من خلال مهمة منزلية في دورة معالجة الإشارات الرقمية عبر الإنترنت. هذا هو وحدة فك ترميز DTMF مطبقة مع Arduino UNO ، فهي تكتشف رقمًا مضغوطًا على لوحة مفاتيح الهاتف في وضع النغمة من خلال الصوت الذي تنتجه.
الخطوة 1: فهم الخوارزمية
في DTMF يتم ترميز كل رمز بترددين حسب الجدول الموجود في الصورة.
يلتقط الجهاز المدخلات من الميكروفون ويحسب سعة ثمانية ترددات. يعطي ترددان ذو سعة قصوى صفًا وعمودًا من الرمز المشفر.
الحصول على البيانات
من أجل إجراء تحليل الطيف ، ينبغي التقاط عينات عند تردد معين يمكن التنبؤ به. لتحقيق ذلك ، استخدمت وضع ADC للتشغيل الحر بأقصى دقة (مقياس مسبق 128) ، فإنه يعطي معدل أخذ العينات 9615 هرتز. يوضح الكود أدناه كيفية تكوين ADC في Arduino.
initADC () باطلة {
// التهيئة ADC ؛ f = (16 ميجا هرتز / مقياس مسبق) / 13 دورة / تحويل ADMUX = 0 ؛ // قناة sel ، يمينًا ، استخدم AREF pin ADCSRA = _BV (ADEN) | // ADC تمكين _BV (ADSC) | // ADC start _BV (ADATE) | // مشغل تلقائي _BV (ADIE) | // تمكين المقاطعة _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0) ؛ // 128: 1/13 = 9615 هرتز ADCSRB = 0 ؛ // وضع التشغيل الحر DIDR0 = _BV (0) ؛ // إيقاف تشغيل الإدخال الرقمي لـ ADC pin TIMSK0 = 0 ؛ // Timer0 off} ويبدو معالج المقاطعة مثل ISR (ADC_vect) {uint16_t sample = ADC؛ sample [samplePos ++] = sample - 400 ؛ إذا (samplePos> = N) {ADCSRA & = ~ _BV (ADIE) ؛ // المخزن المؤقت ممتلئ ، المقاطعة متوقفة}}
تحليل الطيف
بعد جمع العينات ، أحسب اتساع رموز ترميز 8 ترددات. لست بحاجة إلى تشغيل FFT بالكامل لهذا الغرض ، لذلك استخدمت خوارزمية Goertzel.
goertzel باطل (uint8_t * عينات ، طيف تعويم *) {
تعويم v_0 ، v_1 ، v_2 ؛ تعويم إعادة ، الدردشة ، أمبير ؛ لـ (uint8_t k = 0؛ k <IX_LEN؛ k ++) {float c = pgm_read_float (& (cos_t [k])) ؛ float s = 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 ؛ v_1 = v_2 ؛ v_2 = (تعويم) (عينات ) + a * v_1 - v_0 ؛ } re = c * v_2 - v_1 ؛ im = s * v_2 ؛ أمبير = sqrt (re * re + im * im) ؛ الطيف [ك] = أمبير ؛ }}
الخطوة الثانية: الكود
توضح الصورة أعلاه مثال ترميز الرقم 3 حيث يتوافق السعة القصوى مع الترددات 697 هرتز و 1477 هرتز.
يبدو الرسم الكامل على النحو التالي
/ ** * التوصيلات: * [Mic to Arduino] * - Out -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [عرض على Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 * / # تضمين # تضمين
#يشمل
#define CS_PIN 9
# تعريف شمال 256
#define IX_LEN 8 # تعريف THRESHOLD 20
LEDMatrixDriver lmd (1 ، CS_PIN) ؛
عينات uint8_t [N] ؛
uint16_t samplePos = 0 ؛
طيف تعويم [IX_LEN] ؛
// الترددات [697.0، 770.0، 852.0، 941.0، 1209.0، 1336.0، 1477.0، 1633.0]
// محسوبة لـ 9615 هرتز 256 عينة عائمة cos_t [IX_LEN] PROGMEM = {0.8932243011955153 ، 0.8700869911087115 ، 0.8448535652497071 ، 0.8032075314806449 ، 0.6895405447370669 ، 0.6343932841636456 ، 0.55553619 ، const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654، 0.49289819222978404، 0.5349976198870972، 0.5956993044924334، 0.7242470829514669، 0.7730104533627369، 0.8314696123025612}؛
بنية typedef {
رقم الحرف فهرس uint8_t ؛ } digit_t؛
تم الكشف عن digit_t_digit ؛
جدول الحرف الثابت [4] [4] PROGMEM = {
{'1'، '2'، '3'، 'A'}، {'4'، '5'، '6'، 'B'}، {'7'، '8'، '9'، ' C '}، {' * '،' 0 '،' # '،' D '}} ؛
const uint8_t char_indexes [4] [4] PROGMEM = {
{1, 2, 3, 10}, {4, 5, 6, 11}, {7, 8, 9, 12}, {15, 0, 14, 13} };
خط بايت [16] [8] = {
{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} ، / / / B {0x00 ، 0x3c ، 0x44 ، 0x40 ، 0x40 ، 0x40 ، 0x44 ، 0x7c} ، // C {0x00 ، 0x7c ، 0x42 ، 0x42 ، 0x42 ، 0x42 ، 0x44 ، 0x78} ، // D {0x00 ، 0x0a ، 0x7f ، 0x14 ، 0x28 ، 0xfe ، 0x50 ، 0x00} ، // # {0x00 ، 0x10 ، 0x54 ، 0x38 ، 0x10 ، 0x38 ، 0x54 ، 0x10} // *} ؛
initADC () باطلة {
// التهيئة ADC ؛ f = (16 ميجا هرتز / مقياس مسبق) / 13 دورة / تحويل ADMUX = 0 ؛ // قناة sel ، يمينًا ، استخدم AREF pin ADCSRA = _BV (ADEN) | // ADC تمكين _BV (ADSC) | // ADC start _BV (ADATE) | // مشغل تلقائي _BV (ADIE) | // تمكين المقاطعة _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0) ؛ // 128: 1/13 = 9615 هرتز ADCSRB = 0 ؛ // وضع التشغيل الحر DIDR0 = _BV (0) ؛ // إيقاف تشغيل الإدخال الرقمي لـ ADC pin TIMSK0 = 0 ؛ // Timer0 off}
goertzel باطل (uint8_t * عينات ، طيف تعويم *) {
تعويم v_0 ، v_1 ، v_2 ؛ تعويم إعادة ، الدردشة ، أمبير ؛ لـ (uint8_t k = 0؛ k <IX_LEN؛ k ++) {float c = pgm_read_float (& (cos_t [k])) ؛ float s = 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 ؛ v_1 = v_2 ؛ v_2 = (تعويم) (عينات ) + a * v_1 - v_0 ؛ } re = c * v_2 - v_1 ؛ im = s * v_2 ؛ أمبير = sqrt (re * re + im * im) ؛ الطيف [ك] = أمبير ؛ }}
float avg (float * a، uint16_t len) {
نتيجة تعويم =.0 ؛ لـ (uint16_t i = 0؛ i <len؛ i ++) {result + = a ؛ } نتيجة الإرجاع / len ؛ }
int8_t get_single_index_above_threshold (float * a، uint16_t len، float threshold) {
إذا (عتبة <THRESHOLD) {إرجاع -1 ؛ } int8_t ix = -1 ؛ لـ (uint16_t i = 0 ؛ i الحد الأدنى) {if (ix == -1) {ix = i؛ } آخر {عودة -1؛ }}} عودة ix؛ }
كشف باطل رقم (طيف * طيف) {
تعويم avg_row = avg (طيف ، 4) ؛ تعويم avg_col = متوسط (& طيف [4] ، 4) ؛ int8_t row = get_single_index_above_threshold (طيف ، 4 ، avg_row) ؛ int8_t col = get_single_index_above_threshold (& الطيف [4]، 4، avg_col) ؛ إذا (row! = -1 && col! = -1 && avg_col> 200) {discovery_digit.digit = pgm_read_byte (& (table [row] [col])) ؛ كشف_digit.index = pgm_read_byte (& (char_indexes [row] [col])) ؛ } else {discovery_digit.digit = 0 ؛ }}
drawSprite باطل (بايت * sprite) {
// يتم استخدام القناع للحصول على بت العمود من قناع بايت صف العفريت = B10000000 ؛ لـ (int iy = 0؛ iy <8؛ iy ++) {لـ (int ix = 0؛ ix <8؛ ix ++) {lmd.setPixel (7 - iy، ix، (bool) (sprite [iy] & mask)) ؛
// انقل القناع بمقدار بكسل واحد إلى اليمين
قناع = قناع >> 1 ؛ }
// إعادة تعيين قناع العمود
قناع = B10000000 ؛ }}
الإعداد باطل() {
cli () ؛ initADC () ، سي () ؛
Serial.begin (115200) ؛
lmd.setEnabled (صحيح) ، lmd.set كثافة (2) ؛ lmd.clear () ، lmd.display () ،
Detective_digit.digit = 0 ؛
}
طويل بدون توقيع z = 0 ؛
حلقة فارغة() {
بينما (ADCSRA & _BV (ADIE)) ؛ // انتظر حتى ينتهي أخذ العينات الصوتية من goertzel (العينات ، الطيف) ؛ كشف الرقم (الطيف) ؛
إذا (اكتشفت_digit.digit! = 0) {
drawSprite (الخط [المكتشف_digit.index]) ؛ lmd.display () ، } if (z٪ 5 == 0) {for (int i = 0؛ i <IX_LEN؛ i ++) {Serial.print (range ) ؛ Serial.print ("\ t") ؛ } Serial.println () ، Serial.println ((int) detect_digit.digit) ؛ } z ++ ؛
samplePos = 0 ؛
ADCSRA | = _BV (ADIE) ، // استئناف مقاطعة أخذ العينات
}
ISR (ADC_vect) {
عينة uint16_t = ADC ؛
عينات [samplePos ++] = عينة - 400 ؛
إذا (samplePos> = N) {ADCSRA & = ~ _BV (ADIE) ؛ // المخزن المؤقت ممتلئ ، المقاطعة متوقفة}}
الخطوة 3: المخططات
يجب عمل التوصيلات التالية:
ميكروفون لاردوينو
خارج -> A0
Vcc -> 3.3V Gnd -> Gnd
من المهم توصيل AREF بـ 3.3V
عرض لاردوينو
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
الخطوة 4: الخاتمة
ما الذي يمكن تحسينه هنا؟ لقد استخدمت N = 256 عينة بمعدل 9615 هرتز الذي يحتوي على بعض تسرب الطيف ، إذا كان N = 205 ومعدل 8000 هرتز ، فإن الترددات المرغوبة تتطابق مع شبكة التقدير. لذلك يجب استخدام ADC في وضع تجاوز سعة المؤقت.
موصى به:
Raspberry Pi - TMD26721 كاشف القرب الرقمي بالأشعة تحت الحمراء برنامج Java التعليمي: 4 خطوات
Raspberry Pi - TMD26721 كاشف القرب الرقمي بالأشعة تحت الحمراء Java Tutorial: TMD26721 عبارة عن كاشف تقارب رقمي يعمل بالأشعة تحت الحمراء يوفر نظامًا كاملاً للكشف عن القرب ومنطق واجهة رقمية في وحدة تثبيت سطحية واحدة مكونة من 8 سنون. صحة. محترف
كاشف مستوى الماء: 7 خطوات
كاشف مستوى الماء: يعمل المستشعر بالموجات فوق الصوتية على نفس مبادئ نظام الرادار. يمكن لجهاز الاستشعار بالموجات فوق الصوتية تحويل الطاقة الكهربائية إلى موجات صوتية والعكس صحيح. يولد مستشعر الموجات فوق الصوتية HC SR04 الشهير موجات فوق صوتية بتردد 40 كيلو هرتز
كاشف وجود سرير Zigbee: 8 خطوات
Zigbee Bed Presence Detector: لبعض الوقت الآن كنت أبحث عن طريقة لاكتشاف عندما نكون في السرير. هذا لاستخدام هذه المعلومات في Homeassistant. باستخدام هذه المعلومات ، يمكنني عمل أتمتة لإطفاء الأنوار ليلاً أو على سبيل المثال تنشيط نظام إنذار في منزلي
كاشف الاهتزاز الحالي: 3 خطوات
جهاز كشف الاهتزاز الحالي: في هذا المشروع ، سنصنع جهازًا سيطلق إنذارًا إذا قام شخص ما بهز هدية / صندوق. خطرت لي هذه الفكرة عندما حصلنا على طرد بالبريد لعيد الميلاد. لمحاولة تخمين ما كان بداخلها ، بالطبع هزناها تمامًا كما يفعل الجميع
كاشف الدخان IOT: تحديث كاشف الدخان الموجود باستخدام IOT: 6 خطوات (بالصور)
كاشف الدخان IOT: تحديث كاشف الدخان الموجود باستخدام IOT: قائمة المساهمين ، المخترع: Tan Siew Chin ، Tan Yit Peng ، Tan Wee Heng المشرف: الدكتور Chia Kim Seng ، قسم الهندسة الميكاترونية والروبوتية ، كلية الهندسة الكهربائية والإلكترونية ، Universiti Tun حسين اون ماليزيا توزيع