INHOUDSOPGAWE:

DTMF -detektor: 4 stappe
DTMF -detektor: 4 stappe

Video: DTMF -detektor: 4 stappe

Video: DTMF -detektor: 4 stappe
Video: Я открываю 5 AP Packs Ikoria the Land of Behemoths, карты Magic The Gathering 2024, Julie
Anonim
Image
Image

Oorsig

Ek is geïnspireer om hierdie toestel te bou deur 'n tuisopdrag oor die digitale kursus van digitale seinverwerking. Dit is 'n DTMF -dekodeerder wat met Arduino UNO geïmplementeer word, en dit ontdek 'n syfer wat op die telefoonklavier in die klankmodus gedruk word deur die klank wat dit produseer.

Stap 1: Begrip van die algoritme

Die kode
Die kode

In DTMF is elke simbool gekodeer met twee frekwensies volgens die tabel op die prent.

Die toestel vang insette vanaf die mikrofoon op en bereken amplitudes van agt frekwensies. Twee frekwensies met 'n maksimum amplitude gee 'n ry en 'n kolom van die gekodeerde simbool.

Data -verkryging

Om spektrumanalise uit te voer, moet monsters teen 'n sekere voorspelbare frekwensie geneem word. Om dit te bereik, gebruik ek die vryloop-ADC-modus met maksimum akkuraatheid (prescaler 128), dit gee 'n monsternemingstempo van 9615Hz. Die onderstaande kode wys hoe u die ADC van Arduino kan opstel.

ongeldig initADC () {

// Init ADC; f = (16MHz/prescaler)/13 siklusse/omskakeling ADMUX = 0; // Kanaal sel, regs-adj, gebruik AREF-pen ADCSRA = _BV (ADEN) | // ADC aktiveer _BV (ADSC) | // ADC begin _BV (ADATE) | // Outomatiese sneller _BV (ADIE) | // Onderbreek aktiveer _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Vryloopmodus DIDR0 = _BV (0); // Skakel digitale invoer uit vir ADC -pen TIMSK0 = 0; // Timer0 af} En die interrupt -hanteerder lyk soos hierdie ISR (ADC_vect) {uint16_t sample = ADC; samples [samplePos ++] = sample - 400; as (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buffer vol, onderbreek af}}

Spektrum analise

Nadat ek monsters versamel het, bereken ek amplitudes van 8 frekwensies wat simbole kodeer. Ek hoef nie volledige FFT hiervoor uit te voer nie, so ek het die algoritme van Goertzel gebruik.

leegte goertzel (uint8_t *monsters, float *spektrum) {

dryf v_0, v_1, v_2; float re, im, amp; vir (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k]))); float s = pgm_read_float (& (sin_t [k]))); dryf a = 2. * c; v_0 = v_1 = v_2 = 0; vir (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (monsters ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektrum [k] = amp; }}

Stap 2: Die kode

Die foto hierbo toon die voorbeeld van kodering van syfer 3 waar die maksimum amplitude ooreenstem met die frekwensies 697Hz en 1477Hz.

Die volledige skets lyk soos volg

/** * Verbindings: * [Mic na Arduino] * - Uit -> 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

#insluit

#definieer CS_PIN 9

#definieer N 256

#definieer IX_LEN 8 #definieer DREMPEL 20

LEDMatrixDriver lmd (1, CS_PIN);

uint8_t monsters [N];

vlugtige uint16_t samplePos = 0;

dryfspektrum [IX_LEN];

// Frekwensies [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]

// Bereken vir 9615Hz 256 monsters const float cos_t [IX_LEN] PROGMEEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.6343932841636456, 0.5365 const float sin_t [IX_LEN] PROGMEEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025451, 0.88

typedef struct {

char syfer; uint8_t indeks; } syfer_t;

syfer_t opgespoor_syfer;

const char tabel [4] [4] PROGMEEM = {

{'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', ' C '}, {'*',' 0 ','#',' D '}};

const uint8_t char_indexes [4] [4] PROGMEEM = {

{1, 2, 3, 10}, {4, 5, 6, 11}, {7, 8, 9, 12}, {15, 0, 14, 13} };

greep lettertipe [16] [8] = {

{0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38}, // 0 {0x04, 0x0c, 0x14, 0x24, 0x04, 0x04, 0x04, 0x04}, // 1 {0x00, 0x30, 0x48, 0x0, 0x04, 0x38, 0x40, 0x7c}, // 2 {0x00, 0x38, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38}, // 3 {0x00, 0x04, 0x0c, 0x14, 0x24, 0x7e, 0x04, 0x0 }, // 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} // *};

ongeldig initADC () {

// Init ADC; f = (16MHz/prescaler)/13 siklusse/omskakeling ADMUX = 0; // Kanaal sel, regs-adj, gebruik AREF-pen ADCSRA = _BV (ADEN) | // ADC aktiveer _BV (ADSC) | // ADC begin _BV (ADATE) | // Outomatiese sneller _BV (ADIE) | // Onderbreek aktiveer _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Vryloopmodus DIDR0 = _BV (0); // Skakel digitale invoer uit vir ADC -pen TIMSK0 = 0; // Timer0 af

leegte goertzel (uint8_t *monsters, float *spektrum) {

float v_0, v_1, v_2; float re, im, amp; vir (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k]))); float s = pgm_read_float (& (sin_t [k]))); dryf a = 2. * c; v_0 = v_1 = v_2 = 0; vir (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (monsters ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektrum [k] = amp; }}

float gemiddelde (float *a, uint16_t len) {

vlot resultaat =.0; vir (uint16_t i = 0; i <len; i ++) {resultaat+= a ; } opbrengs resultaat / len; }

int8_t get_single_index_above_threshold (float *a, uint16_t len, float drumpel) {

as (drempel <DREMPEL) {opgawe -1; } int8_t ix = -1; vir (uint16_t i = 0; i drempel) {if (ix == -1) {ix = i; } anders {opgawe -1; }}} terugkeer ix; }

leemte detect_digit (float *spektrum) {

float avg_row = gemiddelde (spektrum, 4); float avg_col = gemiddelde (& spektrum [4], 4); int8_t ry = get_single_index_above_threshold (spektrum, 4, avg_row); int8_t col = get_single_index_above_threshold (& spektrum [4], 4, avg_col); as (ry! = -1 && col! = -1 && avg_col> 200) {detect_digit.digit = pgm_read_byte (& (tabel [ry] [col])); detect_digit.index = pgm_read_byte (& (char_indexes [ry] [kol])); } anders {detect_digit.digit = 0; }}

void drawSprite (byte* sprite) {

// Die masker word gebruik om die kolombit uit die sprite ry byte masker te kry = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & masker));

// skuif die masker met een pixel na regs

masker = masker >> 1; }

// stel kolommasker terug

masker = B10000000; }}

ongeldige opstelling () {

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

Serial.begin (115200);

lmd.setEnabled (waar); lmd.setIntensity (2); lmd.clear (); lmd.display ();

detect_digit.digit = 0;

}

ongetekende lang z = 0;

leemte -lus () {

terwyl (ADCSRA & _BV (ADIE)); // Wag totdat die klankmonster klaar is met goertzel (monsters, spektrum); detect_digit (spektrum);

as (detect_digit.digit! = 0) {

drawSprite (font [detect_digit.index]); lmd.display (); } if (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (spektrum ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) detect_digit.digit); } z ++;

samplePos = 0;

ADCSRA | = _BV (ADIE); // Hervat die steekproefonderbreking

}

ISR (ADC_vect) {

uint16_t monster = ADC;

monsters [samplePos ++] = monster - 400;

as (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buffer vol, onderbreek af}}

Stap 3: Skema's

Skemas
Skemas

Die volgende verbindings moet gemaak word:

Mikrofoon na Arduino

Uit -> A0

Vcc -> 3.3V Gnd -> Gnd

Dit is belangrik om AREF aan te sluit op 3.3V

Vertoon vir Arduino

Vcc -> 5V

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

Stap 4: Gevolgtrekking

Wat kan hier verbeter word? Ek gebruik N = 256 monsters met 'n snelheid van 9615Hz, wat 'n mate van spektrumlek het, as N = 205 en die snelheid 8000Hz is, val die gewenste frekwensies saam met die diskretiseringsrooster. Hiervoor moet ADC gebruik word in die timer -oorloopmodus.

Aanbeveel: