Indholdsfortegnelse:

DTMF -detektor: 4 trin
DTMF -detektor: 4 trin

Video: DTMF -detektor: 4 trin

Video: DTMF -detektor: 4 trin
Video: Relay control via phone call | DTMF Decoding 2024, Juli
Anonim
Image
Image

Oversigt

Jeg blev inspireret til at bygge denne enhed af en hjemmeopgave på Digital Signal Processing online kursus. Dette er en DTMF -dekoder implementeret med Arduino UNO, det registrerer et ciffer, der trykkes på et telefontastatur i tonefunktionen af den lyd, det producerer.

Trin 1: Forståelse af algoritmen

Koden
Koden

I DTMF er hvert symbol kodet med to frekvenser i henhold til tabellen på billedet.

Enheden fanger input fra mikrofonen og beregner amplituder på otte frekvenser. To frekvenser med maksimale amplituder giver en række og en kolonne med det kodede symbol.

Dataindsamling

For at udføre spektrumanalyse skal prøver fanges med en bestemt forudsigelig frekvens. For at opnå dette brugte jeg fritløbende ADC-tilstand med maksimal præcision (prescaler 128) det giver samplingshastighed 9615Hz. Koden herunder viser, hvordan du konfigurerer Arduinos ADC.

ugyldig initADC () {

// Init ADC; f = (16MHz/prescaler)/13 cyklusser/konvertering ADMUX = 0; // Kanalsel, højre-adj, brug AREF pin ADCSRA = _BV (ADEN) | // ADC aktiver _BV (ADSC) | // ADC start _BV (ADATE) | // Auto trigger _BV (ADIE) | // Afbryd aktivering _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Free-run mode DIDR0 = _BV (0); // Sluk digital input for ADC pin TIMSK0 = 0; // Timer0 off} Og interrupt handler ligner denne ISR (ADC_vect) {uint16_t sample = ADC; samples [samplePos ++] = sample - 400; hvis (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buffer fuld, afbryd}}

Spektrumanalyse

Efter indsamling af prøver beregner jeg amplituder på 8 frekvenser, der koder for symboler. Jeg behøver ikke at køre fuld FFT til dette, så jeg brugte Goertzels algoritme.

void goertzel (uint8_t *samples, float *spectrum) {

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])); flyde 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 = (float) (prøver ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektrum [k] = amp; }}

Trin 2: Koden

Billedet ovenfor viser eksemplet på kodning af ciffer 3, hvor maksimal amplitude svarer til frekvenserne 697Hz og 1477Hz.

Den komplette skitse ser således ud

/** * Tilslutninger: * [Mic til Arduino] * - Ud -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Display til Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include

#omfatte

#define CS_PIN 9

#definer N 256

#define IX_LEN 8 #define THRESHOLD 20

LEDMatrixDriver lmd (1, CS_PIN);

uint8_t prøver [N];

flygtig uint16_t samplePos = 0;

float spektrum [IX_LEN];

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

// Beregnet til 9615Hz 256 prøver const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.6343932841636456, 0.5365 const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025451, 0.88

typedef struct {

char ciffer; uint8_t indeks; } ciffer_t;

digit_t opdaget_digit;

const char tabel [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} };

byte skrifttype [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} // *};

ugyldig initADC () {

// Init ADC; f = (16MHz/prescaler)/13 cyklusser/konvertering ADMUX = 0; // Kanalsel, højre-adj, brug AREF pin ADCSRA = _BV (ADEN) | // ADC aktiver _BV (ADSC) | // ADC start _BV (ADATE) | // Auto trigger _BV (ADIE) | // Afbryd aktivering _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Free-run mode DIDR0 = _BV (0); // Sluk digital input for ADC pin TIMSK0 = 0; // Timer0 fra

void goertzel (uint8_t *samples, float *spectrum) {

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])); flyde 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 = (float) (prøver ) + 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 gns. (float *a, uint16_t len) {

float resultat =.0; for (uint16_t i = 0; i <len; i ++) {resultat+= a ; } returnere resultat / len; }

int8_t get_single_index_above_threshold (float *a, uint16_t len, float tærskel) {

hvis (tærskel <THRESHOLD) {return -1; } int8_t ix = -1; for (uint16_t i = 0; i tærskel) {if (ix == -1) {ix = i; } else {return -1; }}} returner ix; }

void detect_digit (float *spectrum) {

float avg_row = gennemsnit (spektrum, 4); float avg_col = avg (& spektrum [4], 4); int8_t række = get_single_index_above_threshold (spektrum, 4, avg_row); int8_t col = get_single_index_above_threshold (& spektrum [4], 4, avg_col); hvis (række! = -1 && col! = -1 && avg_col> 200) {detect_digit.digit = pgm_read_byte (& (tabel [række] [col])); detekteret_digit.index = pgm_read_byte (& (char_indexes [række] [kol])); } andet {opdaget_digit.digit = 0; }}

void drawSprite (byte* sprite) {

// Masken bruges til at hente søjlebitten fra sprite række byte maske = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));

// skift masken med en pixel til højre

maske = maske >> 1; }

// nulstil kolonnemaske

maske = B10000000; }}

ugyldig opsætning () {

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

Serial.begin (115200);

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

detekteret_digit.digit = 0;

}

usigneret lang z = 0;

void loop () {

mens (ADCSRA & _BV (ADIE)); // Vent på, at lydsampling er færdig med goertzel (prøver, spektrum); detect_digit (spektrum);

hvis (opdaget_digit.digit! = 0) {

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

samplePos = 0;

ADCSRA | = _BV (ADIE); // Genoptag prøveudtagningsafbrydelse

}

ISR (ADC_vect) {

uint16_t sample = ADC;

prøver [samplePos ++] = prøve - 400;

hvis (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buffer fuld, afbryd}}

Trin 3: Skemaer

Skemaer
Skemaer

Følgende forbindelser skal foretages:

Mikrofon til Arduino

Ud -> A0

Vcc -> 3.3V Gnd -> Gnd

Det er vigtigt at tilslutte AREF til 3,3V

Skærm til Arduino

Vcc -> 5V

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

Trin 4: Konklusion

Hvad kan forbedres her? Jeg brugte N = 256 prøver med en hastighed på 9615Hz, som har noget spektrumlækage, hvis N = 205 og hastigheden er 8000Hz, falder de ønskede frekvenser sammen med diskretiseringsgitteret. Til denne ADC bør bruges i timeroverløbstilstand.

Anbefalede: