Sadržaj:
Video: DTMF detektor: 4 koraka
2024 Autor: John Day | [email protected]. Zadnja izmjena: 2024-01-30 08:07
Pregled
Za izradu ovog uređaja inspirirao me domaći zadatak na online kursu Digitalna obrada signala. Ovo je DTMF dekoder implementiran sa Arduino UNO, on detektuje cifru pritisnutu na tastaturi telefona u tonskom režimu zvukom koji proizvodi.
Korak 1: Razumevanje algoritma
U DTMF -u je svaki simbol kodiran s dvije frekvencije prema tablici na slici.
Uređaj snima ulaz sa 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 treba uhvatiti na određenoj predvidljivoj frekvenciji. Da bih to postigao, koristio sam ADC način rada sa maksimalnom preciznošću (predskaler 128) koji daje frekvenciju uzorkovanja 9615Hz. Donji kod prikazuje kako konfigurirati Arduino ADC.
void initADC () {
// Init 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 start _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); // Bafer 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) {
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])); 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: Kodeks
Na gornjoj slici prikazan je primjer kodiranja znamenke 3 gdje maksimalna amplituda odgovara frekvencijama 697Hz i 1477Hz.
Kompletna skica izgleda ovako
/** * Priključci: * [Mikrofon na Arduino] * - Izlaz -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Prikaz na Arduinu] * - 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 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 {
znak znamenke; uint8_t indeks; } digit_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 bajta [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 () {
// Init 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 start _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; // Tajmer0 isključen}
void goertzel (uint8_t *uzorci, float *spektar) {
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])); 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 ; } return result / len; }
int8_t get_single_index_above_threshold (float *a, uint16_t len, float prag) {
if (prag <THRESHOLD) {return -1; } int8_t ix = -1; za (uint16_t i = 0; i prag) {if (ix == -1) {ix = i; } else {return -1; }}} return ix; }
void detektiraj_digit (float *spektar) {
float avg_row = avg (spektar, 4); float avg_col = avg (& spektar [4], 4); int8_t red = 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 (& (tabela [red] [col])); otkriven_digit.index = pgm_čitani_bajt (& (char_indexes [red] [col])); } else {otkrivena_digit.digit = 0; }}
void drawSprite (byte* sprite) {
// Maska se koristi za dobivanje bita kolone 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; }
// poništavanje maske kolone
maska = B10000000; }}
void setup () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (true); lmd.setIntensity (2); lmd.clear (); lmd.display ();
otkrivena_digit.digit = 0;
}
nepotpisano dugo z = 0;
void loop () {{100} {101}
while (ADCSRA & _BV (ADIE)); // Sač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) detection_digit.digit); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Nastavak prekida uzorkovanja
}
ISR (ADC_vect) {
uint16_t uzorak = ADC;
uzorci [samplePos ++] = uzorak - 400;
if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Bafer pun, prekid isključen}}
Korak 3: Sheme
Treba uspostaviti sljedeće veze:
Mikrofon na Arduino
Izlaz -> A0
Vcc -> 3.3V 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
Šta bi se tu moglo poboljšati? Koristio sam N = 256 uzoraka pri brzini 9615Hz koja ima neko curenje u spektru, ako je N = 205 i brzina je 8000Hz tada se željene frekvencije podudaraju s diskrecijskom mrežom. Za to bi ADC trebao biti korišten u modu preljevanja timera.
Preporučuje se:
DTMF VIDEO STREAMING ROVER: 3 koraka
DTMF VIDEO STREAMING ROVER: zdravo nakon mog LINUX TERMINALNOG UPRAVLJANOG ROVERA I WIFI DTMF PC KONTROLIRANOG ROBOTA Ovo je moj treći robot. i kao i druga dva ovdje, također nisam koristio nikakav mikrokontroler ili programiranje da bi bilo jednostavno i jednostavno za napraviti. također prenosi video uživo putem WiFi -a
Kako napraviti jednostavan DTMF (tonski) 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: zdravo u ovom vodiču pokazat ću vam kako možete napraviti računalno upravljani rover bez korištenja mikro kontrolera, što znači da u ovom projektu nije uključen kôd na visokom nivou, samo vam je potrebno osnovno znanje o izradi html stranice. mogu gledati do kraja
Kako napraviti mobilnog robota pod kontrolom - DTMF baziran - Bez mikrokontrolera i programiranja - Kontrola sa bilo kojeg mjesta u svijetu - RoboGeeks: 15 koraka
Kako napraviti mobilnog robota pod kontrolom | DTMF baziran | Bez mikrokontrolera i programiranja | Kontrola sa 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 sa IOT -om: 6 koraka (sa slikama)
IOT detektor dima: Ažurirajte postojeći detektor dima sa IOT -om: Spisak saradnika, izumitelj: Tan Siew Chin, Tan Yit Peng, Tan Wee Heng Nadzornik: Dr Chia Kim Seng Odsjek za mehatroničko i robotsko inženjerstvo, Fakultet elektrotehnike i elektronike, Univerzitet Tun Hussein Onn Malaysia.Distribut