Mündəricat:

DTMF Detektoru: 4 addım
DTMF Detektoru: 4 addım

Video: DTMF Detektoru: 4 addım

Video: DTMF Detektoru: 4 addım
Video: GSM/GPRS-модуль SIM800L (#4) - все о DTMF: парсинг, управление, безопасность 2024, Iyul
Anonim
Image
Image

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

Kod
Kod

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

Sxemalar
Sxemalar

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ə: