Мазмұны:

DTMF детекторы: 4 қадам
DTMF детекторы: 4 қадам

Бейне: DTMF детекторы: 4 қадам

Бейне: DTMF детекторы: 4 қадам
Бейне: GSM/GPRS-модуль SIM800L (#4) - все о DTMF: парсинг, управление, безопасность 2024, Қараша
Anonim
Image
Image

Шолу

Мен бұл құрылғыны цифрлық сигналды өңдеудің онлайн курсы бойынша үй тапсырмасынан шабыттандырдым. Бұл Arduino UNO көмегімен енгізілген DTMF декодері, ол дыбыс режимінде телефон пернетақтасында басылған санды анықтайды.

1 -қадам: Алгоритмді түсіну

Кодекс
Кодекс

DTMF -те әр белгі суреттегі кестеге сәйкес екі жиілікпен кодталған.

Құрылғы микрофоннан кірісті алады және сегіз жиіліктің амплитудасын есептейді. Максималды амплитудасы бар екі жиілік кодталған символдың жолын және бағанын береді.

Деректерді алу

Спектрлік талдауды жүргізу үшін белгілі бір жиілікте үлгілерді алу керек. Бұған қол жеткізу үшін мен ADC режимін максималды дәлдікпен қолдандым (128-прескалор), ол 9615 Гц іріктеу жиілігін береді. Төмендегі код Arduino ADC конфигурациясын көрсетеді.

жарамсыз initADC () {

// ADC қосу; f = (16MHz/prescaler)/13 цикл/ADMUX = 0 түрлендіру; // Channel sel, right-adj, AREF pin 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 өшірулі} Ал үзіліс өңдегіші келесідей көрінеді ISR (ADC_vect) {uint16_t sample = ADC; sample [samplePos ++] = үлгі - 400; if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Буфер толды, үзіліс өшірілді}}

Спектрлік талдау

Үлгілерді жинағаннан кейін мен таңбаларды кодтайтын 8 жиіліктің амплитудасын есептеймін. Бұл үшін толық FFT іске қосудың қажеті жоқ, сондықтан мен Гертцель алгоритмін қолдандым.

жарамсыз герцель (uint8_t *үлгілері, float *спектрі) {

өзгермелі v_0, v_1, v_2; float re, im, amp; үшін (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); float s = pgm_read_float (& (sin_t [k])); float 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 = (float) (үлгілер ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); спектр [k] = амп; }}

2 -қадам: Кодекс

Жоғарыдағы суретте максималды амплитудасы 697 Гц және 1477 Гц жиіліктеріне сәйкес келетін 3 -ші цифрды кодтау мысалы көрсетілген.

Толық эскиз келесідей көрінеді

/** * Қосылымдар: * [Mic to Arduino] * - Out -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Display to Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include

#қосу

#CS_PIN 9 анықтаңыз

#анықтаңыз N 256

#анықтау IX_LEN 8 #анықтау ШЕКТІ 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]

// 9615 Гц 256 сынамалар үшін есептеледі const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370639666666666666666666666666666666868 const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.7730104533627459

typedef құрылымы {

таңбалық сан; uint8_t индексі; } digit_t;

цифр_t анықталды_сандар;

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} };

байт қарпі [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/prescaler)/13 цикл/конверсия ADMUX = 0; // Channel sel, right-adj, AREF pin 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 өшірулі}

жарамсыз герцель (uint8_t *үлгілері, float *спектрі) {

өзгермелі v_0, v_1, v_2; float re, im, amp; үшін (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k]))); float s = pgm_read_float (& (sin_t [k])); float 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 = (float) (үлгілер ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); спектр [k] = амп; }}

орташа өзгермелі (float *a, uint16_t len) {

өзгермелі нәтиже =.0; for (uint16_t i = 0; i <len; i ++) {нәтиже+= a ; } нәтижені қайтару / len; }

int8_t get_single_index_above_threshold (float *a, uint16_t len, float табалдырығы) {

if (шекті <THRESHOLD) {қайтару -1; } int8_t ix = -1; for (uint16_t i = 0; i шегі) {if (ix == -1) {ix = i; } else {қайтару -1; }}} ix қайтару; }

void detect_digit (float *спектрі) {

float avg_row = avg (спектр, 4); float avg_col = avg (& спектр [4], 4); int8_t row = get_single_index_above_threshold (спектр, 4, avg_row); int8_t col = get_single_index_above_threshold (& спектр [4], 4, avg_col); егер (жол! = -1 && col! = -1 && avg_col> 200) {found_digit.digit = pgm_read_byte (& (кесте [қатар] [col])); found_digit.index = pgm_read_byte (& (char_indexes [қатар] [col])); } басқа {found_digit.digit = 0; }}

void drawSprite (байт* спрайт) {

// Маска спрайт жолының байт маскасынан баған битін алу үшін қолданылады = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));

// масканы бір пиксельге оңға жылжытыңыз

маска = маска >> 1; }

// баған маскасын қалпына келтіру

маска = B10000000; }}

жарамсыз орнату () {

cli (); initADC (); sei ();

Serial.begin (115200);

lmd.setEnabled (шын); lmd.setIntensity (2); lmd.clear (); lmd.display ();

found_digit.digit = 0;

}

белгісіз ұзын z = 0;

void loop () {

while (ADCSRA & _BV (ADIE)); // Аудиториялық іріктеудің тоқтауы аяқталғанша күтіңіз (үлгілер, спектр); detect_digit (спектр);

if (found_digit.digit! = 0) {

drawSprite (қаріп [detect_digit.index]); lmd.display (); } if (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (спектр ); Serial.print («\ t»); } Serial.println (); Serial.println ((int) detect_digit.digit); } z ++;

samplePos = 0;

ADCSRA | = _BV (ADIE); // іріктеу үзілісін жалғастыру

}

ISR (ADC_vect) {

uint16_t үлгі = ADC;

үлгілер [samplePos ++] = үлгі - 400;

if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Буфер толды, үзіліс өшірілді}}

3 -қадам: Схемалар

Схемалар
Схемалар

Келесі байланыстар жасалуы керек:

Ардуиноға микрофон

Шығу -> A0

Vcc -> 3.3V Gnd -> Gnd

AREF -ті 3.3 В -ке қосу маңызды

Arduino дисплейі

Vcc -> 5V

Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9

4 -қадам: Қорытынды

Бұл жерде нені жақсартуға болады? Мен N = 256 үлгілерін 9615 Гц жылдамдықта қолдандым, оның спектрінің ағуы бар, егер N = 205 және жылдамдығы 8000 Гц болса, онда қалаған жиіліктер дискретизация торымен сәйкес келеді. Ол үшін ADC таймердің толып кету режимінде қолданылуы керек.

Ұсынылған: