สารบัญ:
วีดีโอ: ตัวตรวจจับ DTMF: 4 ขั้นตอน
2024 ผู้เขียน: John Day | [email protected]. แก้ไขล่าสุด: 2024-01-30 13:06
ภาพรวม
ฉันได้รับแรงบันดาลใจในการสร้างอุปกรณ์นี้จากการบ้านในหลักสูตรออนไลน์เกี่ยวกับการประมวลผลสัญญาณดิจิทัล นี่คือตัวถอดรหัส DTMF ที่ใช้งานกับ Arduino UNO โดยจะตรวจจับตัวเลขที่กดบนแป้นกดของโทรศัพท์ในโหมดโทนโดยเสียงที่สร้าง
ขั้นตอนที่ 1: ทำความเข้าใจอัลกอริทึม
ใน DTMF แต่ละสัญลักษณ์จะถูกเข้ารหัสด้วยความถี่สองความถี่ตามตารางในภาพ
อุปกรณ์จับอินพุตจากไมโครโฟนและคำนวณแอมพลิจูดแปดความถี่ สองความถี่ที่มีแอมพลิจูดสูงสุดให้แถวและคอลัมน์ของสัญลักษณ์ที่เข้ารหัส
การเก็บข้อมูล
เพื่อที่จะทำการวิเคราะห์สเปกตรัม ตัวอย่างควรถูกจับที่ความถี่ที่คาดการณ์ได้ เพื่อให้บรรลุสิ่งนี้ ฉันใช้โหมด ADC แบบรันฟรีพร้อมความแม่นยำสูงสุด (พรีสเกลเลอร์ 128) ซึ่งให้อัตราการสุ่มตัวอย่าง 9615Hz รหัสด้านล่างแสดงวิธีกำหนดค่า ADC ของ Arduino
เป็นโมฆะ initADC () {
// เริ่ม ADC; f = (16MHz/พรีสเกลเลอร์) / 13 รอบ/การแปลง ADMUX = 0; // Channel sel, right-adj, ใช้พิน AREF 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 TIMSK0 = 0; // Timer0 off } และตัวจัดการขัดจังหวะดูเหมือนว่า ISR (ADC_vect) { uint16_t sample = ADC;samples [samplePos++] = ตัวอย่าง - 400; ถ้า (samplePos >= N) { ADCSRA &= ~_BV (ADIE); // บัฟเฟอร์เต็ม ขัดจังหวะปิด } }
การวิเคราะห์สเปกตรัม
หลังจากรวบรวมตัวอย่าง ฉันจะคำนวณแอมพลิจูดของ 8 สัญลักษณ์การเข้ารหัสความถี่ ฉันไม่ต้องการใช้ FFT เต็มรูปแบบสำหรับสิ่งนี้ ดังนั้นฉันจึงใช้อัลกอริทึมของ Goertzel
เป็นโมฆะ goertzel (uint8_t * ตัวอย่าง, ลอย * สเปกตรัม) {
ลอย v_0, v_1, v_2; ลอยใหม่ im แอมป์; สำหรับ (uint8_t k = 0; k < IX_LEN; k++) { float c = pgm_read_float(&(cos_t[k])); float s = pgm_read_float(&(sin_t[k])); ลอย a = 2. * c; 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; amp = sqrt(re * re + im * im); สเปกตรัม[k] = แอมป์; } }
ขั้นตอนที่ 2: รหัส
ภาพด้านบนแสดงตัวอย่างการเข้ารหัสตัวเลข 3 ซึ่งแอมพลิจูดสูงสุดสอดคล้องกับความถี่ 697Hz และ 1477Hz
ร่างที่สมบูรณ์มีลักษณะดังนี้
/** * การเชื่อมต่อ: * [ไมค์กับ Arduino] * - ออก -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [แสดงผลไปยัง Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include
#รวม
#define CS_PIN 9
#define N 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]
// คำนวณจาก 9615Hz 256 ตัวอย่าง const float cos_t[IX_LEN] PROGMEM = { 0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.6343932841636456, 0.55557023673096023, 250.47199; const float sin_t [IX_LEN] PROGMEM = { 0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025451, 0.8819212643483549 };
โครงสร้าง typedef {
ตัวเลขถ่าน; ดัชนี uint8_t; } digit_t;
digit_t ตรวจพบ_digit;
ตารางอักขระ const [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}, // A {0x00, 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x7c}, / / 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 = (16MHz/พรีสเกลเลอร์) / 13 รอบ/การแปลง ADMUX = 0; // Channel sel, right-adj, ใช้พิน AREF 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 TIMSK0 = 0; // ปิดตัวจับเวลา0 }
โมฆะ goertzel (uint8_t * ตัวอย่าง, ลอย * สเปกตรัม) {
ลอย v_0, v_1, v_2; ลอยใหม่ im แอมป์; สำหรับ (uint8_t k = 0; k < IX_LEN; k++) { float c = pgm_read_float(&(cos_t[k])); float s = pgm_read_float(&(sin_t[k])); ลอย a = 2. * c; 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; amp = sqrt(re * re + im * im); สเปกตรัม[k] = แอมป์; } }
float เฉลี่ย (float *a, uint16_t len) {
ผลลอย =.0; สำหรับ (uint16_t i = 0; i < len; i++) { ผลลัพธ์ += a; } ส่งคืนผลลัพธ์ / len; }
int8_t get_single_index_above_threshold (float *a, uint16_t len, เกณฑ์การลอย) {
ถ้า (เกณฑ์ < THRESHOLD) { กลับ -1; } int8_t ix = -1; สำหรับ (uint16_t i = 0; i เกณฑ์) { if (ix == -1) { ix = i; } อื่น ๆ { กลับ -1; } } } ส่งคืน ix; }
เป็นโมฆะ detect_digit (ลอย * สเปกตรัม) {
float avg_row = เฉลี่ย (สเปกตรัม 4); float avg_col = avg(&สเปกตรัม[4], 4); int8_t แถว = get_single_index_above_threshold (สเปกตรัม, 4, avg_row); int8_t col = get_single_index_above_threshold(&สเปกตรัม[4], 4, avg_col); if (แถว != -1 && col != -1 && avg_col > 200) { ตรวจพบ_digit.digit = pgm_read_byte(&(table[row][col])); ตรวจพบ_digit.index = pgm_read_byte(&(char_indexes[row][col])); } อื่น ๆ { ตรวจพบ_digit.digit = 0; } }
เป็นโมฆะ drawSprite (ไบต์ * สไปรท์) {
// หน้ากากใช้เพื่อรับบิตคอลัมน์จากมาสก์แถวสไปรท์ = 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.setIntensity(2); lmd.clear(); lmd.display();
ตรวจพบ_digit.digit = 0;
}
ยาวที่ไม่ได้ลงนาม z = 0;
วงเป็นโมฆะ () {
ในขณะที่(ADCSRA & _BV(ADIE)); // รอให้การสุ่มตัวอย่างเสียงเสร็จสิ้น goertzel (ตัวอย่าง, สเปกตรัม); detect_digit(สเปกตรัม);
ถ้า (detected_digit.digit != 0) {
drawSprite(ฟอนต์[detected_digit.index]); lmd.display(); } ถ้า (z % 5 == 0) { สำหรับ (int i = 0; i < IX_LEN; i++) { Serial.print(spectrum ); Serial.print("\t"); } Serial.println(); Serial.println((int)detected_digit.digit); } z++;
ตัวอย่างPos = 0;
ADCSRA |= _BV(ADIE); // หยุดการสุ่มตัวอย่างต่อ
}
ISR (ADC_vect) {
ตัวอย่าง uint16_t = ADC;
ตัวอย่าง[samplePos++] = ตัวอย่าง - 400;
ถ้า (samplePos >= N) { ADCSRA &= ~_BV (ADIE); // บัฟเฟอร์เต็ม ขัดจังหวะปิด } }
ขั้นตอนที่ 3: แผนผัง
ควรทำการเชื่อมต่อต่อไปนี้:
ไมค์ไปยัง Arduino
ออก -> A0
Vcc -> 3.3V Gnd -> Gnd
การเชื่อมต่อ AREF กับ 3.3V เป็นสิ่งสำคัญ
แสดงผลไปยัง Arduino
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
ขั้นตอนที่ 4: บทสรุป
สิ่งที่สามารถปรับปรุงได้ที่นี่? ฉันใช้ตัวอย่าง N = 256 ที่อัตรา 9615Hz ซึ่งมีคลื่นความถี่รั่ว ถ้า N = 205 และอัตราคือ 8000Hz แสดงว่าความถี่ที่ต้องการจะตรงกับกริดการแยกส่วน สำหรับ ADC นั้นควรใช้ในโหมดโอเวอร์โฟลว์ตัวจับเวลา
แนะนำ:
DTMF สตรีมมิงวิดีโอโรเวอร์: 3 ขั้นตอน
DTMF VIDEO STREAMING ROVER: สวัสดี หลังจาก LINUX TERMINAL CONTROLLED ROVER และ WIFI DTMF PC CONTROLLED ROBOT ของฉัน นี่คือหุ่นยนต์ตัวที่สามของฉัน และเช่นเดียวกับอีกสองตัวที่นี่ ฉันไม่ได้ใช้ไมโครคอนโทรลเลอร์หรือโปรแกรมใดๆ เพื่อให้ง่ายและสะดวกในการสร้าง นอกจากนี้ยังสตรีมวิดีโอสดผ่าน wifi
วิธีสร้างตัวถอดรหัสสายโทรศัพท์ DTMF (โทน) อย่างง่าย: 3 ขั้นตอน
วิธีการสร้างตัวถอดรหัสสายโทรศัพท์ DTMF (โทน) อย่างง่าย: นี่เป็นโครงการง่ายๆ ที่ให้คุณถอดรหัสสัญญาณ DTMF บนสายโทรศัพท์ใดก็ได้ ในบทช่วยสอนนี้ เรากำลังใช้ตัวถอดรหัส MT8870D เราใช้ตัวถอดรหัสเสียงที่สร้างไว้ล่วงหน้าเพราะเชื่อฉันเถอะว่าการลองทำกับ
WIFI DTMF ROBOT: 5 ขั้นตอน
WIFI DTMF ROBOT: สวัสดีในบทช่วยสอนนี้ ฉันจะแสดงให้คุณเห็นว่าคุณสามารถสร้างรถแลนด์โรเวอร์ที่ควบคุมด้วยพีซีได้อย่างไรโดยไม่ต้องใช้ไมโครคอนโทรลเลอร์ ซึ่งหมายความว่าในโครงการนี้ไม่มีโค้ดระดับสูงที่เกี่ยวข้อง คุณเพียงแค่ต้องมีความรู้พื้นฐานเกี่ยวกับหน้า html เท่านั้น สามารถรับชมเต็มๆ
วิธีทำหุ่นยนต์ควบคุมด้วยมือถือ - ตาม DTMF - ไม่มีไมโครคอนโทรลเลอร์ & การเขียนโปรแกรม - ควบคุมได้จากทุกที่ในโลก - RoboGeeks: 15 ขั้นตอน
วิธีทำหุ่นยนต์ควบคุมด้วยมือถือ | ตาม DTMF | ไม่มีไมโครคอนโทรลเลอร์ & การเขียนโปรแกรม | ควบคุมได้จากทุกที่ในโลก | RoboGeeks: อยากสร้างหุ่นยนต์ที่ควบคุมได้จากทุกที่ในโลก ลงมือทำเลย
DTMF และรถเข็นหุ่นยนต์ควบคุมด้วยท่าทาง: 7 ขั้นตอน (พร้อมรูปภาพ)
DTMF และรถเข็นหุ่นยนต์ควบคุมด้วยท่าทาง: ในโลกนี้มีคนพิการจำนวนมาก ชีวิตของพวกเขาหมุนรอบล้อ โครงงานนี้นำเสนอแนวทางในการควบคุมการเคลื่อนตัวของรถเข็นคนพิการโดยใช้การจดจำท่าทางของมือและ DTMF ของสมาร์ทโฟน