Daftar Isi:
Video: Detektor DTMF: 4 Langkah
2024 Pengarang: John Day | [email protected]. Terakhir diubah: 2024-01-30 09:56
Gambaran
Saya terinspirasi untuk membangun perangkat ini dengan tugas rumah pada kursus online Digital Signal Processing. Ini adalah dekoder DTMF yang diimplementasikan dengan Arduino UNO, mendeteksi digit yang ditekan pada keypad telepon dalam mode nada dengan suara yang dihasilkannya.
Langkah 1: Memahami Algoritma
Dalam DTMF setiap simbol dikodekan dengan dua frekuensi sesuai tabel pada gambar.
Perangkat menangkap input dari mikrofon dan menghitung amplitudo delapan frekuensi. Dua frekuensi dengan amplitudo maksimum memberikan baris dan kolom dari simbol yang dikodekan.
akuisisi data
Untuk melakukan analisis spektrum, sampel harus ditangkap pada frekuensi tertentu yang dapat diprediksi. Untuk mencapai ini, saya menggunakan mode ADC free-run dengan presisi maksimum (prescaler 128) yang memberikan laju sampling 9615Hz. Kode di bawah ini menunjukkan cara mengkonfigurasi ADC Arduino.
batalkan initADC() {
// Inisi ADC; f = (16MHz/prascaler) / 13 siklus/konversi ADMUX = 0; // Channel sel, adj kanan, gunakan pin AREF ADCSRA = _BV(ADEN) | // ADC mengaktifkan _BV(ADSC) | // ADC mulai _BV(ADATE) | // Pemicu otomatis _BV(ADIE) | // Interupsi aktifkan _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128:1 / 13 = 9615 Hz ADCSRB = 0; // Mode lari bebas DIDR0 = _BV(0); // Matikan input digital untuk pin ADC TIMSK0 = 0; // Timer0 off } Dan pengendali interupsi terlihat seperti ini ISR(ADC_vect) { uint16_t sample = ADC;samples[samplePos++] = sample - 400; if(samplePos >= N) { ADCSRA &= ~_BV(ADIE); // Buffer penuh, interupsi mati } }
Analisis spektrum
Setelah mengumpulkan sampel, saya menghitung amplitudo dari 8 simbol pengkodean frekuensi. Saya tidak perlu menjalankan FFT penuh untuk ini, jadi saya menggunakan algoritma Goertzel.
void goertzel(uint8_t *sampel, float *spektrum) {
mengambang v_0, v_1, v_2; float re, im, amp; for (uint8_t k = 0; k < IX_LEN; k++) { float c = pgm_read_float(&(cos_t[k])); float s = pgm_read_float(&(sin_t[k])); mengapung a = 2. * c; v_0 = v_1 = v_2 = 0; for (uint16_t i = 0; i < N; i++) { v_0 = v_1; v_1 = v_2; v_2 = (mengambang)(sampel) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = kuadrat(re * re + im * im); spektrum[k] = amp; } }
Langkah 2: Kode
Gambar di atas menunjukkan contoh pengkodean digit 3 di mana amplitudo maksimum sesuai dengan frekuensi 697Hz dan 1477Hz.
Sketsa lengkapnya terlihat sebagai berikut:
/** * Koneksi: * [Mikrofon ke Arduino] * - Keluar -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Tampilan ke Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include
#termasuk
#tentukan CS_PIN 9
#tentukan N 256
#define IX_LEN 8 #define THRESHOLD 20
LEDMatrixDriver lmd(1, CS_PIN);
uint8_t sampel[N];
volatil uint16_t samplePos = 0;
spektrum float[IX_LEN];
// Frekuensi [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]
// Dihitung untuk 9615Hz 256 sampel const float cos_t[IX_LEN] PROGMEM = { 0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.6343932841636456, 0.55557.023301960}; const float sin_t[IX_LEN] PROGMEM = { 0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025451, 0.88491921};
struktur typedef {
angka karakter; indeks uint8_t; } angka_t;
digit_t terdeteksi_digit;
tabel const char[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} };
byte font[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} // * };
batalkan initADC() {
// Inisi ADC; f = (16MHz/prascaler) / 13 siklus/konversi ADMUX = 0; // Channel sel, adj kanan, gunakan pin AREF ADCSRA = _BV(ADEN) | // ADC mengaktifkan _BV(ADSC) | // ADC mulai _BV(ADATE) | // Pemicu otomatis _BV(ADIE) | // Interupsi aktifkan _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // 128:1 / 13 = 9615 Hz ADCSRB = 0; // Mode lari bebas DIDR0 = _BV(0); // Matikan input digital untuk pin ADC TIMSK0 = 0; // Timer0 mati }
void goertzel(uint8_t *sampel, float *spektrum) {
mengambang v_0, v_1, v_2; float re, im, amp; for (uint8_t k = 0; k < IX_LEN; k++) { float c = pgm_read_float(&(cos_t[k])); float s = pgm_read_float(&(sin_t[k])); mengapung a = 2. * c; v_0 = v_1 = v_2 = 0; for (uint16_t i = 0; i < N; i++) { v_0 = v_1; v_1 = v_2; v_2 = (mengambang)(sampel) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = kuadrat(re * re + im * im); spektrum[k] = amp; } }
float rata-rata(float *a, uint16_t len) {
hasil float =.0; for (uint16_t i = 0; i < len; i++) { hasil += a; } mengembalikan hasil / len; }
int8_t get_single_index_above_threshold(float *a, uint16_t len, float threshold) {
if (ambang < THRESHOLD) { kembali -1; } int8_t ix = -1; for (uint16_t i = 0; i threshold) { if (ix == -1) { ix = i; } else { kembali -1; } } } kembali ix; }
void detect_digit(float *spektrum) {
float avg_row = avg(spektrum, 4); float avg_col = avg(&spektrum[4], 4); int8_t baris = get_single_index_above_threshold(spektrum, 4, avg_row); int8_t col = get_single_index_above_threshold(&spektrum[4], 4, avg_col); if (baris != -1 && col != -1 && avg_col > 200) { terdeteksi_digit.digit = pgm_read_byte(&(tabel[baris][kol])); terdeteksi_digit.index = pgm_read_byte(&(char_indexes[baris][kol])); } else { terdeteksi_digit.digit = 0; } }
void drawSprite(byte* sprite) {
// Mask digunakan untuk mendapatkan bit kolom dari baris sprite byte mask = B10000000; for(int iy = 0; iy < 8; iy++) { for(int ix = 0; ix < 8; ix++) { lmd.setPixel(7 - iy, ix, (bool)(sprite[iy] & mask));
// geser topeng satu piksel ke kanan
topeng = topeng >> 1; }
// setel ulang topeng kolom
topeng = B10000000; } }
batalkan pengaturan() {
kli(); initADC(); sei();
Serial.begin(115200);
lmd.setEnabled(benar); lmd.setIntensity(2); lmd.clear(); lmd.display();
terdeteksi_digit.digit = 0;
}
unsigned panjang z = 0;
lingkaran kosong() {
while(ADCSRA & _BV(ADIE)); // Tunggu pengambilan sampel audio selesai goertzel(sampel, spektrum); deteksi_digit(spektrum);
if (terdeteksi_digit.digit != 0) {
drawSprite(font[terdeteksi_digit.index]); lmd.display(); } if (z % 5 == 0) { for (int i = 0; i < IX_LEN; i++) { Serial.print(spectrum); Serial.print("\t"); } Serial.println(); Serial.println((int)detected_digit.digit); } z++;
sampelPos = 0;
ADCSRA |= _BV(ADIE); // Lanjutkan interupsi pengambilan sampel
}
ISR(ADC_vect) {
uint16_t sampel = ADC;
sampel[samplePos++] = sampel - 400;
if(samplePos >= N) { ADCSRA &= ~_BV(ADIE); // Buffer penuh, interupsi mati } }
Langkah 3: Skema
Koneksi berikut harus dibuat:
Mikrofon ke Arduino
Keluar -> A0
Vcc -> 3.3V Gnd -> Gnd
Penting untuk menghubungkan AREF ke 3.3V
Tampilan ke Arduino
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Langkah 4: Kesimpulan
Apa yang bisa diperbaiki di sini? Saya menggunakan N = 256 sampel pada laju 9615Hz yang memiliki beberapa kebocoran spektrum, jika N = 205 dan laju adalah 8000Hz maka frekuensi yang diinginkan bertepatan dengan kisi diskritisasi. Untuk itu ADC sebaiknya digunakan dalam mode timer overflow.
Direkomendasikan:
ROVER STREAMING VIDEO DTMF: 3 Langkah
DTMF VIDEO STREAMING ROVER: hai setelah LINUX TERMINAL CONTROLLED ROVER dan WIFI DTMF PC CONTROLLED ROBOT saya, ini adalah robot ketiga saya. dan seperti dua lainnya di sini juga saya tidak menggunakan mikrokontroler atau pemrograman apa pun untuk membuatnya tetap sederhana dan mudah. Ini juga mengalirkan video langsung melalui wifi
Cara Membuat Decoder Saluran Telepon DTMF (nada) Sederhana: 3 Langkah
Cara Membuat Dekoder Saluran Telepon DTMF (nada) Sederhana: Ini adalah proyek sederhana yang memungkinkan Anda memecahkan kode sinyal DTMF pada dasarnya semua saluran telepon. Dalam tutorial ini, kami menggunakan decoder MT8870D. Kami menggunakan dekoder nada bawaan karena, percayalah, sulit untuk mencoba dan melakukannya dengan
ROBOT DTMF WIFI: 5 Langkah
WIFI DTMF ROBOT: hai dalam tutorial ini saya akan menunjukkan kepada Anda bagaimana Anda dapat membuat rover yang dikendalikan pc tanpa menggunakan pengontrol mikro, ini berarti dalam proyek ini tidak ada kode tingkat tinggi yang terlibat Anda hanya perlu pengetahuan dasar tentang pembuatan halaman html itu saja. bisa nonton full
Cara Membuat Robot Terkendali Seluler - Berbasis DTMF - Tanpa Mikrokontroler & Pemrograman - Kontrol Dari Mana Saja di Dunia - RoboGeeks: 15 Langkah
Cara Membuat Robot Terkendali Seluler | Berbasis DTMF | Tanpa Mikrokontroler & Pemrograman | Kontrol Dari Mana Saja di Dunia | RoboGeeks: Ingin membuat robot yang bisa dikendalikan dari mana saja di dunia, Ayo Lakukan
Detektor Asap IOT: Perbarui Detektor Asap yang Ada Dengan IOT: 6 Langkah (dengan Gambar)
Detektor Asap IOT: Perbarui Detektor Asap yang Ada Dengan IOT: Daftar kontributor,Penemu:Tan Siew Chin, Tan Yit Peng, Tan Wee Heng Pembimbing: Dr Chia Kim Seng Departemen Teknik Mekatronika dan Robotika, Fakultas Teknik Elektro dan Elektronik, Universiti Tun Hussein Onn Malaysia.Distribu