Sadržaj:
Video: DTMF detektor: 4 koraka
2024 Autor: John Day | [email protected]. Zadnja promjena: 2024-01-30 09:36
Pregled
Za izradu ovog uređaja inspirirao me domaći zadatak na internetskom tečaju Digitalna obrada signala. Ovo je DTMF dekoder implementiran s Arduino UNO, detektira znamenku pritisnutu na tipkovnici telefona u tonskom načinu zvukom koji proizvodi.
Korak 1: Razumijevanje algoritma
U DTMF -u je svaki simbol kodiran s dvije frekvencije prema tablici na slici.
Uređaj snima ulaz s mikrofona i izračunava amplitude osam frekvencija. Dvije frekvencije s maksimalnim amplitudama daju red i stupac kodiranog simbola.
Prikupljanje podataka
Kako bi se izvršila analiza spektra, uzorke je potrebno snimiti na određenoj predvidljivoj frekvenciji. Da bih to postigao, koristio sam ADC način rada s maksimalnom preciznošću (predskaler 128) koji daje frekvenciju uzorkovanja 9615Hz. Donji kod prikazuje kako konfigurirati Arduino ADC.
void initADC () {
// Pokreni ADC; f = (16MHz/predskaler)/13 ciklusa/konverzija ADMUX = 0; // Sel channel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // Omogućivanje ADC -a _BV (ADSC) | // ADC početak _BV (ADATE) | // Automatski okidač _BV (ADIE) | // Omogućivanje prekida _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Slobodni način rada DIDR0 = _BV (0); // Isključivanje digitalnog ulaza za ADC pin TIMSK0 = 0; // Timer0 off} A rukovatelj prekida izgleda ovako: ISR (ADC_vect) {uint16_t sample = ADC; uzorci [samplePos ++] = uzorak - 400; if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Međuspremnik pun, prekid isključen}}
Analiza spektra
Nakon prikupljanja uzoraka izračunavam amplitude 8 frekvencija koje kodiraju simbole. Za ovo mi ne treba pokretanje punog FFT -a, pa sam upotrijebio Goertzelov algoritam.
void goertzel (uint8_t *uzorci, float *spektar) {
plovak 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])); float a = 2. * c; v_0 = v_1 = v_2 = 0; za (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (uzorci ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektar [k] = amp; }}
Korak 2: Kôd
Gornja slika prikazuje primjer kodiranja znamenke 3 gdje maksimalna amplituda odgovara frekvencijama 697Hz i 1477Hz.
Cjelovita skica izgleda ovako
/** * Priključci: * [Mic na Arduino] * - Out -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Prikaz na Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include
#uključi
#define CS_PIN 9
#definiraj N 256
#define IX_LEN 8 #define THRESHOLD 20
LEDMatrixDriver lmd (1, CS_PIN);
uint8_t uzorci [N];
volatile uint16_t samplePos = 0;
plutajući spektar [IX_LEN];
// Frekvencije [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]
// Izračunato za 9615Hz 256 uzoraka const float cos_t [IX_LEN] PROGMEM = {0,8932243011955153, 0,8700869911087115, 0,8448535652497071, 0,8032075314806449, 0,6895405447370669, 0,634393284163645639, 0,56036, 0,62336 const float sin_t [IX_LEN] PROGMEM = {0,44961132965460654, 0,49289819222978404, 0,5349976198870972, 0,5956993044924334, 0,7242470829514669, 0,7730104533627369, 0,8314696123025451, 0,8314696123025451, typedef struct {
znamenka znamenke; uint8_t indeks; } znamenka_t;
digit_t otkrivena_digit;
const char tablica [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} };
font byte [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 }, // 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} // *};
void initADC () {
// Pokreni ADC; f = (16MHz/predskaler)/13 ciklusa/konverzija ADMUX = 0; // Sel channel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // Omogućivanje ADC -a _BV (ADSC) | // ADC početak _BV (ADATE) | // Automatski okidač _BV (ADIE) | // Omogućivanje prekida _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Hz ADCSRB = 0; // Slobodni način rada DIDR0 = _BV (0); // Isključivanje digitalnog ulaza za ADC pin TIMSK0 = 0; // Timer0 isključen}
void goertzel (uint8_t *uzorci, float *spektar) {
plovak 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])); float a = 2. * c; v_0 = v_1 = v_2 = 0; za (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (uzorci ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektar [k] = amp; }}
float avg (float *a, uint16_t len) {
plutajući rezultat =, 0; for (uint16_t i = 0; i <len; i ++) {rezultat+= a ; } vratiti rezultat / len; }
int8_t get_single_index_above_threshold (float *a, uint16_t len, float prag) {
if (prag <PRAG) {return -1; } int8_t ix = -1; za (uint16_t i = 0; i prag) {if (ix == -1) {ix = i; } else {povratak -1; }}} return ix; }
void detektiraj_digit (float *spektar) {
float avg_row = avg (spektar, 4); float avg_col = avg (& spektar [4], 4); int8_t redak = get_single_index_above_threshold (spektar, 4, prosjek_row); int8_t col = get_single_index_above_threshold (& spektar [4], 4, avg_col); if (red! = -1 && col! = -1 && avg_col> 200) {otkrivena_digit.digit = pgm_čitana_bajt (& (tablica [redak] [kol])); otkrivena_digit.index = pgm_čitana_bajta (& (char_indexes [red] [col])); } else {otkrivena_digit.digit = 0; }}
void drawSprite (byte* sprite) {
// Maska se koristi za dobivanje bita stupca iz sprite red byte mask = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));
// pomaknuti masku za jedan piksel udesno
maska = maska >> 1; }
// vraćanje maske stupca
maska = B10000000; }}
void setup () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (true); lmd.setIntensity (2); lmd.clear (); lmd.display ();
otkrivena_digit.digit = 0;
}
bezznačno dugo z = 0;
void loop () {{100} {101}
while (ADCSRA & _BV (ADIE)); // Pričekajte da audio uzorkovanje završi goertzel (uzorci, spektar); detektiraj_cifru (spektar);
if (otkrivena_digit.digit! = 0) {
drawSprite (font [otkriven_digit.index]); lmd.display (); } if (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (spektar ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) otkrivena_digit.digit); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Nastavak uzorkovanja prekida
}
ISR (ADC_vect) {
uint16_t uzorak = ADC;
uzorci [samplePos ++] = uzorak - 400;
if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Međuspremnik pun, prekid isključen}}
Korak 3: Sheme
Potrebno je uspostaviti sljedeće veze:
Mic na Arduino
Izlaz -> A0
Vcc -> 3,3 V Gnd -> Gnd
Važno je spojiti AREF na 3.3V
Prikaži na Arduinu
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Korak 4: Zaključak
Što bi se tu moglo poboljšati? Koristio sam N = 256 uzoraka pri brzini 9615Hz koja ima neko curenje spektra, ako je N = 205 i brzina je 8000Hz tada se željene frekvencije podudaraju s diskrecijskom mrežom. Za to se ADC treba koristiti u modu preljevanja timera.
Preporučeni:
DTMF VIDEO STRAMING ROVER: 3 koraka
DTMF VIDEO STREAMING ROVER: zdravo nakon mog LINUX TERMINALNOG KONTROLIRANOG ROVERA i WIFI DTMF ROBOTA KOJIMA UPRAVLJA PC, ovo je moj treći robot. i kao i druga dva ovdje, također nisam koristio nikakav mikrokontroler ili programiranje kako bi bilo jednostavno i jednostavno za napraviti. također prenosi video uživo putem WiFi -a
Kako napraviti jednostavan DTMF (ton) dekoder telefonske linije: 3 koraka
Kako napraviti jednostavan DTMF (tonski) dekoder telefonske linije: Ovo je jednostavan projekt koji vam omogućuje dekodiranje DTMF signala u osnovi bilo koje telefonske linije. U ovom vodiču koristimo dekoder MT8870D. Koristimo unaprijed ugrađeni dekoder tonova jer, vjerujte, bol je straga pokušavati to učiniti s
WIFI DTMF ROBOT: 5 koraka
WIFI DTMF ROBOT: pozdrav u ovom vodiču pokazat ću vam kako možete napraviti rover s računalom bez korištenja mikro kontrolera, što znači da u ovom projektu nema uključenog koda na visokoj razini samo trebate osnovno znanje o izradi html stranica. mogu gledati do kraja
Kako napraviti mobilnog upravljanog robota - Na temelju DTMF -a - Bez mikrokontrolera i programiranja - Kontrola s bilo kojeg mjesta u svijetu - RoboGeeks: 15 koraka
Kako napraviti mobilnog upravljanog robota | Na temelju DTMF -a | Bez mikrokontrolera i programiranja | Kontrola s bilo kojeg mjesta u svijetu | RoboGeeks: Želite napraviti robota kojim se može upravljati bilo gdje u svijetu, učinimo to
IOT detektor dima: Ažurirajte postojeći detektor dima s IOT -om: 6 koraka (sa slikama)
IOT detektor dima: Ažurirajte postojeći detektor dima s IOT -om: Popis suradnika, izumitelj: Tan Siew Chin, Tan Yit Peng, Tan Wee Heng Nadzornik: dr. Chia Kim Seng Zavod za mehatroničko i robotsko inženjerstvo, Fakultet elektrotehnike i elektronike, Sveučilište Tun Hussein Onn Malezija. Distributer