Лампа настроения (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.


Архив для статьи "Лампа настроения реагирующая на звук"
Описание: Проект AVRStudio4, макет печатной платы
Размер файла: 94.92 KB Количество загрузок: 1 377 Скачать

Комментарии  

+2 #1 m1tya52 25.02.2016 19:52
Дброго времени! А фюзы можно?
Сообщить модератору
0 #2 m1tya52 26.02.2016 20:57
Подскажите пожалуйста фюзы кто делал. Че то у меня не совсем наверное правильно работает
Сообщить модератору
0 #3 Daud 19.04.2016 21:39
A .lay файл можно ?
Сообщить модератору
0 #4 igorlk61 05.09.2016 12:25
Собрал, все работает, только почему не полностью происходит гашение каналов? Спасибо.
Сообщить модератору
0 #5 Артем_____ 29.01.2020 16:11
Статья бесполезная!
НЕ могу выставить правильно фьюзы, в статье нет инструкции как их выставлять. Мигает быстро и зависает на произвольном цвете.
Сообщить модератору
0 #6 Тупица 17.05.2020 23:14
А где-нибудь можно купить такую?
Сообщить модератору