Orodha ya maudhui:

Kigunduzi cha DTMF: Hatua 4
Kigunduzi cha DTMF: Hatua 4

Video: Kigunduzi cha DTMF: Hatua 4

Video: Kigunduzi cha DTMF: Hatua 4
Video: ESP32 Tutorial 3 - Resistor, LED, Bredboard and First Project: Hello LED -ESP32 IoT Learnig kit 2024, Julai
Anonim
Image
Image

Maelezo ya jumla

Nilivutiwa kujenga kifaa hiki na mgawo wa nyumbani kwenye kozi mkondoni ya Usindikaji wa Ishara ya Dijiti. Hii ni kiboreshaji cha DTMF kilichotekelezwa na Arduino UNO, hugundua nambari iliyobanwa kwenye kitufe cha simu katika modi ya sauti na sauti inayozalisha.

Hatua ya 1: Kuelewa Algorithm

Kanuni
Kanuni

Katika DTMF kila ishara imesimbwa na masafa mawili kulingana na meza kwenye picha.

Kifaa hicho kinachukua pembejeo kutoka kwa kipaza sauti na huhesabu amplitudes ya masafa nane. Masafa mawili na amplitudes ya kiwango cha juu hutoa safu na safu ya ishara iliyosimbwa.

Upataji wa data

Ili kufanya sampuli za uchambuzi wa wigo zinapaswa kukamatwa kwa masafa fulani ya kutabirika. Ili kufanikisha hili nilitumia hali ya bure ya kukimbia ADC na usahihi wa juu (prescaler 128) inatoa kiwango cha sampuli 9615Hz. Nambari hapa chini inaonyesha jinsi ya kusanidi ADC ya Arduino.

batili initADC () {

// Init ADC; f = (16MHz / prescaler) / mizunguko 13 / ubadilishaji ADMUX = 0; // Channel sel, kulia-adj, tumia pini ya AREF ADCSRA = _BV (ADEN) | // ADC kuwezesha _BV (ADSC) | // ADC kuanza _BV (ADATE) | // Kichocheo cha moja kwa moja _BV (ADIE) | // Kukatiza kuwezesha _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Njia ya kukimbia bure DIDR0 = _BV (0); // Zima uingizaji wa dijiti kwa pini ya ADC TIMSK0 = 0; // Timer0 off} Na kidhibiti cha kukatiza kinaonekana kama ISR (ADC_vect) {uint16_t sample = ADC; sampuli [samplePos ++] = sampuli - 400; ikiwa (sampuliPos> = N) {ADCSRA & = ~ _BV (ADIE); // Bafa imejaa, usumbue}}

Uchambuzi wa wigo

Baada ya kukusanya sampuli mimi huhesabu amplitudes ya alama 8 za encoding. Sina haja ya kukimbia FFT kamili kwa hili, kwa hivyo nilitumia algorithm ya Goertzel.

batili goertzel (sampuli uint8_t *, kuelea * wigo) {

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

Hatua ya 2: Kanuni

Picha hapo juu inaonyesha mfano wa usimbuaji wa nambari 3 ambapo kiwango cha juu kinalingana na masafa 697Hz na 1477Hz.

Mchoro kamili unaonekana kama ifuatavyo

/ ** * Maunganisho: * [Mic hadi Arduino] * - Kati -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Onyesha kwa Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 * / # pamoja na # pamoja

# pamoja

#fafanua CS_PIN 9

#fafanua N 256

#fafanua IX_LEN 8 #fafanua THRESHOLD 20

LEDMatrixDriver lmd (1, CS_PIN);

sampuli za uint8_t [N];

sampuli uint16_t sampuliPos = 0;

wigo wa kuelea [IX_LEN];

// Masafa [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]

// Imehesabiwa kwa sampuli za 9615Hz 256 const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.6343932846836556836536536536536556 const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.83146964830191211211

typedef struct {

nambari ya char; faharisi ya uint8_t; } tarakimu_t;

digit_t detected_digit;

jedwali la const char [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} };

fonti baiti [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, 0x4 }, // 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} // *};

batili initADC () {

// Init ADC; f = (16MHz / prescaler) / mizunguko 13 / ubadilishaji ADMUX = 0; // Channel sel, kulia-adj, tumia pini ya AREF ADCSRA = _BV (ADEN) | // ADC kuwezesha _BV (ADSC) | // ADC kuanza _BV (ADATE) | // Kichocheo cha moja kwa moja _BV (ADIE) | // Kukatiza kuwezesha _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // Njia ya kukimbia bure DIDR0 = _BV (0); // Zima uingizaji wa dijiti kwa pini ya ADC TIMSK0 = 0; // Timer0 imezimwa}

batili goertzel (sampuli uint8_t *, kuelea * wigo) {

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

kuelea wastani (kuelea * a, uint16_t len) {

matokeo ya kuelea =.0; kwa (uint16_t i = 0; i <len; i ++) {matokeo + = a ; } matokeo ya kurudi / len; }

int8_t kupata_single_index_above_ kizingiti (kuelea * a, uint16_t len, kizingiti cha kuelea) {

ikiwa (kizingiti <THRESHOLD) {kurudi -1; } int8_t ix = -1; kwa (uint16_t i = 0; kizingiti) {if (ix == -1) {ix = i; } mwingine {kurudi -1; }}} kurudi ix; }

batili detect_digit (kuelea * wigo) {

kuelea avg_row = wastani (wigo, 4); kuelea avg_col = wastani (& wigo [4], 4); mstari8 int int8_t col = pata_single_index_above_ kizingiti (& wigo [4], 4, avg_col); ikiwa (safu! = -1 && col! = -1 && avg_col> 200) {detected_digit.digit = pgm_read_byte (& (meza [safu] [col])); detected_digit.index = pgm_read_byte (& (char_indexes [safu] [col])); } mwingine {detected_digit.digit = 0; }}

utupu wa kutekaSprite (byte * sprite) {

// kinyago kinatumiwa kupata safu kidogo kutoka kwa kinyago cha safu ya sprite = B10000000; kwa (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));

// songa kinyago kwa pikseli moja kulia

kinyago = kinyago >> 1; }

// kuweka tena kinyago cha safu

mask = B10000000; }}

usanidi batili () {

cli (); initADC (); jinsi ();

Serial. Kuanza (115200);

imewezeshwa (kweli); Uwezo wa lmd.set (2); lmd safi (); onyesho la lmd ();

detected_digit.digit = 0;

}

saini ndefu z = 0;

kitanzi batili () {

wakati (ADCSRA & _BV (ADIE)); // Subiri sampuli ya sauti kumaliza goertzel (sampuli, wigo); detect_digit (wigo);

ikiwa (detected_digit.digit! = 0) {

DrawSprite (font [detected_digit.index]); onyesho la lmd (); } ikiwa (z% 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (wigo ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) imetambuliwa_digit.digit); } z ++;

sampuliPos = 0;

ADCSRA | = _BV (ADIE); // Endelea sampuli kukatiza

}

ISR (ADC_vect) {

uint16_t sampuli = ADC;

sampuli [sampuliPos ++] = sampuli - 400;

ikiwa (sampuliPos> = N) {ADCSRA & = ~ _BV (ADIE); // Bafa imejaa, usumbue}}

Hatua ya 3: Skematiki

Skimatiki
Skimatiki

Viunganisho vifuatavyo vinapaswa kufanywa:

Mic kwa Arduino

Nje -> A0

Vcc -> 3.3V Gnd -> Gnd

Ni muhimu kuunganisha AREF kwa 3.3V

Onyesha kwa Arduino

Vcc -> 5V

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

Hatua ya 4: Hitimisho

Ni nini kinachoweza kuboreshwa hapa? Nilitumia sampuli za N = 256 kwa kiwango cha 9615Hz ambacho kina uvujaji wa wigo, ikiwa N = 205 na kiwango ni 8000Hz basi masafa yanayotakiwa yanapatana na gridi ya hiari. Kwa ADC hiyo inapaswa kutumika katika hali ya kufurika kwa timer.

Ilipendekeza: