Мазмуну:

DTMF детектору: 4 кадам
DTMF детектору: 4 кадам

Video: DTMF детектору: 4 кадам

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

Обзор

Бул аппаратты санариптик сигналды иштетүү боюнча онлайн курстун тапшырмасы шыктандырды. Бул Arduino UNO менен ишке ашырылган DTMF декодери, ал үндүн режиминде телефондун клавиатурасында басылган санды аныктайт.

1 -кадам: Алгоритмди түшүнүү

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

DTMFде ар бир символ сүрөттөгү таблицага ылайык эки жыштык менен коддолгон.

Түзмөк микрофондун киришин жазат жана сегиз жыштыктын амплитудасын эсептейт. Максималдуу амплитудасы бар эки жыштык коддолгон символдун бир сабын жана колонкасын берет.

Маалымат алуу

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

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

// Init ADC; f = (16MHz/prescaler)/13 цикл/конверсия ADMUX = 0; // Channel sel, right-adj, AREF pin ADCSRA = _BV (ADEN) | колдонуңуз // ADC _BV (ADSC) иштетүү | // ADC баштоо _BV (ADATE) | // Авто триггер _BV (ADIE) | // Үзгүлтүк иштетүү _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Гц ADCSRB = 0; // Эркин иштөө режими DIDR0 = _BV (0); // ADC пин TIMSK0 = 0 үчүн санариптик киргизүүнү өчүрүү; // Timer0 өчүк} Жана үзгүлтүк иштетүүчү мындай ISR (ADC_vect) окшойт {uint16_t sample = ADC; sample [samplePos ++] = sample - 400; if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Буфер толгон, үзгүлтүккө учуроо}}

Спектр анализи

Үлгүлөрдү чогулткандан кийин мен 8 жыштыктын коддоочу амплитудасын эсептейм. Бул үчүн толук FFT иштетүүнүн кажети жок, ошондуктан мен Goertzelдин алгоритмин колдондум.

жараксыз гертцел (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 = (калкып чыгуу) (үлгүлөр ) + 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 үчүн Arduino] * - Чыгуу -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Ардуиного көрсөтүү] * - 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.6895405447370639623666666666666666666686, 0,831666666666666, 0,8316692 const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.7730104533627369, 0.7730104533627369

typedef структурасы {

char цифрасы; uint8_t индекси; } digit_t;

digit_t found_digit;

const char table [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 () {

// Init ADC; f = (16MHz/prescaler)/13 цикл/конверсия ADMUX = 0; // Channel sel, right-adj, AREF pin ADCSRA = _BV (ADEN) | колдонуңуз // ADC _BV (ADSC) иштетүү | // ADC баштоо _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 = (калкып чыгуу) (үлгүлөр ) + 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) {

float result =.0; for (uint16_t i = 0; i <len; i ++) {result+= a ; } return result / 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 {return -1; }}} return 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); if (row! = -1 && col! = -1 && avg_col> 200) {found_digit.digit = pgm_read_byte (& (table [row] [col])); found_digit.index = pgm_read_byte (& (char_indexes [катар] [col])); } else {found_digit.digit = 0; }}

жараксыз 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 sample = ADC;

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

if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Буфер толгон, үзгүлтүккө учуроо}}

3 -кадам: схемалар

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

Төмөндөгү байланыштар түзүлүшү керек:

Микрофон Ардуиного

Чыгуу -> A0

Vcc -> 3.3V Gnd -> Gnd

AREFти 3.3Vга туташтыруу маанилүү

Arduino үчүн көрсөтүү

Vcc -> 5V

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

4 -кадам: Жыйынтык

Бул жерде эмне жакшыртылышы мүмкүн? Мен N = 256 үлгүлөрүн 9615 Гц ылдамдыкта колдонгом, ал спектрдин агып кетишине ээ, эгерде N = 205 жана ылдамдыгы 8000 Гц болсо, анда каалаган жыштыктар дискретизация торуна дал келет. Бул үчүн ADC таймердин толуп кетүү режиминде колдонулушу керек.

Сунушталууда: