فهرست مطالب:
تصویری: آشکارساز DTMF: 4 مرحله
2024 نویسنده: John Day | [email protected]. آخرین اصلاح شده: 2024-01-30 08:56
بررسی اجمالی
من برای ساخت این دستگاه از یک تکلیف خانگی در دوره آنلاین پردازش سیگنال دیجیتال الهام گرفتم. این یک رمزگشای DTMF است که با Arduino UNO پیاده سازی شده است ، با صدایی که تولید می کند ، یک رقم فشرده شده روی صفحه کلید تلفن را در حالت تن تشخیص می دهد.
مرحله 1: درک الگوریتم
در DTMF هر نماد با دو فرکانس مطابق جدول روی تصویر کدگذاری می شود.
دستگاه ورودی میکروفون را گرفته و دامنه هشت فرکانس را محاسبه می کند. دو فرکانس با حداکثر دامنه یک ردیف و یک ستون از نماد رمزگذاری شده می دهد.
اکتساب داده ها
به منظور انجام تجزیه و تحلیل طیف نمونه ها باید با فرکانس قابل پیش بینی خاصی گرفته شوند. برای دستیابی به این هدف ، من از حالت ADC رایگان با حداکثر دقت (پیش شماره گیری 128) استفاده کردم که میزان نمونه برداری را 9615 هرتز می دهد. کد زیر نحوه پیکربندی ADC Arduino را نشان می دهد.
void initADC () {
// Init ADC؛ f = (16 مگاهرتز/پیش فروشنده)/13 چرخه/تبدیل ADMUX = 0 ؛ // کانال فروش ، right-adj ، از پین AREF ADCSRA = _BV (ADEN) | استفاده کنید // ADC را فعال کنید _BV (ADSC) | // ADC start _BV (ADATE) | // ماشه خودکار _BV (ADIE) | // وقفه فعال _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0) ؛ // 128: 1 /13 = 9615 هرتز ADCSRB = 0 ؛ // حالت آزاد اجرا DIDR0 = _BV (0)؛ // خاموش کردن ورودی دیجیتال برای پین ADC TIMSK0 = 0؛ // تایمر 0 خاموش} و کنترل کننده وقفه شبیه این ISR (ADC_vect) است {uint16_t sample = ADC؛ نمونه [samplePos ++] = نمونه - 400 ؛ if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE) ؛ // بافر کامل ، وقفه خاموش}}
تجزیه و تحلیل طیف
پس از جمع آوری نمونه ها ، دامنه 8 فرکانس رمزگذاری نمادها را محاسبه می کنم. برای این کار نیازی به اجرای کامل FFT ندارم ، بنابراین از الگوریتم Goertzel استفاده کردم.
void goertzel (uint8_t *نمونه ، شناور *طیف) {
شناور 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 * [نمایش به Arduino] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #include #include
#عبارتند از
#تعریف 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]
// محاسبه برای 9615Hz 256 نمونه توایع cos_t شناور [IX_LEN] PROGMEM = {.8932243011955153،.8700869911087115،.8448535652497071،.8032075314806449،.6895405447370669،.6343932841636456،.5555702330196023،.4713967368259978}؛ const float sin_t [IX_LEN] PROGMEM = {0.44961132965460654 ، 0.49289819222978404 ، 0.5349976198870972 ، 0.5956993044924334 ، 0.7242470829514669 ، 0.7730104533627369 ، 0.831924984 ، 0.8319246 ، 0.83141296 ، 0.8319246 ، 0.8319246
typedef struct {
رقم کاراکتر ؛ شاخص uint8_t ؛ } digit_t؛
رقم_تشخیص_شخص ؛
const char table [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 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 0x04 ، 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 ؛ // کانال فروش ، right-adj ، از پین AREF ADCSRA = _BV (ADEN) | استفاده کنید // ADC را فعال کنید _BV (ADSC) | // ADC start _BV (ADATE) | // ماشه خودکار _BV (ADIE) | // وقفه فعال _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0) ؛ // 128: 1 /13 = 9615 هرتز ADCSRB = 0 ؛ // حالت آزاد اجرا DIDR0 = _BV (0)؛ // خاموش کردن ورودی دیجیتال برای پین ADC TIMSK0 = 0؛ // تایمر 0 خاموش}
void goertzel (uint8_t *نمونه ، شناور *طیف) {
شناور 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 ؛ } result result / len؛ }
int8_t get_single_index_above_threshold (float *a، uint16_t len، float threshold) {
if (آستانه <THRESHOLD) {بازگشت -1 ؛ } int8_t ix = -1؛ برای (uint16_t i = 0؛ i آستانه) {if (ix == -1) {ix = i؛ } else {return -1؛ }}} return ix؛ }
void dete_digit (float *spectrum) {
شناور avg_row = avg (طیف ، 4) ؛ شناور avg_col = avg (& طیف [4] ، 4) ؛ int8_t row = get_single_index_above_threshold (طیف ، 4 ، avg_row) ؛ int8_t col = get_single_index_above_threshold (& spectrum [4] ، 4 ، avg_col) ؛ if (row! = -1 && col! = -1 && avg_col> 200) {dete_digit.digit = pgm_read_byte (& (جدول [سطر] [col])) ؛ detect_digit.index = pgm_read_byte (& (char_indexes [ردیف] [col]))؛ } else {dete_digit.digit = 0؛ }}
void drawSprite (بایت* Sprite) {
// ماسک برای بدست آوردن بیت ستون از sprite row byte mask = B10000000 استفاده می شود؛ for (int iy = 0؛ iy <8؛ iy ++) {for (int ix = 0؛ ix <8؛ ix ++) {lmd.setPixel (7 - iy، ix، (bool) (sprite [iy] & mask)) ؛
// ماسک را یک پیکسل به راست منتقل کنید
mask = mask >> 1؛ }
// بازنشانی ماسک ستون
ماسک = B10000000؛ }}
void setup () {
cli ()؛ initADC ()؛ sei ()؛
Serial.begin (115200) ؛
lmd.setEnabled (درست) ؛ lmd.setIntensity (2) ؛ lmd.clear ()؛ lmd.display ()؛
dete_digit.digit = 0؛
}
طولانی بدون علامت z = 0؛
حلقه خالی () {
در حالی که (ADCSRA & _BV (ADIE)) ؛ // منتظر بمانید تا نمونه برداری صوتی گواترزل (نمونه ها ، طیف) را به پایان برساند. detective_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) detect_digit.digit) ؛ } z ++ ؛
samplePos = 0 ؛
ADCSRA | = _BV (ADIE) ؛ // ادامه نمونه گیری وقفه
}
ISR (ADC_vect) {
uint16_t نمونه = ADC؛
نمونه [samplePos ++] = نمونه - 400 ؛
if (samplePos> = N) {ADCSRA & = ~ _BV (ADIE) ؛ // بافر کامل ، وقفه خاموش}}
مرحله 3: شماتیک
اتصالات زیر باید ایجاد شود:
میکروفون به آردوینو
خارج -> A0
Vcc -> 3.3V Gnd -> Gnd
اتصال AREF به 3.3V مهم است
نمایش به آردوینو
Vcc -> 5V
Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9
مرحله 4: نتیجه گیری
چه چیزی می تواند در اینجا بهبود یابد؟ من از N = 256 نمونه با نرخ 9615 هرتز که دارای نشتی طیف است استفاده کردم ، اگر N = 205 و نرخ 8000Hz باشد ، فرکانس های مورد نظر با شبکه گسسته مطابقت دارد. برای آن ADC باید در حالت سرریز تایمر استفاده شود.
توصیه شده:
آشکارساز سطح آب: 7 مرحله
آشکارساز سطح آب: سنسور اولتراسونیک بر اساس اصول یک سیستم راداری کار می کند. سنسور اولتراسونیک می تواند انرژی الکتریکی را به امواج صوتی و بالعکس تبدیل کند. سنسور اولتراسونیک HC SR04 امواج فراصوت را با فرکانس 40 کیلوهرتز تولید می کند
آشکارساز حضور تخت زیگبی: 8 مرحله
آشکارساز حضور تخت زیگبی: مدتی است که بدنبال راهی برای تشخیص زمان خوابیدن در رختخواب بودم. این برای استفاده از این اطلاعات در Homeassistant است. با استفاده از این اطلاعات می توانم برای خاموش کردن چراغ ها در شب اتوماسیون انجام دهم یا به عنوان مثال یک سیستم هشدار را در خانه من فعال کنم
آشکارساز دود: 13 مرحله
آشکارساز دود: سلام دوستان امروز اجازه دهید در مورد آشکارساز دود ببینیم بسیاری از شما به مراکز خرید در مراکز خرید رفته اید ، بیشتر می توانید این دستگاه را مشاهده کنید که دود آشکارساز نامیده می شود که دود را تشخیص داده و آبپاش را روشن می کند و آتش را متوقف می کند. بجای
آشکارساز لرزش کنونی: 3 مرحله
Present Shake Detector: در این پروژه ما قصد داریم دستگاهی بسازیم که در صورت تکان دادن هدیه/جعبه ، زنگ خطر را به صدا در آورد. من این ایده را زمانی دریافت کردم که بسته ای را برای کریسمس در نامه دریافت کردیم. برای اینکه حدس بزنیم چه چیزی در آن وجود دارد ، البته ما آن را تکان دادیم مانند همه
آشکارساز دود IOT: آشکارساز دود موجود را با IOT به روز کنید: 6 مرحله (همراه با تصاویر)
آشکارساز دود IOT: آشکارساز دود موجود را با IOT به روز کنید: فهرست مشارکت کنندگان ، مخترع: Tan Siew Chin ، Tan Yit Peng ، Tan Wee Heng ناظر: دکتر Chia Kim Seng گروه مهندسی مکاترونیک و رباتیک ، دانشکده مهندسی برق و الکترونیک ، Universiti Tun حسین اونن مالزی. توزیع