Cuprins:

Detector DTMF: 4 pași
Detector DTMF: 4 pași

Video: Detector DTMF: 4 pași

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

Prezentare generală

Am fost inspirat să construiesc acest dispozitiv printr-o misiune la domiciliu pe cursul online de procesare digitală a semnalului. Acesta este un decodor DTMF implementat cu Arduino UNO, detectează o cifră apăsată pe tastatura telefonului în modul de ton prin sunetul pe care îl produce.

Pasul 1: Înțelegerea algoritmului

Codul
Codul

În DTMF fiecare simbol este codat cu două frecvențe în conformitate cu tabelul din imagine.

Dispozitivul captează intrarea de la microfon și calculează amplitudini de opt frecvențe. Două frecvențe cu amplitudini maxime dau un rând și o coloană a simbolului codificat.

Achizitie de date

Pentru a efectua analiza spectrului, probele ar trebui să fie capturate la o anumită frecvență previzibilă. Pentru a realiza acest lucru, am folosit modul ADC cu rulare liberă cu precizie maximă (prescaler 128), acesta oferă o rată de eșantionare 9615Hz. Codul de mai jos arată cum să configurați ADC-ul Arduino.

voie initADC () {

// Init ADC; f = (16MHz / prescaler) / 13 cicluri / conversie ADMUX = 0; // Channel sel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // ADC activate _BV (ADSC) | // ADC start _BV (ADATE) | // Declanșare automată _BV (ADIE) | // Activare întrerupere _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Modul de rulare liberă DIDR0 = _BV (0); // Dezactivați intrarea digitală pentru pinul ADC TIMSK0 = 0; // Timer0 off} Și gestionarul de întreruperi arată ca acest ISR (ADC_vect) {uint16_t sample = ADC; samples [samplePos ++] = sample - 400; if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buffer full, interrupt off}}

Analiza spectrului

După colectarea probelor calculez amplitudini de 8 frecvențe care codifică simboluri. Nu trebuie să rulez FFT complet pentru asta, așa că am folosit algoritmul Goertzel.

voertz goertzel (uint8_t * mostre, float * spectru) {

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

Pasul 2: Codul

Imaginea de mai sus arată exemplul de codificare a cifrei 3 în care amplitudinea maximă corespunde frecvențelor 697Hz și 1477Hz.

Schița completă arată după cum urmează

/ ** * Conexiuni: * [Mic la Arduino] * - Out -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Afișare la Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 * / #include #include

#include

#define CS_PIN 9

#define N 256

#define IX_LEN 8 #define THRESHOLD 20

LEDMatrixDriver lmd (1, CS_PIN);

uint8_t mostre [N];

volatil uint16_t samplePos = 0;

spectru plutitor [IX_LEN];

// Frecvențe [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]

// Calculat pentru 9615Hz 256 de probe const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.6343932841636456, 0.5555, 0.5555 const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.83146961230252451, 0.88

typedef struct {

cifra char; uint8_t index; } cifră_t;

cifră_t cifră_detectată;

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

octet font [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, 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} // *};

voit initADC () {

// Init ADC; f = (16MHz / prescaler) / 13 cicluri / conversie ADMUX = 0; // Channel sel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // ADC activate _BV (ADSC) | // ADC start _BV (ADATE) | // Declanșare automată _BV (ADIE) | // Activare întrerupere _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Modul de rulare liberă DIDR0 = _BV (0); // Dezactivați intrarea digitală pentru pinul ADC TIMSK0 = 0; // Timer0 off}

voertz goertzel (uint8_t * mostre, spectru float *) {

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

float avg (float * a, uint16_t len) {

rezultat float =.0; for (uint16_t i = 0; i <len; i ++) {result + = a ; } returnează rezultatul / len; }

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

if (prag <THRESHOLD) {return -1; } int8_t ix = -1; for (uint16_t i = 0; i prag) {if (ix == -1) {ix = i; } else {return -1; }}} returnează ix; }

void detect_digit (float * spectru) {

float avg_row = avg (spectru, 4); float avg_col = avg (& spectru [4], 4); int8_t rând = get_single_index_above_threshold (spectru, 4, avg_row); int8_t col = get_single_index_above_threshold (& spectru [4], 4, avg_col); if (rând! = -1 && col! = -1 && avg_col> 200) {detectat_digit.digit = pgm_read_byte (& (tabel [rând] [col])); digital_digit.index = pgm_read_byte (& (char_indexes [rând] [col])); } else {detect_digit.digit = 0; }}

nul drawSprite (octet * sprite) {

// Masca este utilizată pentru a obține bitul de coloană din masca de octet rând 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));

// deplasați masca cu un pixel spre dreapta

masca = masca >> 1; }

// resetează masca coloanei

mască = B10000000; }}

configurare nulă () {

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

Serial.begin (115200);

lmd.setEnabled (adevărat); lmd.setIntensity (2); lmd.clear (); lmd.display ();

digital_digit.digit = 0;

}

nesemnat lung z = 0;

bucla nulă () {

while (ADCSRA & _BV (ADIE)); // Așteptați ca eșantionarea audio să finalizeze goertzel (mostre, spectru); detect_digit (spectru);

dacă (detectat_digit.digit! = 0) {

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

samplePos = 0;

ADCSRA | = _BV (ADIE); // Reluați întreruperea eșantionării

}

ISR (ADC_vect) {

uint16_t sample = ADC;

samples [samplePos ++] = sample - 400;

if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buffer full, interrupt off}}

Pasul 3: Scheme

Scheme
Scheme

Ar trebui făcute următoarele conexiuni:

Mic la Arduino

Afară -> A0

Vcc -> 3.3V Gnd -> Gnd

Este important să conectați AREF la 3,3V

Afișați pe Arduino

Vcc -> 5V

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

Pasul 4: Concluzie

Ce ar putea fi îmbunătățit aici? Am folosit N = 256 eșantioane la o rată de 9615Hz, care are o anumită scurgere de spectru, dacă N = 205 și rata este de 8000Hz, atunci frecvențele dorite coincid cu grila de discretizare. Pentru aceasta ADC ar trebui să fie utilizat în modul de depășire a temporizatorului.

Recomandat: