Բովանդակություն:
Video: DTMF դետեկտոր ՝ 4 քայլ
2024 Հեղինակ: John Day | [email protected]. Վերջին փոփոխված: 2024-01-30 09:49
Ակնարկ
Այս սարքը ստեղծելու համար ինձ ոգեշնչեց թվային ազդանշանի մշակման առցանց դասընթացի տնային առաջադրանքը: Սա DTMF- ի ապակոդավորիչ է, որն իրականացվել է Arduino UNO- ի հետ: Այն ձայնային ստեղնաշարի վրա սեղմված թվանշանը հայտնաբերում է հնչերանգի ռեժիմում `դրա արտադրած ձայնով:
Քայլ 1. Ալգորիթմի իմացություն
DTMF- ում յուրաքանչյուր խորհրդանիշ կոդավորված է երկու հաճախականությամբ `ըստ նկարի աղյուսակի:
Սարքը գրավում է խոսափողի մուտքը և հաշվարկում ութ հաճախականությունների ամպլիտուդներ: Առավելագույն ամպլիտուդներով երկու հաճախականություններ տալիս են կոդավորված խորհրդանիշի տող և սյունակ:
Տվյալների ձեռքբերում
Սպեկտրի վերլուծություն կատարելու համար նմուշները պետք է վերցվեն որոշակի կանխատեսելի հաճախականությամբ: Դրան հասնելու համար ես օգտագործեցի անվճար գործարկվող ADC ռեժիմը առավելագույն ճշգրտությամբ (նախալեզվիչ 128), որը տալիս է նմուշառման արագություն 9615 Հց: Ստորև բերված ծածկագիրը ցույց է տալիս, թե ինչպես կարգավորել Arduino- ի ADC- ն:
void initADC () {
// Init ADC; f = (16 ՄՀց/նախալեզվիչ)/13 ցիկլ/փոխակերպում ADMUX = 0; // Channel sel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // ADC միացնել _BV (ADSC) | // ADC սկիզբ _BV (ADATE) | // Ավտոմատ ձգան _BV (ADIE) | // Ընդհատել միացնել _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Հց ADCSRB = 0; // Անվճար գործարկման ռեժիմ DIDR0 = _BV (0); // Անջատել թվային մուտքագրումը ADC կապի համար TIMSK0 = 0; // erամաչափը անջատված է} Եվ ընդհատումների կարգավորիչը նման է այս ISR (ADC_vect) {uint16_t sample = ADC; sample [samplePos ++] = sample - 400; եթե (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Բուֆերն ամբողջությամբ, ընդհատումը անջատված է}}
Սպեկտրի վերլուծություն
Նմուշներ հավաքելուց հետո ես հաշվարկում եմ 8 հաճախականությունների ամպլիտուդներ, որոնք ծածկագրում են խորհրդանիշներ: Ես դրա համար կարիք չունեմ լրիվ FFT գործարկելու, այնպես որ ես օգտագործեցի Գոերտցելի ալգորիթմը:
void goertzel (uint8_t *նմուշներ, float *սպեկտր) {
բոց v_0, v_1, v_2; float re, im, amp; համար (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k]))); float s = pgm_read_float (& (sin_t [k])); բոց a = 2. * c; v_0 = v_1 = v_2 = 0; համար (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (բոց) (նմուշներ ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); սպեկտրը [k] = ուժեղացուցիչ; }}
Քայլ 2: Կոդ
Վերը նկարը ցույց է տալիս 3 -րդ թվանշանի կոդավորման օրինակը, որտեղ առավելագույն ամպլիտուդը համապատասխանում է 697 Հց և 1477 Հց հաճախականություններին:
Ամբողջական ուրվագիծը հետևյալն է
/** * Միացումներ. * [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 */ #ներառել #ներառել
#ներառում
#սահմանել CS_PIN 9
#սահմանի N 256
#սահմանել IX_LEN 8 #սահմանել THRESHOLD 20
LEDMatrixDriver lmd (1, CS_PIN);
uint8_t նմուշներ [N];
անկայուն uint16_t samplePos = 0;
բոց սպեկտր [IX_LEN];
// Հաճախականություններ [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]
// Հաշվարկված 9615 Հց 256 նմուշների համար const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.6343963985, 0.634396393, 0.634396393, 0.63439.36393, 0.63439. const float sin_t [IX_LEN] GՐԱԳԻՐ = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.831914696, 0.831914696, 0.831914696, 0.831914696, 0.831914696, 0.831914696, 0.831914696, 0.831914696, 0.831914696, 0.831912696, 0.83191469
typedef struct {
տառանշան; uint8_t ինդեքս; } թվանշան_թ;
թվանշան_ հայտնաբերված_ թվանշան;
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} };
բայթ տառատեսակ [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, 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 = (16 ՄՀց/նախալեզվիչ)/13 ցիկլ/փոխակերպում ADMUX = 0; // Channel sel, right-adj, use AREF pin ADCSRA = _BV (ADEN) | // ADC միացնել _BV (ADSC) | // ADC սկիզբ _BV (ADATE) | // Ավտոմատ ձգան _BV (ADIE) | // Ընդհատել միացնել _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1 /13 = 9615 Հց ADCSRB = 0; // Անվճար գործարկման ռեժիմ DIDR0 = _BV (0); // Անջատել թվային մուտքագրումը ADC կապի համար TIMSK0 = 0; // erամաչափը անջատված է}
void goertzel (uint8_t *նմուշներ, float *սպեկտր) {
բոց v_0, v_1, v_2; float re, im, amp; համար (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k]))); float s = pgm_read_float (& (sin_t [k])); բոց a = 2. * c; v_0 = v_1 = v_2 = 0; համար (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (բոց) (նմուշներ ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); սպեկտրը [k] = ուժեղացուցիչ; }}
բոց միջին (float *a, uint16_t len) {
բոց արդյունքը =.0; համար (uint16_t i = 0; i <len; i ++) {result+= a ; } վերադարձի արդյունք / լեն; }
int8_t get_single_index_above_threshold (float *a, uint16_t len, float threshold) {
եթե (շեմը <THRESHOLD) {վերադարձ -1; } int8_t ix = -1; համար (uint16_t i = 0; i շեմ) {if (ix == -1) {ix = i; } else {վերադարձ -1; }}} վերադարձ ix; }
դատարկ dete_digit (float *spectrum) {
բոց avg_row = միջին (սպեկտր, 4); բոց avg_col = միջին (& սպեկտր [4], 4); int8_t տող = get_single_index_above_threshold (սպեկտր, 4, avg_row); int8_t col = get_single_index_above_threshold (& spectrum [4], 4, avg_col); if (տող! = -1 && col! = -1 && avg_col> 200) {dete_digit.digit = pgm_read_byte (& (աղյուսակ [տող] [col])); dete_digit.index = pgm_read_byte (& (char_indexes [տող] [col])); } else {dete_digit.digit = 0; }}
void drawSprite (բայթ* sprite) {
// Դիմակը օգտագործվում է սփրեյթ շարքի բայթ դիմակի սյունակի բիթը ստանալու համար = B10000000; համար (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & դիմակ));
// դիմակը մեկ պիքսելով տեղափոխել աջ
դիմակ = դիմակ >> 1; }
// վերականգնել սյունակի դիմակը
դիմակ = B10000000; }}
void setup () {
cli (); initADC (); sei ();
Serial.begin (115200);
lmd.setEnabled (ճշմարիտ); lmd.setIntensity (2); lmd. հստակ (); lmd.display ();
dete_digit.digit = 0;
}
անստորագիր երկար z = 0;
դատարկ շրջան () {
իսկ (ADCSRA & _BV (ADIE)); // Սպասեք աուդիո նմուշառման ավարտին goertzel (նմուշներ, սպեկտր); dete_digit (սպեկտր);
եթե (dete_digit.digit! = 0) {
drawSprite (տառատեսակ [dete_digit.index]); lmd.display (); } if (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (սպեկտրը ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) dete_digit.digit); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Վերսկսել ընտրանքի ընդհատումը
}
ISR (ADC_vect) {
uint16_t նմուշ = ADC;
նմուշներ [samplePos ++] = նմուշ - 400;
եթե (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Բուֆերն ամբողջությամբ, ընդհատումը անջատված է}}
Քայլ 3: Սխեմաներ
Հետևյալ կապերը պետք է կատարվեն.
Խոսափողը Arduino- ին
Դուրս -> A0
Vcc -> 3.3V Gnd -> Gnd
Կարևոր է AREF- ը միացնել 3.3 Վ -ին:
Displayուցադրել Arduino- ին
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Քայլ 4: Եզրակացություն
Ի՞նչը կարելի է բարելավել այստեղ: Ես օգտագործել եմ N = 256 նմուշ 9615 Հց արագությամբ, որն ունի որոշակի սպեկտրի արտահոսք, եթե N = 205 և արագությունը 8000 Հց է, ապա ցանկալի հաճախականությունները համընկնում են դիսկրետացիոն ցանցի հետ: Դրա համար ADC- ն պետք է օգտագործվի ժմչփի արտահոսքի ռեժիմում:
Խորհուրդ ենք տալիս:
Raspberry Pi - TMD26721 ինֆրակարմիր թվային հարևանության դետեկտոր Java ձեռնարկ. 4 քայլ
Raspberry Pi-TMD26721 Ինֆրակարմիր թվային հարևանության դետեկտոր Java ձեռնարկ: ճշգրտություն. Պրո
Zigbee անկողնու ներկայության դետեկտոր ՝ 8 քայլ
Zigbee Bed Presence Detector: Որոշ ժամանակ ես փնտրում էի միջոց ՝ պարզելու, թե երբ ենք անկողնում: Սա `այս տեղեկատվությունը Homeassistant- ում օգտագործելու համար: Այս տեղեկատվության շնորհիվ ես կարող եմ ավտոմատներ սարքել գիշերը լույսերը անջատելու համար կամ, օրինակ, ազդանշանային համակարգ ակտիվացնել
Smխի դետեկտոր ՝ 13 քայլ
Okeխի դետեկտոր. Բարև ընկերներ, այսօր եկեք տեսնենք ծխի դետեկտորի մասին: Ձեզանից շատերը գնացինք առևտրի կենտրոններ, հիմնականում դուք կարող եք տեսնել այս սարքը, որը կոչվում է ծխի դետեկտոր: այն կբացահայտի ծուխը և կմիացնի ցնցուղը և կդադարեցնի կրակը: Բայց այս նախագծում դա փոքր փոփոխություն է: փոխարենը
Ներկա ցնցումների դետեկտոր `3 քայլ
Present Shake Detector: Այս նախագծում մենք պատրաստվում ենք սարք պատրաստել, որը ահազանգ կհնչի, եթե ինչ -որ մեկը թափի նվերը/տուփը: Այս գաղափարն ունեցա, երբ Սուրբ Christmasննդյան տոների համար փաթեթ ստացանք: Փորձելու և կռահելու համար, թե ինչ կար դրա մեջ, իհարկե, մենք այն ցնցեցինք այնպես, ինչպես բոլորը
Անձրևի դետեկտոր ՝ օգտագործելով Arduino և անձրևի տվիչ ՝ 8 քայլ
Անձրևի դետեկտոր ՝ օգտագործելով Arduino և Raindrop Sensor: Այս ձեռնարկում մենք կսովորենք, թե ինչպես կարելի է անձրևը հայտնաբերել անձրևի սենսորի միջոցով և ձայն արձակել ՝ օգտագործելով ազդանշանային մոդուլը և OLED էկրանը և Visuino- ն: Դիտեք տեսանյութը