Cuprins:
Video: Detector DTMF: 4 pași
2024 Autor: John Day | [email protected]. Modificat ultima dată: 2024-01-30 11:44
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
Î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
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:
DTMF VIDEO STREAMING ROVER: 3 pași
DTMF VIDEO STREAMING ROVER: salut după LINUX TERMINAL CONTROLLED ROVER și WIFI DTMF PC CONTROLLED ROBOT acesta este al treilea robot al meu. și, ca și alte două aici, nu am folosit niciun microcontroler sau programare pentru a-l păstra simplu și ușor de făcut
Cum se face un decodificator de linie telefonică DTMF simplu (ton): 3 pași
Cum se face un decodificator de linie telefonică DTMF simplu (ton): Acesta este un proiect simplu care vă permite să decodificați semnale DTMF pe orice linie telefonică. În acest tutorial, folosim decodorul MT8870D. Folosim un decodor de tonuri preconstruit deoarece, credeți-mă, este o durere în spate să încercați să o faceți cu
ROBOT WIFI DTMF: 5 pași
WIFI DTMF ROBOT: salut în acest tutorial vă voi arăta cum puteți face un rover controlat de computer fără a utiliza microcontroler, acest lucru înseamnă că în acest proiect nu există cod de nivel înalt implicat, aveți nevoie doar de cunoștințe de bază despre realizarea paginii html. pot viziona complet
Cum se face un robot controlat pe mobil - Bazat pe DTMF - Fără microcontroler și programare - Control de oriunde din lume - RoboGeeks: 15 pași
Cum se face un robot controlat pe mobil | Bazat pe DTMF | Fără microcontroler și programare | Control de oriunde din lume | RoboGeeks: Vrei să faci un robot care poate fi controlat de oriunde în lume, Lets do It
DETECTOR ÎMBUNĂTĂȚIT DETECTOR PENTRU CAMERE SUBMĂRII: 7 pași (cu imagini)
ÎMBUNĂTĂȚIT DETECTOR DE SCURGERI PENTRU CAMERE SUBMARINE: O versiune anterioară a acestui detector de scurgere a carcasei camerei subacvatice a fost postată pe Instructables anul trecut, unde proiectarea s-a bazat pe un AdaFruit Trinket bazat pe Atmel AVR. Această versiune îmbunătățită folosește AdaFruit Trinket bazat pe Atmel SAMD M0. Acolo