Агуулгын хүснэгт:
Видео: DTMF илрүүлэгч: 4 алхам
2024 Зохиолч: John Day | [email protected]. Хамгийн сүүлд өөрчлөгдсөн: 2024-01-30 11:04
Тойм
Дижитал дохио боловсруулах онлайн хичээл дээр гэрийн даалгавар өгөхөд би энэ төхөөрөмжийг бүтээх санаа авсан юм. Энэ бол DTMF декодер бөгөөд Arduino UNO -той хамтран ажилладаг бөгөөд гар утасны товчлуур дээр дарагдсан цифрийг дууны горимоор нь илрүүлдэг.
Алхам 1: Алгоритмыг ойлгох
DTMF -д тэмдэг тус бүрийг зурган дээрх хүснэгтийн дагуу хоёр давтамжаар кодлодог.
Төхөөрөмж нь микрофоны оролтыг авч, найман давтамжийн далайцыг тооцоолно. Хамгийн их далайцтай хоёр давтамж нь кодлогдсон тэмдгийн мөр, баганыг өгдөг.
Мэдээлэл олж авах
Спектрийн шинжилгээ хийхийн тулд дээжийг урьдчилан таамаглах боломжтой давтамжтайгаар авах ёстой. Үүнд хүрэхийн тулд би ADC горимыг хамгийн нарийвчлалтайгаар (prescaler 128) ашиглан ашигласан бөгөөд энэ нь 9615 Гц дээж авах хурдыг өгдөг. Доорх код нь Arduino -ийн ADC -ийг хэрхэн тохируулахыг харуулж байна.
хүчингүй initADC () {
// ADC -ийг эхлүүлэх; f = (16MHz/prescaler)/13 цикл/хувиргах ADMUX = 0; // Channel sel, right-adj, 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; // Timer0 унтраалттай} Тэгээд тасалдлын зохицуулагч нь ийм ISR (ADC_vect) {uint16_t sample = ADC; sample [samplePos ++] = sample - 400; if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Буфер дүүрсэн, тасалдал унтарсан}}
Спектрийн шинжилгээ
Дээж цуглуулсны дараа би тэмдэглэгээг кодлох 8 давтамжийн далайцыг тооцоолов. Үүнийг хийхийн тулд би бүрэн FFT ажиллуулах шаардлагагүй тул Goertzel -ийн алгоритмыг ашигласан.
хүчингүй гөрөөл (uint8_t *дээж, хөвөх *спектр) {
хөвөх 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])); хөвөх a = 2. * c; v_0 = v_1 = v_2 = 0; for (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (хөвөх) (дээж ) + a * v_1 - v_0; } дахин = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); спектр [k] = өсгөгч; }}
Алхам 2: Код
Дээрх зураг нь хамгийн их далайц нь 697 Гц ба 1477 Гц давтамжтай тохирч байгаа 3 -р оронтой кодчиллын жишээг харуулж байна.
Бүрэн ноорог дараах байдлаар харагдаж байна
/** * Холболтууд: * [Micro to Arduino] * - Out -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Arduino руу харуулах] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include
#оруулах
#CS_PIN 9 -ийг тодорхойлох
#тодорхойлох N 256
#тодорхойлох IX_LEN 8 #ТОГТООХ БУУДАЛ 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.68954054473706396236666666666666666868 const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654, 0.49289819222978404, 0.5349976198870972, 0.5956993044924334, 0.7242470829514669, 0.7730104533627369, 0.7730104533627369, 0.7730104533627369
typedef бүтэц {
char цифр; uint8_t индекс; } digit_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, 0x18, 0x04, 0x44, 0x38 }, // 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} // *};
хүчингүй initADC () {
// ADC -ийг эхлүүлэх; f = (16MHz/prescaler)/13 цикл/хувиргах ADMUX = 0; // Channel sel, right-adj, 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; // Таймер0 унтраалттай}
хоосон хөөмий (uint8_t *дээж, хөвөх *спектр) {
хөвөх 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])); хөвөх a = 2. * c; v_0 = v_1 = v_2 = 0; for (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (хөвөх) (дээж ) + a * v_1 - v_0; } дахин = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); спектр [k] = өсгөгч; }}
хөвөх дундаж (float *a, uint16_t len) {
хөвөх үр дүн =.0; for (uint16_t i = 0; i <len; i ++) {үр дүн+= a ; } үр дүнг буцаах / len; }
int8_t get_single_index_above_threshold (float *a, uint16_t len, float босго) {
if (босго <БОНГО) {буцах -1; } int8_t ix = -1; for (uint16_t i = 0; i босго) {if (ix == -1) {ix = i; } өөр {буцах -1; }}} ix буцаах; }
хүчин төгөлдөр бус илрүүлэх_дигит (хөвөх *спектр) {
хөвөх avg_row = дундаж (спектр, 4); float avg_col = avg (& спектр [4], 4); int8_t row = get_single_index_above_threshold (спектр, 4, дундаж_хаг); int8_t col = get_single_index_above_threshold (& спектр [4], 4, avg_col); хэрэв (мөр! = -1 && col! = -1 && avg_col> 200) {илрүүлсэн_дигит.дигит = pgm_read_byte (& (хүснэгт [мөр] [col])); илрүүлсэн_digit.index = pgm_read_byte (& (char_indexes [мөр] [col])); } өөр {илрүүлсэн_digit.digit = 0; }}
void drawSprite (байт* спрайт) {
// Маскийг sprite эгнээний байтын маскнаас баганын битийг авахад ашигладаг = B10000000; for (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));
// маскыг нэг пикселээр баруун тийш шилжүүлэх
маск = маск >> 1; }
// баганын маскыг дахин тохируулах
маск = B10000000; }}
хүчингүй тохиргоо () {
cli (); initADC (); sei ();
Цуваа.begin (115200);
lmd.setEnabled (үнэн); lmd.setIntensity (2); lmd.clear (); lmd.display ();
илэрсэн_дигит.digit = 0;
}
гарын үсэг зураагүй урт z = 0;
void loop () {
байхад (ADCSRA & _BV (ADIE)); // Аудио дээж авах ажлыг goertzel дуусгахыг хүлээнэ үү (дээж, спектр); илрүүлэх_дижит (спектр);
хэрэв (илэрсэн_дигит.дигит! = 0) {
drawSprite (фонт [found_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) илрүүлсэн_дижит.дижит); } z ++;
samplePos = 0;
ADCSRA | = _BV (ADIE); // Дээж авах тасалдлыг үргэлжлүүлнэ үү
}
ISR (ADC_vect) {
uint16_t дээж = ADC;
дээж [samplePos ++] = дээж - 400;
if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // Буфер дүүрсэн, тасалдал унтарсан}}
Алхам 3: Схем
Дараахь холболтыг хийх ёстой.
Микрофоноос Arduino руу
Гарсан -> A0
Vcc -> 3.3V Gnd -> Gnd
AREF -ийг 3.3V -т холбох нь чухал юм
Arduino дээр харуулах
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
Алхам 4: Дүгнэлт
Энд юу сайжруулж болох вэ? Би 9615 Гц давтамжтай N = 256 дээжийг ашигласан бөгөөд энэ нь зарим спектрийн алдагдалтай, хэрэв N = 205 ба хурд нь 8000 Гц бол хүссэн давтамж нь дискретизацийн сүлжээтэй давхцдаг. Үүний тулд ADC -ийг таймер халих горимд ашиглах ёстой.
Зөвлөмж болгож буй:
Raspberry Pi - TMD26721 Хэт улаан туяаны дижитал ойролцоо илрүүлэгч Java заавар: 4 алхам
Raspberry Pi-TMD26721 хэт улаан туяаны дижитал ойролцоо илрүүлэгч Java заавар: TMD26721 нь хэт улаан туяаны дижитал детектор бөгөөд 8 зүү бүхий гадаргуутай холбох ганц модульд ойр орчныг илрүүлэх систем, дижитал интерфэйсийн логикийг өгдөг. нарийвчлал. Мэргэжилтэн
Усны түвшин илрүүлэгч: 7 алхам
Усны түвшин илрүүлэгч: Хэт авианы мэдрэгч нь радар системтэй ижил зарчмаар ажилладаг. Хэт авианы мэдрэгч нь цахилгаан энергийг акустик долгион болгон хувиргаж чаддаг. Алдарт HC SR04 хэт авианы мэдрэгч нь 40 кГц давтамжтай хэт авианы долгион үүсгэдэг
Зигбигийн ор байгааг илрүүлэгч: 8 алхам
Зигбигийн ор байгааг илрүүлэгч: Хэсэг хугацааны турш би орондоо хэвтэж байхдаа илрүүлэх арга хайж байсан. Энэ мэдээллийг Homeassistant -д ашиглахад зориулагдсан болно. Энэхүү мэдээллийн тусламжтайгаар би шөнийн цагаар гэрлээ унтраах автоматжуулалт хийх эсвэл жишээлбэл миний гэрт дохиоллын системийг идэвхжүүлэх боломжтой болсон
Утаа илрүүлэгч: 13 алхам
Утаа илрүүлэгч: Сайн байна уу найзуудаа өнөөдөр утааны мэдрэгчийн талаар үзье. Та нарын ихэнх нь худалдааны төвүүдээр зочилсон бөгөөд ихэнхдээ утааны детектор гэж нэрлэдэг энэ төхөөрөмжийг харах боломжтой бөгөөд утаа илрүүлж, ус цацагчийг асааж, галыг зогсоох болно. оронд нь
Одоогийн чичиргээ илрүүлэгч: 3 алхам
Одоогийн чичиргээ илрүүлэгч: Энэ төсөлд бид хэн нэгэн бэлэг/хайрцаг сэгсрэвэл дохиолол өгөх төхөөрөмж хийх гэж байна. Христийн Мэндэлсний Баяраар шуудангаар илгээмж авах үед надад ийм санаа төрсөн. Үүнд юу байсныг таахыг оролдохын тулд мэдээж бид бүгд л үүнийг сэгсрэв