Isi kandungan:
Video: Pengesan DTMF: 4 Langkah
2024 Pengarang: John Day | [email protected]. Diubah suai terakhir: 2024-01-30 11:10
Gambaran keseluruhan
Saya mendapat inspirasi untuk membina peranti ini dengan tugasan rumah dalam kursus dalam talian Pemprosesan Isyarat Digital. Ini adalah penyahkod DTMF yang dilaksanakan dengan Arduino UNO, ia mengesan digit yang ditekan pada papan kekunci telefon dalam mod nada dengan suara yang dihasilkannya.
Langkah 1: Memahami Algoritma
Di DTMF setiap simbol dikodkan dengan dua frekuensi mengikut jadual pada gambar.
Peranti menangkap input dari mikrofon dan mengira amplitud lapan frekuensi. Dua frekuensi dengan amplitud maksimum memberikan baris dan lajur simbol yang dikodkan.
Perolehan data
Untuk melakukan analisis spektrum, sampel harus diambil pada frekuensi yang dapat diramalkan. Untuk mencapai ini, saya menggunakan mod ADC lari bebas dengan ketepatan maksimum (prescaler 128) ia memberikan kadar pensampelan 9615Hz. Kod di bawah menunjukkan cara mengkonfigurasi ADC Arduino.
batal initADC () {
// Init ADC; f = (16MHz / prescaler) / 13 kitaran / penukaran ADMUX = 0; // Sel sel, kanan, gunakan pin AREF ADCSRA = _BV (ADEN) | // ADC aktifkan _BV (ADSC) | // ADC bermula _BV (ADATE) | // Pencetus automatik _BV (ADIE) | // Selang aktifkan _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Mod jalan bebas DIDR0 = _BV (0); // Matikan input digital untuk pin ADC TIMSK0 = 0; // Timer0 off} Dan pengendali interrupt kelihatan seperti ISR ini (ADC_vect) {uint16_t sample = ADC; samples [samplePos ++] = sample - 400; jika (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Penampan penuh, gangguan dimatikan}}
Analisis spektrum
Setelah mengumpulkan sampel saya mengira amplitud 8 frekuensi simbol pengekodan. Saya tidak perlu menjalankan FFT sepenuhnya untuk ini, jadi saya menggunakan algoritma Goertzel.
batal goertzel (sampel uint8_t *, spektrum apungan *) {
terapung v_0, v_1, v_2; float re, im, amp; untuk (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); terapung s = pgm_read_float (& (sin_t [k])); apungan a = 2. * c; v_0 = v_1 = v_2 = 0; untuk (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (terapung) (sampel ) + a * v_1 - v_0; } semula = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektrum [k] = amp; }}
Langkah 2: Kodnya
Gambar di atas menunjukkan contoh pengekodan digit 3 di mana amplitud maksimum sepadan dengan frekuensi 697Hz dan 1477Hz.
Lakaran yang lengkap kelihatan seperti berikut
/ ** * Sambungan: * [Mic ke Arduino] * - Keluar -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Paparan ke Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 * / #include #include
#sertakan
#tentukan CS_PIN 9
#tentukan N 256
#define IX_LEN 8 #define THRESHOLD 20
LEDMatrixDriver lmd (1, CS_PIN);
uint8_t sampel [N];
uint16_t samplePos yang tidak menentu = 0;
spektrum terapung [IX_LEN];
// Kekerapan [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.63439328416366456258238358258 const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025121
typedef struktur {
digit char; indeks uint8_t; } digit_t;
digit_t dikesan_digit;
jadual 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} };
fon bait [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, 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} // *};
batal initADC () {
// Init ADC; f = (16MHz / prescaler) / 13 kitaran / penukaran ADMUX = 0; // Sel sel, kanan, gunakan pin AREF ADCSRA = _BV (ADEN) | // ADC aktifkan _BV (ADSC) | // ADC bermula _BV (ADATE) | // Pencetus automatik _BV (ADIE) | // Selang aktifkan _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Mod jalan bebas DIDR0 = _BV (0); // Matikan input digital untuk pin ADC TIMSK0 = 0; // Pemasa0 dimatikan}
batal goertzel (sampel uint8_t *, spektrum apungan *) {
terapung v_0, v_1, v_2; float re, im, amp; untuk (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); terapung s = pgm_read_float (& (sin_t [k])); apungan a = 2. * c; v_0 = v_1 = v_2 = 0; untuk (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (terapung) (sampel ) + a * v_1 - v_0; } semula = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektrum [k] = amp; }}
float avg (float * a, uint16_t len) {
hasil apungan =.0; untuk (uint16_t i = 0; i <len; i ++) {hasil + = a ; } keputusan pulangan / len; }
int8_t get_single_index_above_threshold (apungan * a, uint16_t len, ambang apungan) {
jika (ambang <THRESHOLD) {return -1; } int8_t ix = -1; untuk (uint16_t i = 0; i ambang) {if (ix == -1) {ix = i; } lain {return -1; }}} pulangkan ix; }
void detect_digit (float * spektrum) {
float avg_row = avg (spektrum, 4); terapung avg_col = avg (& spektrum [4], 4); int8_t row = get_single_index_above_threshold (spektrum, 4, avg_row); int8_t col = get_single_index_above_threshold (& spektrum [4], 4, avg_col); jika (baris! = -1 && col! = -1 && avg_col> 200) {dikesan_digit.digit = pgm_read_byte (& (jadual [baris] [col])); dikesan_digit.index = pgm_read_byte (& (char_indexes [baris] [col])); } lain {dikesan_digit.digit = 0; }}
kekosongan drawSprite (byte * sprite) {
// Topeng digunakan untuk mendapatkan bit lajur dari sprite baris byte mask = B10000000; untuk (int iy = 0; iy <8; iy ++) {untuk (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));
// alihkan topeng dengan satu piksel ke kanan
topeng = topeng >> 1; }
// tetapkan semula topeng lajur
topeng = B10000000; }}
batal persediaan () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (benar); lmd.setIntensity (2); lmd.clear (); lmd.display ();
dikesan_digit.digit = 0;
}
panjang tidak bertanda z = 0;
gelung kosong () {
sementara (ADCSRA & _BV (ADIE)); // Tunggu persampelan audio untuk menyelesaikan goertzel (sampel, spektrum); mengesan_digit (spektrum);
jika (dikesan_digit.digit! = 0) {
drawSprite (fon [dikesan_digit.index]); lmd.display (); } jika (z% 5 == 0) {untuk (int i = 0; i <IX_LEN; i ++) {Serial.print (spektrum ); Serial.print ("\ t"); } Bersiri.println (); Serial.println ((int) dikesan_digit.digit); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Sambung semula sampel mengganggu
}
ISR (ADC_vect) {
uint16_t sample = ADC;
sampel [samplePos ++] = sampel - 400;
jika (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Penampan penuh, gangguan dimatikan}}
Langkah 3: Skematik
Sambungan berikut harus dibuat:
Mic ke Arduino
Keluar -> A0
Vcc -> 3.3V Gnd -> Gnd
Penting untuk menghubungkan AREF ke 3.3V
Paparan ke Arduino
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Langkah 4: Kesimpulannya
Apa yang boleh diperbaiki di sini? Saya menggunakan sampel N = 256 pada kadar 9615Hz yang mempunyai beberapa kebocoran spektrum, jika N = 205 dan kadarnya 8000Hz maka frekuensi yang diinginkan bertepatan dengan grid diskritisasi. Untuk itu ADC harus digunakan dalam mod overflow pemasa.
Disyorkan:
Pengesan Paras Air: 7 Langkah
Pengesan Tahap Air: Sensor ultrasonik berfungsi berdasarkan prinsip yang sama dengan sistem radar. Sensor ultrasonik dapat menukar tenaga elektrik menjadi gelombang akustik dan sebaliknya. Sensor ultrasonik HC SR04 yang terkenal menghasilkan gelombang ultrasonik pada frekuensi 40kHz.Jenis
Pengesan Kehadiran Tempat Tidur Zigbee: 8 Langkah
Zigbee Bed Presence Detector: Untuk beberapa waktu sekarang saya sedang mencari kaedah untuk mengesan ketika kita sedang tidur. Ini untuk menggunakan maklumat ini ke Homeassistant. Dengan maklumat ini saya dapat membuat automasi untuk mematikan lampu pada waktu malam atau misalnya mengaktifkan sistem penggera di
Pengesan Asap: 13 Langkah
Alat Pengesan Asap: Hai kawan-kawan hari ini mari kita lihat mengenai alat pengesan asap. Ramai di antara anda yang pergi ke pusat membeli-belah di pusat membeli-belah yang kebanyakannya anda dapat melihat alat yang dipanggil alat pengesan asap ini akan mengesan asap dan menghidupkan pemercik dan menghentikan kebakaran. Tetapi dalam projek ini, ini adalah sedikit perubahan sebaliknya
Cara Membuat Pengesan Jarak Sosial: 15 Langkah
Cara Membuat Pengesan Jarak Sosial: Dengan tahun 2020 yang akan berakhir, saya rasa senang untuk mengucapkan selamat tinggal dengan tutorial yang hampir sama pada tahun 2020. Saya beri anda, Pengesan Jarak Sosial. Dengan peranti ini, anda dapat melakukan jarak sosial dengan teknologi dan meninggalkan kebimbangan. T
Pengesan Asap IOT: Kemas kini Pengesan Asap yang Ada Dengan IOT: 6 Langkah (dengan Gambar)
Pengesan Asap IOT: Kemas kini Pengesan Asap yang Ada Dengan IOT: Senarai penyumbang, Pencipta: Tan Siew Chin, Tan Yit Peng, Tan Wee Heng Penyelia: Dr Chia Kim Seng Jabatan Kejuruteraan Mekatronik dan Robotik, Fakulti Kejuruteraan Elektrik dan Elektronik, Universiti Tun Hussein Onn Malaysia. Pengedar