Orodha ya maudhui:
Video: Kigunduzi cha DTMF: Hatua 4
2024 Mwandishi: John Day | [email protected]. Mwisho uliobadilishwa: 2024-01-30 12:53
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
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
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:
Kigunduzi cha Kiwango cha Maji: Hatua 7
Kigunduzi cha Kiwango cha Maji: Sensor ya ultrasonic inafanya kazi kwa kanuni sawa na mfumo wa rada. Sensorer ya ultrasonic inaweza kubadilisha nishati ya umeme kuwa mawimbi ya acoustic na kinyume chake. Sensor maarufu ya HC SR04 inazalisha mawimbi ya ultrasonic katika frequency 40kHz.Typica
Kigunduzi cha Uwepo wa Kitanda cha Zigbee: Hatua 8
Kigunduzi cha Uwepo wa Kitanda cha Zigbee: Kwa muda sasa nilikuwa nikitafuta njia ya kugundua tukiwa kitandani. Hii kwa kutumia habari hii kwa Homeassistant. Kwa habari hii ningeweza kutengeneza mitambo ya kuzima taa usiku au kwa mfano kuwezesha mfumo wa kengele katika ho yangu
Kigunduzi cha sasa cha Kutetereka: Hatua 3
Kigunduzi cha Kutetereka cha Sasa: Katika mradi huu tutatengeneza kifaa ambacho kitapiga kengele ikiwa mtu atatikisa zawadi / sanduku. Nilipata wazo hili wakati tulipata kifurushi kwa barua kwa Krismasi. Kujaribu na kukisia ni nini kilikuwa ndani yake, kwa kweli tuliitikisa kama kila mtu anavyofanya
Kigunduzi cha Kiwango cha Nuru cha LDR: Kufungua na Kufumba Macho: Hatua 6
Kigunduzi cha Kiwango cha Mwanga cha LDR: Kufungua na Kufumba Macho: Halo kila mtu, natumai hii inaweza kufundishwa. Shaka yoyote, maoni au marekebisho yatapokelewa vizuri.Mzunguko huu uligunduliwa kama moduli ya kudhibiti ili kutoa habari juu ya nuru kiasi gani katika mazingira, ili kushirikiana
Kigunduzi cha Chuma cha Urafiki cha Eco - Arduino: Hatua 8 (na Picha)
Kigunduzi cha Urafiki wa Chuma cha Eco - Arduino: Kugundua Chuma ni raha nyingi. Moja ya changamoto ni kuweza kupunguza mahali halisi pa kuchimba ili kupunguza ukubwa wa shimo lililoachwa nyuma. Kigunduzi hiki cha kipekee cha chuma kina kozi nne za utaftaji, skrini ya kugusa rangi ili kubaini na kubainisha lo