Satura rādītājs:
Video: DTMF detektors: 4 soļi
2024 Autors: John Day | [email protected]. Pēdējoreiz modificēts: 2024-01-30 10:56
Pārskats
Būvēt šo ierīci mani iedvesmoja mājas uzdevums digitālā signāla apstrādes tiešsaistes kursā. Šis ir DTMF dekodētājs, kas ieviests ar Arduino UNO, un tas rada ciparu, kas toņa režīmā tiek nospiests uz tālruņa tastatūras, pēc tā radītās skaņas.
1. darbība. Izprotiet algoritmu
DTMF sistēmā katrs simbols ir kodēts ar divām frekvencēm saskaņā ar tabulu attēlā.
Ierīce uztver mikrofona ievadi un aprēķina astoņu frekvenču amplitūdas. Divas frekvences ar maksimālo amplitūdu dod kodēta simbola rindu un kolonnu.
Datu ieguve
Lai veiktu spektra analīzi, paraugi jāuztver noteiktā paredzamā frekvencē. Lai to panāktu, es ar maksimālu precizitāti izmantoju brīvā skrējiena ADC režīmu (prescaler 128), tas nodrošina paraugu ņemšanas ātrumu 9615 Hz. Zemāk esošais kods parāda, kā konfigurēt Arduino ADC.
void initADC () {
// Init ADC; f = (16MHz/prescaler)/13 cikli/konversija ADMUX = 0; // Kanāls sel, labais-adj, izmantojiet AREF tapu ADCSRA = _BV (ADEN) | // ADC iespējot _BV (ADSC) | // ADC sākums _BV (ADATE) | // Automātiskais sprūda _BV (ADIE) | // Pārtraukšanas iespējošana _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Brīvās darbības režīms DIDR0 = _BV (0); // Izslēgt ciparu ievadi ADC tapai TIMSK0 = 0; // Taimeris0 izslēgts} Un pārtraukuma apstrādātājs izskatās šādi: ISR (ADC_vect) {uint16_t paraugs = ADC; paraugi [samplePos ++] = paraugs - 400; ja (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buferis pilns, pārtraukums izslēgts}}
Spektra analīze
Pēc paraugu savākšanas es aprēķinu 8 frekvenču amplitūdas, kas kodē simbolus. Man nav nepieciešams palaist pilnu FFT, tāpēc es izmantoju Gertzela algoritmu.
void goertzel (uint8_t *paraugi, pludiņa *spektrs) {
pludiņš v_0, v_1, v_2; pludiņš re, im, amp; par (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k]))); pludiņš s = pgm_read_float (& (sin_t [k]))); pludiņš a = 2. * c; v_0 = v_1 = v_2 = 0; par (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (pludiņš) (paraugi ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektrs [k] = amp; }}
2. darbība: kods
Iepriekš redzamajā attēlā parādīts 3. ciparu kodēšanas piemērs, kur maksimālā amplitūda atbilst frekvencēm 697 Hz un 1477 Hz.
Pilna skice izskatās šādi
/** * Savienojumi: * [Mic to Arduino] * - Out -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Display to Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include
#iekļaut
#define CS_PIN 9
#definēt N 256
#define IX_LEN 8 #define THRESHOLD 20
LEDMatrixDriver lmd (1, CS_PIN);
uint8_t paraugi [N];
gaistošs uint16_t samplePos = 0;
pludiņa spektrs [IX_LEN];
// Frekvences [697,0, 770,0, 852,0, 941,0, 1209,0, 1336,0, 1477,0, 1633,0]
// Aprēķināts 9615 Hz 256 paraugiem const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.634393284163645619566056 const float sin_t [IX_LEN] PROGMĒMA = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.8314696123025456 0.48
typedef structure {
char cipars; indekss uint8_t; } ciparu_t;
ciparu_t atklāts_cipars;
const char tabula [4] [4] PROGMĒMA = {
{'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', '' C '}, {'*',' 0 ','#',' D '}};
const uint8_t char_indexes [4] [4] PROGMĒMA = {
{1, 2, 3, 10}, {4, 5, 6, 11}, {7, 8, 9, 12}, {15, 0, 14, 13} };
baitu fonts [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 () {
// Sākotnējais ADC; f = (16MHz/prescaler)/13 cikli/konversija ADMUX = 0; // Kanāls sel, labais-adj, izmantojiet AREF tapu ADCSRA = _BV (ADEN) | // ADC iespējot _BV (ADSC) | // ADC sākums _BV (ADATE) | // Automātiskais sprūda _BV (ADIE) | // Pārtraukšanas iespējošana _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Brīvās darbības režīms DIDR0 = _BV (0); // Izslēgt ciparu ievadi ADC tapai TIMSK0 = 0; // Taimeris0 izslēgts}
void goertzel (uint8_t *paraugi, pludiņa *spektrs) {
pludiņš v_0, v_1, v_2; pludiņš re, im, amp; par (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k]))); pludiņš s = pgm_read_float (& (sin_t [k]))); pludiņš a = 2. * c; v_0 = v_1 = v_2 = 0; par (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (pludiņš) (paraugi ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); spektrs [k] = amp; }}
float avg (float *a, uint16_t len) {
pludiņa rezultāts =.0; par (uint16_t i = 0; i <len; i ++) {rezultāts+= a ; } atgriešanās rezultāts / len; }
int8_t get_single_index_above_threshold (pludiņš *a, uint16_t len, pludiņa slieksnis) {
if (slieksnis <THRESHOLD) {return -1; } int8_t ix = -1; par (uint16_t i = 0; i slieksnis) {ja (ix == -1) {ix = i; } cits {atgriezties -1; }}} atgriezties ix; }
void detect_digit (pludiņa *spektrs) {
peldēt avg_row = avg (spektrs, 4); pludiņš avg_col = avg (& spektrs [4], 4); int8_t rinda = get_single_index_above_threshold (spektrs, 4, avg_row); int8_t col = get_single_index_above_threshold (& spektrs [4], 4, avg_col); ja (rinda! = -1 && col! = -1 && avg_col> 200) {atklāts_cipars.cipars = pgm_read_byte (& (tabula [rinda] [kolonna])); atklāts_digits.index = pgm_read_byte (& (char_indexes [rinda] [kol.])); } cits {atklāts_cipars.cipars = 0; }}
void drawSprite (baits* sprite) {
// Maska tiek izmantota, lai iegūtu kolonnas bitu no sprite rindas baitu maskas = B10000000; par (int iy = 0; iy <8; iy ++) {par (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));
// pārbīdiet masku par vienu pikseļu pa labi
maska = maska >> 1; }
// atiestatīt kolonnu masku
maska = B10000000; }}
void setup () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (true); lmd.setIntensity (2); lmd.clear (); lmd.display ();
atklāts_cipars.cipars = 0;
}
neparakstīts garais z = 0;
void loop () {
kamēr (ADCSRA & _BV (ADIE)); // Pagaidiet, līdz audio paraugu ņemšana pabeigs goertzel (paraugi, spektrs); atklāt_ciparu (spektrs);
ja (atklāts_cipars.cipars! = 0) {
drawSprite (fonts [atklāts_ciparu.indekss]); lmd.display (); } ja (z % 5 == 0) {par (int i = 0; i <IX_LEN; i ++) {Sērijas nospiedums (spektrs ); Serial.print ("\ t"); } Sērijas.println (); Serial.println ((int) atklāts_cipars.cipars); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Atsākt paraugu ņemšanas pārtraukšanu
}
ISR (ADC_vect) {
uint16_t paraugs = ADC;
paraugi [samplePos ++] = paraugs - 400;
ja (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Buferis pilns, pārtraukums izslēgts}}
3. darbība. Shēmas
Jāizveido šādi savienojumi:
Mikrofons Arduino
Ārā -> A0
Vcc -> 3.3V Gnd -> Gnd
Ir svarīgi savienot AREF ar 3.3V
Parādiet Arduino
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
4. solis. Secinājums
Ko šeit varētu uzlabot? Es izmantoju N = 256 paraugus ar frekvenci 9615Hz, kam ir zināma spektra noplūde, ja N = 205 un ātrums ir 8000Hz, tad vēlamās frekvences sakrīt ar diskretizācijas režģi. Šim nolūkam ADC jāizmanto taimera pārpildes režīmā.
Ieteicams:
Ūdens līmeņa detektors: 7 soļi
Ūdens līmeņa detektors: Ultraskaņas sensors darbojas pēc tādiem pašiem principiem kā radara sistēma. Ultraskaņas sensors var pārveidot elektroenerģiju akustiskos viļņos un otrādi. Slavenais ultraskaņas sensors HC SR04 ģenerē ultraskaņas viļņus 40 kHz frekvencē
Zigbee gultas klātbūtnes detektors: 8 soļi
Zigbija gultas klātbūtnes detektors: Jau kādu laiku es meklēju veidu, kā noteikt, kad esam gultā. Tas paredzēts šīs informācijas izmantošanai mājas palīgā. Izmantojot šo informāciju, es varētu izveidot automātiku gaismas izslēgšanai naktī vai, piemēram, aktivizēt trauksmes sistēmu savā mājā
Dūmu detektors: 13 soļi
Dūmu detektors: Sveiki draugi, šodien apskatīsim par dūmu detektoru Daudzi no jums gāja tirdzniecības centros lielveikalos, galvenokārt jūs varat redzēt šo ierīci, ko sauc par dūmu detektoru, tā noteiks dūmus un ieslēgs smidzinātāju un apturēs uguni. Bet šajā projektā tas ir nelielas izmaiņas tā vietā
Pašreizējais kratīšanas detektors: 3 soļi
Pašreizējā kratīšanas detektors: Šajā projektā mēs izgatavosim ierīci, kas atskaņos trauksmi, ja kāds sakratīs dāvanu/kastīti. Šī ideja man radās, kad pa pastu saņēmām Ziemassvētku paciņu. Lai mēģinātu uzminēt, kas tajā bija, protams, mēs to satricinājām tāpat kā visi
Projeto IoT - Sistēmas detektors De Fumaça: 5 soļi
Projeto IoT - Sistēmas detektors De Fumaça: Ievads Sistēmas detektors Fumaça sastāv no katra risinājuma IoT com vai objetivo de atļauju vai monitoramento de alarmmes de incêndio de residências através de um applicativo Android. O projeto é baseado em um microcontrolador que se comunica com a nu