Pull to refresh

Новогодняя музыкальная открытка

Reading time 4 min
Views 29K
На носу новогодние и рождественские праздники, и многие озабочены тем, что подарить друзьям и близким.
Собственно, тем же вопросом озаботился и я. И пришла мне такая идея — сделать музыкальную открытку. Конечно, идея не новая — наши братья китайцы их делают в больших количествах и по низкой цене. Но конкурировать с китайцами я и не собирался, просто хотелось все-таки чего-то своего. И, как мне кажется, получился неплохой результат:




ТЗ

Для начала я сформулировал такие требования:
В открытом состоянии открытка должна играть мелодию по кругу.
В качестве мелодии я выбрал «Щедрик», или «Carol Of The Bells».
Желательно, чтобы мелодия была полифонической.
Схема должна быть максимально простой, содержать минимум деталей, легко повторяться, стоить недорого. И главное — помещаться в открытку.

Анализ

Я давно собирался заняться микроконтроллерами, и для опытов купил несколько штук самых дешевых — attiny13, поэтому решил делать схему на базе этих микроконтроллеров.
Для начала, я прикинул, получится ли реализовать задуманное на этом МК, и если да, то каким способом. Для этого я нашел и скачал ноты, и приступил к анализу.
Мелодию в память МК можно записать многими способами, мне на ум пришло 2 варианта: 1) в виде номера ноты в каждый отрезок времени, соответствующий длительности минимальной ноты, и 2) в формате длительность — нота. Первый вариант реализовать, естественно, проще. Считаю: в песне 25 тактов, из них 16 повторяются дважды, т.е. всего 41 такт. Минимальная длительность ноты — 1/8, а размер такта — 3/4, следовательно, в одном такте — 6 нот минимальной длительности, а вся мелодия будет содержать 6 (нот в такте) * 41 (такт) * 3 (голоса) = 738 нот. Если на каждую ноту тратить один байт — выходит многовато, так как attiny13 всего содержит 1024 байт flash-памяти (а нужно разместить еще саму программу и таблицу частот). Следовательно, стоит попробовать второй способ. Считаю: всего 263 ноты (включая паузы) — уже приемлемо, даже если использовать байт на длительность, и байт на высоту ноты — получится 526 байт.
Писать решил на ассемблере — во-первых, для того чтобы лучше разобраться с самим МК, а во-вторых — чтобы уместиться в оставшиеся 700 байт.
У МК tiny13 на борту есть 2 ШИМ, с помощью которых можно сделать двухголосную мелодию. Но для данной мелодии нужно 3 голоса, поэтому использовать один только ШИМ для генерации звука не получится. Для простоты я решил отказаться от использования ШИМ — по крайней мере в первой версии устройства.

Схема

Сначала я решил выводить каждый голос мелодии на отдельную ногу МК. Поэтому изначально схема была следующей:



В последствии оказалось, что при таком включении музыка звучит очень тихо. Чтобы решить эту проблему, пришлось все голоса смешать в один канал, и результат подавать на два вывода МК в противофазе — благодаря этому изменение напряжения на пьезоэлементе оказалось в 2 раза больше напряжения питания. Схема получилась еще проще:



Алгоритм

Для того, чтобы получить звук заданной частоты на выходе МК, нужно поделить его тактовую частоту на число-коэффициент, равное частоте МК / заданную частоту. Так как операции деления (и вычисления остатка по модулю) в списке команд AVR отсутствует, то будем делить с помощью счетчика. Изначально счетчику присваивается коэффициент деления, а на очередном цикле — вычитается 1. Если счетчик равен нулю, значит настал момент изменения сигнала на делителе, и нужно изменить значение на определенной ножке МК, а также заново записать в счетчик значение-коэффициент.
Счетчиков-делителей нужно 4 штуки: по одному для каждого голоса, и еще один — для отсчета нот (и определения темпа).
Алгоритм работы следующий:

1) инициализировать переменные
2) если счетчик-делитель нот равен нулю, то для каждого голоса проверить, доиграла ли текущая нота, и если доиграла — загрузить из памяти следующую.
3) для каждого голоса уменьшить счетчик на 1, если он равен нулю — заново присвоить ему коэффициент деления, и изменить значение на выходе.
4) переход на 2

Для того, чтобы этот алгоритм работал, нужно чтобы каждый цикл программы выполнялся за одинаковое количество тактов. Для этого пришлось просчитать все ветки ветвлений, и добавить nop или пустой цикл для слишком «шустрых» участков.

Сначала, когда звук выводился на три вывода МК, форма сигнала была в виде меандра. Потом, когда пришлось все это смешивать и выводить через 2 пина в противофазе (т.е. фактически, через один пин) возникла проблема, как смешать эти три голоса. Поэтому было принято решение сделать форму сигнала в виде коротких импульсов, а суммировать их с помощью простого or`а.

Код программы

Исходный код программы можно посмотреть здесь

Железо

При реализации финального варианта возникли следующие задачи:
1) питание
2) включение-выключение
Задачу 1 я решил с помощью литиевой батарейки cr2016, которая согласно этой статье должна иметь емкость приблизительно 90 мАч. Батарейку я разместил в самодельном отсеке из канцелярской скрепки, так как приемлемого по размерам и цене промышленного отсека я не нашел. Схема потребляет около 2 мА, поэтому такой батарейки должно хватить часов на 40, что более чем достаточно.
Задачу 2 я поначалу думал решать с помощью тех же скрепок, но потом отказался от этой идеи в пользу геркона и магнита. Принцип работы виден на видео.

Прошивка

Компилировал и прошивал я в AVR Studio 4, при прошивке в фьюзах изменил только тактовую частоту на 4.8 МГц и отключил деление на 8 частоты задающего генератора.

Бюджет

Микроконтроллер — 8 грн
Пьезоэлемент — 2 грн
Батарейка — 4 грн
Геркон — 2 грн
Разработка, отладка программы — 6 часов
Разработка, тестирование схемы — 3 часа
Изготовление одной открытки (при наличии вытравленной платы) — 1 час

Фото


Первый прототип


Второй прототип


Крепление для батарейки


Готовое устройство — вид со стороны деталей


Готовое устройство — вид с обратной стороны


Первая серия

PS

Всех с наступающим Новым Годом и Рождеством!
Tags:
Hubs:
+77
Comments 37
Comments Comments 37

Articles