Mündəricat:
Video: DTMF Detektoru: 4 addım
2024 Müəllif: John Day | [email protected]. Son dəyişdirildi: 2024-01-30 07:46
Baxış
Rəqəmsal Siqnal İşləmə onlayn kursunda ev tapşırığı ilə bu cihazı qurmağımdan ilham aldım. Bu, Arduino UNO ilə tətbiq olunan bir DTMF dekoderidir, istehsal etdiyi səslə ton rejimində telefon klaviaturasında basılan bir rəqəmi algılar.
Addım 1: Alqoritmi anlayın
DTMF -də hər bir simvol şəkildəki cədvələ uyğun olaraq iki tezliklə kodlanır.
Cihaz mikrofondan daxil olan məlumatları tutur və səkkiz tezliyin amplitüdünü hesablayır. Maksimum amplitüdlü iki tezlik kodlanmış simvolun bir sətirini və sütunu verir.
Məlumat əldə etmə
Spektr analizini aparmaq üçün nümunələr müəyyən bir proqnozlaşdırılan tezlikdə alınmalıdır. Buna nail olmaq üçün maksimum dəqiqliklə sərbəst işləyən ADC rejimindən istifadə etdim (prescaler 128) 9615Hz nümunə götürmə sürətini verir. Aşağıdakı kod Arduino ADC -nin necə qurulacağını göstərir.
etibarsız initADC () {
// ADC -ni işə salın; f = (16MHz/prescaler)/13 dövr/dönüşüm ADMUX = 0; // Kanal sel, sağ-adj, AREF pin ADCSRA = _BV (ADEN) istifadə edin | // ADC _BV (ADSC) imkan verir | // ADC start _BV (ADATE) | // Avtomatik tetikleyici _BV (ADIE) | // Ara ver _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Sərbəst iş rejimi DIDR0 = _BV (0); // ADC pin TIMSK0 = 0 üçün rəqəmsal girişi söndürün; // Timer0 off} Və kəsmə işləyicisi bu ISR (ADC_vect) kimi görünür {uint16_t sample = ADC; nümunələr [samplePos ++] = nümunə - 400; əgər (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Tampon doludur, ara ver}}
Spektr analizi
Nümunələr topladıqdan sonra simvolları kodlayan 8 tezliyin amplitüdlərini hesablayıram. Bunun üçün tam FFT işləməyimə ehtiyac yoxdur, buna görə Goertzel alqoritmindən istifadə etdim.
void goertzel (uint8_t *nümunələri, float *spektri) {
float 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])); üzmək a = 2. * c; v_0 = v_1 = v_2 = 0; üçün (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (nümunələr ) + a * v_1 - v_0; } yenidən = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektr [k] = amp; }}
Addım 2: Kod
Yuxarıdakı şəkil, maksimum amplitüdünün 697Hz və 1477Hz tezliklərinə uyğun olduğu 3 rəqəminin kodlaşdırılması nümunəsini göstərir.
Tam eskiz aşağıdakı kimi görünür
/** * Əlaqələr: * [Mikrofondan Arduinoya] * - Çıxış -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Arduinoya Göstər] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include
#daxil edin
#CS_PIN 9 təyin edin
#təyin N 256
#dexine IX_LEN 8 #DEĞİŞDİR HƏSLİ 20
LEDMatrixDriver lmd (1, CS_PIN);
uint8_t nümunələri [N];
uçucu uint16_t samplePos = 0;
üzmə spektri [IX_LEN];
// Tezliklər [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]
// 9615Hz 256 nümunə const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370639623623666666666666666666666666666666666666666666686, 0.3636 const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.7730104533627369, 0.7730104533627369
typedef quruluşu {
char rəqəmi; uint8_t indeksi; } rəqəm_t;
rəqəm_t aşkar_digit;
const char cədvəli [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} };
bayt şrift [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} // *};
etibarsız initADC () {
// ADC -ni işə salın; f = (16MHz/prescaler)/13 dövr/dönüşüm ADMUX = 0; // Kanal sel, sağ-adj, AREF pin ADCSRA = _BV (ADEN) istifadə edin | // ADC _BV (ADSC) imkan verir | // ADC start _BV (ADATE) | // Avtomatik tetikleyici _BV (ADIE) | // Ara ver _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Sərbəst iş rejimi DIDR0 = _BV (0); // ADC pin TIMSK0 = 0 üçün rəqəmsal girişi söndürün; // Taymer 0 söndür}
void goertzel (uint8_t *nümunələri, float *spektri) {
float 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])); üzmək a = 2. * c; v_0 = v_1 = v_2 = 0; üçün (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (nümunələr ) + a * v_1 - v_0; } yenidən = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektr [k] = amp; }}
float ort (float *a, uint16_t len) {
float nəticə =.0; for (uint16_t i = 0; i <len; i ++) {nəticə+= a ; } nəticə / len qaytar; }
int8_t get_single_index_above_threshold (float *a, uint16_t len, float eşik) {
if (eşik <THRESHOLD) {qaytar -1; } int8_t ix = -1; for (uint16_t i = 0; i eşik) {if (ix == -1) {ix = i; } başqa {qaytar -1; }}} ix ix; }
void detect_digit (float *spektri) {
float avg_row = ort (spektr, 4); float avg_col = ort ((spektr [4], 4); int8_t sıra = get_single_index_above_threshold (spektr, 4, ort_sayısı); int8_t col = get_single_index_above_threshold (& spektr [4], 4, avg_col); əgər (satır! = -1 && col! = -1 && avg_col> 200) {found_digit.digit = pgm_read_byte (& (table [row] [col])); aşkar_digit.index = pgm_read_byte (& (char_indexes [satır] [col])); } başqa {aşkar_digit.digit = 0; }}
void drawSprite (bayt* sprite) {
// Maska, sprite satır bayt maskasından sütun bitini almaq üçün istifadə olunur = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));
// maskanı bir piksel sağa sürüşdürün
maska = maska >> 1; }
// sütun maskasını sıfırlayın
maska = B10000000; }}
boş quraşdırma () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (doğru); lmd.setIntensity (2); lmd.clear (); lmd.display ();
aşkar_digit.digit = 0;
}
işarəsiz uzun z = 0;
boşluq döngəsi () {
isə (ADCSRA & _BV (ADIE)); // Səs nümunəsinin goertzel bitməsini gözləyin (nümunələr, spektr); Detect_digit (spektr);
əgər (aşkar_digit.digit! = 0) {
drawSprite (şrift [aşkar_digit.index]); lmd.display (); } if (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (spektr ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) detect_digit.digit); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Nümunə kəsilməsini davam etdirin
}
ISR (ADC_vect) {
uint16_t nümunəsi = ADC;
nümunələr [samplePos ++] = nümunə - 400;
əgər (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Tampon doludur, ara ver}}
Addım 3: sxemlər
Aşağıdakı əlaqələr qurulmalıdır:
Arduino üçün mikrofon
Çıxış -> A0
Vcc -> 3.3V Gnd -> Gnd
AREF -in 3.3V -ə qoşulması vacibdir
Arduinoya göstərin
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Addım 4: Nəticə
Burada nəyi yaxşılaşdırmaq olar? Bəzi spektr sızıntısı olan 9615Hz nisbətində N = 256 nümunələri istifadə etdim, əgər N = 205 və dərəcəsi 8000Hz olarsa, istənilən tezliklər diskretasiya şəbəkəsi ilə üst -üstə düşür. Bunun üçün ADC taymer daşma rejimində istifadə edilməlidir.
Tövsiyə:
Su səviyyəsi detektoru: 7 addım
Su Səviyyə Dedektoru: Ultrasonik sensor bir radar sistemi ilə eyni prinsiplər üzərində işləyir. Ultrasonik sensor elektrik enerjisini akustik dalğalara və əksinə çevirə bilər. Məşhur HC SR04 ultrasəs sensoru 40 kHz tezlikdə ultrasəs dalğaları yaradır
Duman Detektoru: 13 addım
Tüstü Dedektörü: Salam dostlar bu gün tüstü detektoru ilə tanış olaq Bir çoxunuz alış -veriş mərkəzlərində ticarət mərkəzlərinə getmisiniz, əsasən tüstü detektoru adlanan bu cihazı görürsünüz, tüstünü aşkar edəcək və çiləyicini işə salacaq və yanğını dayandıracaq. əvəzinə
Simsiz AC Cərəyan Detektoru: 7 Addım (Şəkillərlə birlikdə)
Simsiz AC Cərəyan Detektoru: Əvvəlki Təlimatlandırıcımı (asan infraqırmızı yaxınlıq sensoru) hazırlayarkən, çox zəif bir siqnalı gücləndirmək üçün ardıcıl olaraq 2 tranzistordan istifadə etməklə bağlı bir neçə şeyi anladım. Bu Təlimat kitabında & quo adlanan bu prinsipi daha ətraflı izah edəcəyəm
Arduino Açıq Pəncərə Detektoru - Qış üçün: 6 addım
Arduino Açıq Pəncərə Detektoru - Qış üçün: Çöldə soyuq olur, amma bəzən otaqlarımda təmiz havaya ehtiyacım var. Beləliklə, pəncərəni açıram, otaqdan çıxıram, qapını bağlayıram və 5-10 dəqiqəyə qayıtmaq istəyirəm. Və bir neçə saatdan sonra pəncərənin açıq olduğunu xatırlayıram … Bəlkə də bilirsən
Cib Ölçülü Öskürək Detektoru: 7 addım
Cib Ölçəkli Öskürək Detektoru: COVID19 həqiqətən də bütün dünyanı çox pis təsir edən tarixi bir pandemiyadır və insanlar onunla mübarizə aparmaq üçün bir çox yeni cihaz qurur. Əlaqəsiz temperatur taraması üçün avtomatik bir dezinfeksiya maşını və Termal Tabanca da qurduq. Tod