Агуулгын хүснэгт:

DTMF илрүүлэгч: 4 алхам
DTMF илрүүлэгч: 4 алхам

Видео: DTMF илрүүлэгч: 4 алхам

Видео: DTMF илрүүлэгч: 4 алхам
Видео: Создание DTMF звонка для Вашей радиостанции 2024, Арваннэгдүгээр
Anonim
Image
Image

Тойм

Дижитал дохио боловсруулах онлайн хичээл дээр гэрийн даалгавар өгөхөд би энэ төхөөрөмжийг бүтээх санаа авсан юм. Энэ бол DTMF декодер бөгөөд Arduino UNO -той хамтран ажилладаг бөгөөд гар утасны товчлуур дээр дарагдсан цифрийг дууны горимоор нь илрүүлдэг.

Алхам 1: Алгоритмыг ойлгох

Код
Код

DTMF -д тэмдэг тус бүрийг зурган дээрх хүснэгтийн дагуу хоёр давтамжаар кодлодог.

Төхөөрөмж нь микрофоны оролтыг авч, найман давтамжийн далайцыг тооцоолно. Хамгийн их далайцтай хоёр давтамж нь кодлогдсон тэмдгийн мөр, баганыг өгдөг.

Мэдээлэл олж авах

Спектрийн шинжилгээ хийхийн тулд дээжийг урьдчилан таамаглах боломжтой давтамжтайгаар авах ёстой. Үүнд хүрэхийн тулд би ADC горимыг хамгийн нарийвчлалтайгаар (prescaler 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 эхлэх _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 *дээж, хөвөх *спектр) {

хөвөх 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])); хөвөх a = 2. * c; v_0 = v_1 = v_2 = 0; for (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (хөвөх) (дээж ) + a * v_1 - v_0; } дахин = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); спектр [k] = өсгөгч; }}

Алхам 2: Код

Дээрх зураг нь хамгийн их далайц нь 697 Гц ба 1477 Гц давтамжтай тохирч байгаа 3 -р оронтой кодчиллын жишээг харуулж байна.

Бүрэн ноорог дараах байдлаар харагдаж байна

/** * Холболтууд: * [Micro to Arduino] * - Out -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [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.68954054473706396236666666666666666868 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;

оронтой_т илэрсэн_дижит;

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, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38 }, // 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 эхлэх _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 *дээж, хөвөх *спектр) {

хөвөх 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])); хөвөх a = 2. * c; v_0 = v_1 = v_2 = 0; for (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (хөвөх) (дээж ) + a * v_1 - v_0; } дахин = 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 (босго <БОНГО) {буцах -1; } int8_t ix = -1; for (uint16_t i = 0; i босго) {if (ix == -1) {ix = i; } өөр {буцах -1; }}} ix буцаах; }

хүчин төгөлдөр бус илрүүлэх_дигит (хөвөх *спектр) {

хөвөх avg_row = дундаж (спектр, 4); float avg_col = avg (& спектр [4], 4); int8_t row = get_single_index_above_threshold (спектр, 4, дундаж_хаг); int8_t col = get_single_index_above_threshold (& спектр [4], 4, avg_col); хэрэв (мөр! = -1 && col! = -1 && avg_col> 200) {илрүүлсэн_дигит.дигит = pgm_read_byte (& (хүснэгт [мөр] [col])); илрүүлсэн_digit.index = pgm_read_byte (& (char_indexes [мөр] [col])); } өөр {илрүүлсэн_digit.digit = 0; }}

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

// Маскийг sprite эгнээний байтын маскнаас баганын битийг авахад ашигладаг = 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 ();

Цуваа.begin (115200);

lmd.setEnabled (үнэн); lmd.setIntensity (2); lmd.clear (); lmd.display ();

илэрсэн_дигит.digit = 0;

}

гарын үсэг зураагүй урт z = 0;

void loop () {

байхад (ADCSRA & _BV (ADIE)); // Аудио дээж авах ажлыг goertzel дуусгахыг хүлээнэ үү (дээж, спектр); илрүүлэх_дижит (спектр);

хэрэв (илэрсэн_дигит.дигит! = 0) {

drawSprite (фонт [found_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) илрүүлсэн_дижит.дижит); } z ++;

samplePos = 0;

ADCSRA | = _BV (ADIE); // Дээж авах тасалдлыг үргэлжлүүлнэ үү

}

ISR (ADC_vect) {

uint16_t дээж = ADC;

дээж [samplePos ++] = дээж - 400;

if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Буфер дүүрсэн, тасалдал унтарсан}}

Алхам 3: Схем

Схем
Схем

Дараахь холболтыг хийх ёстой.

Микрофоноос Arduino руу

Гарсан -> A0

Vcc -> 3.3V Gnd -> Gnd

AREF -ийг 3.3V -т холбох нь чухал юм

Arduino дээр харуулах

Vcc -> 5V

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

Алхам 4: Дүгнэлт

Энд юу сайжруулж болох вэ? Би 9615 Гц давтамжтай N = 256 дээжийг ашигласан бөгөөд энэ нь зарим спектрийн алдагдалтай, хэрэв N = 205 ба хурд нь 8000 Гц бол хүссэн давтамж нь дискретизацийн сүлжээтэй давхцдаг. Үүний тулд ADC -ийг таймер халих горимд ашиглах ёстой.

Зөвлөмж болгож буй: