Лампа настрою, що реагує на звук - Мікроконтролери та Технології

лампа

Лампа настрою (mood lamp) – невелика декоративна настільна лампа, яка періодично випадково плавно змінює свій колір. У мережі повно різних варіантів саморобних ламп настрою (у тому числі і на AVR), але просто зміна кольору випадково - це досить нудно. У цій статті я розповім про те, як зробити просту лампу настрою, яка реагує на звук.

Ідея

Отже, ідея в тому, щоб забезпечити звичну лампу настрою мікрофоном, і змусити її змінювати колір не просто випадковим чином, а залежно від того, що вона "чує" через цей мікрофон. Лампа працюватиме в трьох режимах (режим перемикається єдиною кнопкою):

- Простий режим або режим звичайної лампи настрою. Лампа просто періодично випадковим чином змінює колір. - Реакція на різкий звук. - Аналіз частоти звуку. У цьому режимі лампа змінює колір залежно від частоти звуку який вона "чує", тобто щось типу музики.

Реалізація

З ідеєю зрозуміло, приступимо до реалізації. Для такої лампи знадобляться, як мінімум, три речі: яскравий триколірний світлодіод - щоб світити, мікрофон - щоб чути, і мікроконтролер - щоб управляти всім цим господарством.

Світлодіод

Як світлодіод я використовував надяскравий триколірний (RGB) світлодіод потужністю 3Вт (по 1Вт на кожну з кольорових компонентів). Сам світлодіод встановлений на алюмінієвій пластині-радіаторі, і виглядає так:

мікроконтролери

Світить досить яскраво і має широкий "кут огляду" - немає яскравої плямипосередині.

На жаль, підключити такий світлодіод безпосередньо до ніжок мікроконтролера не вийде, тому що струму йому потрібно близько 200Ма на канал, а, наприклад, максимально допустимий струм через ніжку контролера ATMega8 – всього 40Ма. Тому на кожен канал світлодіода я поставив транзистором - контролер відкриває/закриває транзистор, змінюючи напругу на базі. А транзистор запалює/гасить світлодіод, адже максимально допустимий струм транзистора цілих 800Ма (для BC337), що з головою вистачає, щоб запалити світлодіод.

Мікрофон

Як мікрофон використовується звичайний електретний мікрофон (капсюль), підключений до АЦП мікроконтролера через підсилювальний каскад.

звук

В принципі можна було б використовувати цифровий мікрофон, але на нашому радіоринку виявилося набагато простіше знайти електретний мікрофон.

Мікроконтролер

Тут вибір здавався цілком очевидним –ATMega8. Щось слабше використовувати не вийде, тому що потрібно три канали ШИМу (по каналу на кожен із трьох кольорів світлодіода). Використовувати щось потужніше, здавалося, не має сенсу. Тому я зупинив свій вибір на мікроконтролері ATMega8.

Але тут мене чатували на граблі. Справа в тому, що для реалізації програми лампою, що управляє, мені знадобилося використання арифметики з плаваючою точкою, а AVR-ки, на жаль, не мають FPU. Тому для дробових чисел використовується програмна реалізація FPU, яка займає чимало місця у пам'яті мікроконтролера. В результаті пам'ять ATMega8 була забита під зав'язку. Якби зараз я вирішив зібрати ще одну лампу, то, напевно, поставив би як мінімум ATMega32.

Схема та друкована плата

З основними компонентами розібралися, тепер залишилося поєднати все це воєдино:

мікроконтролери

Обв'язка мікроконтролера стандартна: живлення, кнопка скидання, роз'єм програматора.

Для того щоб запустити контролер на максимальній частоті (16МГц), доданий кварцовий осцилятор (у лівому нижньому куті схеми).

На вхід аналогового живлення (AVCC) підключений LC-фільтр (дросель та конденсатор), за рекомендацією даташиту на ATMega8 (див. розділ "Analog Noise Canceling Techniques"). Щоправда, як виявилося - знайти на нашому радіоринку потрібний дросель досить проблематично, тому я поставив що знайшов, а саме - старий радянський дросель на 120мкГн.

КнопкаBUTTON використовується для перемикання режимів роботи лампи.

СвітлодіодDBG_LED використовувався для налагодження прошивки, і ставити його не обов'язково.

У верхньому правому куті схеми зображено підсилювальний каскад для підключення мікрофона до АЦП мікроконтролера. Сам мікрофон підключається до роз'ємуMIC.

Трохи нижче зображено схему для підключення RGB світлодіода. Бази транзисторів підключені до ніжок контролера, які вміють генерувати апаратний ШІМ (OC1A, OC1B, OC2). Катоди світлодіода через транзистори посаджено на землю. Джампер JP1 потрібен щоб можна було відключати канал OC2 від транзистора. Справа в тому, що OC2 є за сумісництвом та входом MOSI для програматора, тому при прошивці мікроконтролера з увімкненим джампером світлодіод починає дратівливо моргати. Ставити його, у принципі, необов'язково.

Друковану плату хотілося зробити повністю односторонньою, але, на жаль, не вийшло. Довелося кинути кілька перемичок з іншого боку (зображені червоними стежками).

технології

Корпус

Як корпус використовується випотрошений звичайний світильник. Плата прикручена болтами до нижньоїчастини корпусу. Мікрофон притиснутий припаяним до корпусу шматком дроту.

настрою

Світлодіод міцно тримається на шматку текстоліту, притиснутий до нього припаяними проводами. Сам шматок текстоліту прикручений шурупами до дерев'яного брусочку, який прикручений до основної плати.

технології

Зібрана лампа в корпусі виглядає так:

технології

Програмна частина

Спочатку трохи про загальну структуру програми. Підтримка різних режимів здійснена за допомогою вказівників на функції, тому змінювати/додавати нові режими дуже просто. Є enum Mode, в якому перелічені всі режими, в яких вміє працювати лампа. Є два масиви з вказівниками на функції: mode_callbacks та mode_switch_callbacks. Масив mode_callbacks містить покажчик на головну процедуру кожного режиму. Масив mode_switch_callbacks, за аналогією, містить покажчики на функції зміни режимів. Функція зміни режиму потрібна щоб дати користувачеві зрозуміти що сталося переключення в новий режим роботи.

У функції main знаходиться головний цикл який складається з трьох рядків:

- mode_callbacks[mode](); Фактично, це виклик головної процедури для поточного режиму роботи. Вона буде виконуватися доти, доки користувач не натисне кнопку. - mode = (mode + 1) % ModeLastInvalid; Переходимо до наступного режиму. - mode_switch_callbacks [mode] (); І викликаємо обробник зміни режиму нового режиму. Все, що зараз роблять ці обробники, блимають п'ять разів якимось кольором. Після виконання цього рядка ми знову повертаємось на початок циклу.

Ще, мабуть, варто згадати функції schedule_delay та pick_random_color.

Функція schedule_delay використовується для створення затримок. Вона необхідна тому, що не можна просто викликати стандартну функцію на кшталт _delay_ms ізаснути, адже потрібно зчитувати дані з АЦП і перевіряти стан кнопки (чи не натиснув її користувач). Саме це завдання функція schedule_delay і виконує. Насправді можна було б використовувати режим безперервного перетворення в АЦП, а обробку натискання на кнопку повісити на переривання, але як показала практика, в режимі безперервного перетворення шуми на АЦП більше ніж в режимі одиночного перетворення.

Функція pick_random_color просто вибирає випадковий колір (у форматі RGB). Вірніше не зовсім просто, а з одним нюансом: що частіше з'являлися красиві "чисті кольори" (червоний, зелений, синій) введена константа COLOR_CLEAR_PROBABILITY, яка у відсотках задає частоту появи "чистих" кольорів. Тобто якщо її значення дорівнює 50, то кожен другий випадковий колір буде червоним, зеленим або синім.

Режим лампи настрою

Головна процедура режиму – mood_lamp_mode. Це найпростіший режим, і його поведінка цілком очевидна з коду: вибираємо і запам'ятовуємо новий випадковий колір, плавно змінюємо поточний колір лампи до вибраного кольору, "утримуємо" деякий час і починаємо все спочатку.

Режим реакції на гучний звук

Головна процедура режиму – sound_lamp_mode. Загалом усе схоже на попередній режим із парою нюансів. По-перше, режим утримання кольору не обмежений за часом - перемикання до вибору нового кольору відбудеться не по таймууту, а якщо лампа почує гучний звук. А по-друге, під час плавного переходу до нового кольору може статися перемикання до вибору нового кольору (знову ж таки, якщо лампа почує гучний звук).

Кілька слів про функцію sound_lamp_mode_get_mic. Її завдання – отримати поточний "рівень" звуку на мікрофоні. Працює вона так: спочатку відключаються всі три канали ШІМ, потімпроганяється пара неодружених перетворень АЦП і запам'ятовується значення з АЦП, потім відновлюються значення на ШІМ-ах. Такі милиці довелося додати тому що робота ШІМу сильно псує показання АЦП (я підозрюю тут дається взнаки китайський блок живлення, який не може забезпечити стабільну напругу).

Режим аналізу звуку

Головна процедура режиму – sound_analysis_mode. По суті, цей режим є послідовним виконанням двох операцій: визначення частоти звуку, і зміна кольору на колір, що відповідає цій частоті. Розглянемо їх докладніше.

Спочатку хотів використовувати дискретне перетворення Фур'є визначення частоти звуку. Але вмістити його у восьми кілобайтах пам'яті мікроконтролера ніяк не вийшло, тому довелося використовувати інший, більш примітивний спосіб. Суть способу полягає у підрахунку перетину звуковим сигналом нуля. Реалізовано це так - звуковий сигнал записується в буфер, потім ми проходимо по цьому буферу і підраховуємо, як багато послідовних пар елементів лежать по різні боки від нуля. Тільки нуль це не математичний нуль, а нульова амплітуда, для якої використовується константа SOUND_AMPL_ZERO. Щоб було зрозуміліше розглянемо приклад: нехай нульова амплітуда в нас це 100, тоді пара значень 95 і 120 перетинають нуль, т.к. вони лежать по різні боки від нульової амплітуди (95 менше 100, а 120 більше 100). А ось пара 80 та 90 не перетинають, т.к. обидва ці значення менше ста. Таким чином частота це кількість перетинів нуля поділена на одиницю часу.

Тепер про те, як на підставі частоти вибрати колір. Колірна модель RGB для цього слабо підходить, оскільки кожен її компонент фактично контролює три параметри: тон, насиченість та яскравість, амені ж хотілося, щоб частота впливала тільки на тон, а яскравість і насиченість залишалися постійними. Тому я вибрав колірну модель HSV. Яскравість і насиченість постійні і рівні їх максимальним значенням, а тон безпосередньо залежить від частоти. Коли на підставі частоти отримано значення кольору HSV, виконується перетворення з HSV в RGB, і отриманий колір виводиться на світлодіод. Весь процес перетворення частоти звуку в колір моделі RGB виконується у функції convert_freq_to_rgb.

Результат