Главная О сайте Контакты

Хороший звук на простейшем бипере

От малобюджетных проектов на однокристаллах чудес полифонии и современных визуальных эффектов ждать не приходится. Пределом их интерфейсных возможностей обычно становятся один – два светодиода и, если повезет, пищалка (beeper). Именно об этом чуде техники я и хочу рассказать.

Beeper – пьезоэлектрический излучатель звука. Достаточно подать на него сигнал типа меандр определенной частоты, чтоб он запел. Что именно он споёт, будет зависеть от поданной частоты. Например, частота 440Гц будет соответствовать ноте Ля первой октавы. В некоторых приложениях этого вполне достаточно, например чтобы просигнализировать нажатие на единственную клавишу, или сообщить о некой ошибке, или обозначить окончание какого-то важного действия. Но что делать если все эти действия присутствуют одновременно, и кнопок несколько, и действия разные, да и на подтверждение тоже звучок повесить хочется, да такой, чтобы от сообщения об ошибке отличался? Естественно чередовать частоты, изменять длительности – одним словом делать музыку!

Аппаратная часть

Управлять бипером довольно просто – понадобится всего один вывод микроконтроллера и минимальная обвязка. Вариант включения бипера приведен на рисунке ниже. Вывод микроконтроллера, как правило, слаботочный и не может выдать ток больше чем 20-40мА, поэтому надо использовать транзистор (VT1). Уровень логической единицы на выходе микроконтроллера полностью откроет транзистор и через бипер (HA1) потечет ток. Логическая единица закрывает транзистор, и ток не течет. Это нужно учитывать при программировании, и позаботится о том, чтобы после окончания звучания, транзистор всегда оставался закрытым. Диод (VD1) нужен для снятия пиковых обратных токов, возникающих при резком закрытии транзистора. Если об этом не позаботиться, то в звучании появится неприятный высокочастотный дребезг. Такая схема хорошо работает как при напряжении питания (Vcc) 5В так и при 3,3В.

Программирование

Ресурсы микроконтроллера, которых всегда не хватает, так же не сильно пострадают – отдайте ему один таймер, сотню (от силы две) байт кода и немножко ОЗУ и таймер сыграет вам пару аккордов. А если не жалко 3 килобайта кода отдать под хорошую музыку, то даже можете услышать как Ваше устройство играет Лунную Сонату Бетховена.

Программировать звук нужно используя прерывания от таймера. Для того чтобы извлечь звук с частотой F нужно запрограммировать таймер на период t = 1000/(2F) (мс) и в каждом прерывании инвертировать значение выводимое на выход микроконтроллера. Введя в программу счетчик импульсов cnt, вы сможете задать время звучания T – при достижении значения cnt = T/2t остановите таймер и не забудьте выставить ноль на выходе микроконтроллера. А если завести массив со значениями частот и длительностей и проигрывать их одну за другой, то получится мелодия. Если мелодия достаточно большая (да даже если и не большая) проследите, чтобы массив попал не в ОЗУ а в память программ, ведь значения нот и частот не будут меняться в процессе исполнения программы. Например, в IAR Embedded workbench это делается с помощью директивы __flash.

Пример массива из двух нот:


__flash unsigned short melody[] = {
    //F   //T
    440,  500,   //Ля первой октавы длится пол секунды
    880,  500    //Ля второй октавы длится пол секунды
};

Этот пример вполне работоспособен, но мало функционален – изменить звучание нот и не промахнуться мимо аккорда, или изменить скорость воспроизведения мелодии не так уж просто, тем более, если мы имеем дело не с парой нот, а с целым музыкальным произведением. Настало время поговорить о связи технических параметров и параметров музыкальных.

Ноты и их частоты

В музыке для записи звуков используют ноты, каждая из которых соответствует определенной частоте. Используя стандартное для нот буквенное обозначения можно получить набор определений:


#define Tone_4_C 262 //До первой октавы
#define Tone_4_D 293 //Ре первой октавы
#define Tone_4_E 330 //Ми первой октавы
#define Tone_4_F 349 //Фа первой октавы
#define Tone_4_G 392 //Соль первой октавы
#define Tone_4_A 440 //Ля первой октавы
#define Tone_4_H 494 //Си первой октавы

Полный список приведен в файле sound_description.h проекта MelodyMIDI.

Запись нот с помощью директив, а не в виде массива, хороша тем, что в процессе программирования вам доступны все значения нот, а в программу попадут только те данные, которые вы используете. Это особенно важно для использования в микроконтроллерах с ограниченным ресурсом.

Темп

Теперь разберемся с длительностью звучания каждой ноты. В первую очередь она зависит от темпа, в котором должно быть сыграно музыкальное произведение. Темп в музыке это количество четвертых долей такта сыгранных в минуту. А такт - единица музыкального метра, начинающаяся с наиболее сильной доли, и заканчивающаяся перед следующей равной ей по силе. Ниже следует определение нескольких музыкальных темпов, взятое из музыкальной энциклопедии:


#define Temp_adagio  52   //Медленно, спокойно
#define Temp_allegro 132  //Скорый темп
#define Temp_presto  184  //Быстро

Полный список приведен в файле sound_description.h проекта MelodyMIDI.

Исходя из этих данных можно рассчитать количество миллисекунд, приходящихся на один такт:


#define get_temp(x) ((unsigned short)(((unsigned long)60000*4)/x))

Зная длительность одно такта не сложно вычислить длительность звучания каждой ноты. Например, если такт состоит из четырех четвертей, то длительность каждой ноты составляет длительность такта деленную на четыре. Таким образом, определив темп (Temp_) для всей композиции, можно записать длительность ноты с помощью директивы:


#define Drt_(nom, denom) ((get_temp(Temp_)*nom)/denom)

Одна восьмая будет записана как Drt_(1,8), а четверть как Drt_(1,4).

Вот теперь мы готовы записать данные из предыдущего примера в виде, приближенном к музыкальному:


#define Temp_ Temp_moderato
__flash unsigned short melody[] = {
  //F         //T
    Tone_4_A,   Drt_(1,2),   //Ля первой октавы
    Tone_5_A,   Drt_(1,2)    //Ля второй октавы
};


Теперь хорошо видно что за ноты будут проиграны – обе Ля одинаковой длительности, и отличаются на одну октаву. Сыграны будут в неспешном темпе. Кроме того изменив директиву Temp мы можем изменить скорость воспроизведения. Теперь наша запись однозначно соответствует музыкальному фрагменту, приведенному ниже:

Динамика

Динамикой в музыке называют силу звука т.е. громкость звучанию нот. Обычно основная тема – мелодия выделяется более сильным звучанием, в то время как аккорды, призванные лишь подчеркнуть красоту мелодии, играются более тихим звуком. Казалось бы это не про нас – бипер одновременно проигрывает только одну ноту и на аккорды не способен, да и силой звука мы тоже не способны управлять, ведь для этого нужно включать в схему некий усилитель с управляемым коэффициентом усиления, чего мы не делаем. Но нет, на оба этих утверждения есть контраргументы. Во-первых, аккорд может быть сыгран не одновременным нажатием нот, а быстрым их чередованием, такой способ называется арпеджио. Во вторых да – мы не управляем силой звучания, но бипер делает это за нас и очень удачно это делает. Дело в том, что его амплитудно частотная характеристика вовсе не равномерна во всем диапазоне слышимых частот. Ниже приведу АЧХ бипера GT-0930RP2.

На графике хорошо виден пик на 2,7кГц и явно выраженный спад амплитуды на низких частотах. Именно это обстоятельство очень удачно подходит к задаче воспроизведения музыки, так как музыкальные произведения, чаще всего, стоится подобным образом – основная мелодия звучит в первой, второй и третьей октавах (частоты от 300 до 2000Гц) а аккорды располагаются в малой, большой, контр и субконтр октавах (частоты от 16 до 300 Гц). Учитывайте это при составлении своих произведений.
Резонансная частота 2,7кГц, конечно же, высоковата, ведь большинство мелодий проигрываются в первой и второй октавах, то есть до 1кГц, а значит мы никогда не услышим максимум громкости бипера, и кажется, что можно выбрать бипер с меньшей резонансной частотой, НО… Чем ниже резонансная частота, тем больше габариты устройства. Да и 80% от максимальной громкости вполне достаточно, чтобы услышать сигнал устройства.

Примеры

В конце статьи приведу несколько примеров мелодий, которые использую сам. Примеры звучания всех приведенных ниже мелодий можно прослушать на плеере в правой колонке этой страницы.

"Ёлочка"

Началась эта история с мелодиями под Новый 2015 Год, и отлаживал я программу на новогодней песенке «В Лесу Родилась Ёлочка». По началу ёлочка сильно хромала и достала всю лабораторию, но тем не менее, именно на ней проект и был отлажен. Вот код этой мелодии:


static __flash unsigned short melody_data_new_year_tree[] = {

  //Tone    //Duration
  
    Tone_4_C, Drt_(1,4),

    Tone_4_A, Drt_(1,4),
    Tone_4_A, Drt_(1,4),
    Tone_4_G, Drt_(1,4),
    Tone_4_A, Drt_(1,4),

    Tone_4_F, Drt_(1,4),
    Tone_4_C, Drt_(1,4),
    Tone_4_C, Drt_(1,4),

  //полная версия приведена в файле melody.c проекта MelodyMIDI
};

Сообщение об ошибке:

В этом примере используется триоль, приходящаяся на одну четверть такта. Не сложно вычислить, что одна нота триоли длится одну треть одной четверти такта, то есть равна одной двенадцатой такта.


#define Temp_ Temp_allegro
static unsigned short melody_error[] = {

  //Tone      //Duration
    Tone_3_C,   Drt_(1,12),
    Tone_2_G,   Drt_(1,12),
    Tone_2_E,   Drt_(1,12),
    Tone_2_C,   Drt_(1,4),
};


Сообщение об успешном событии

Торжественные две первые ноты гимна:
«Союз…»


#define Temp_ Temp_allegretto
static unsigned short melody_success[] = {
  //Tone    //Duration
    Tone_3_G, Drt_(1,8),
    Tone_4_C, Drt_(1,4),
};


"Трепак"

В одном из приложений понадобилась развеселая мелодия, сопровождающая длительные вычисления, и показывающая, на сколько на самом деле «быстро» работает устройство. Причем мелодия должна начинаться с сильной доли (с удара). И такое нашлось - П.И. Чайковский, «Трепак» из балета «Щелкунчик».

Это два первых такта произведения. Основная мелодия содержится в верхних нотах – ее и сыграем, увеличив немного темп:


#define Temp_ Temp_prestissimo
static unsigned short melody_data_trepak[] = {
  //Tone     //Duration

    Tone_5_D,  Drt_(1,32),
    Tone_5_E,  Drt_(1,32),
    Tone_5_Fd, Drt_(1,32),

//1
    Tone_5_G,  Drt_(1,4),

    Tone_5_G,  Drt_(1,8),
    Tone_5_Fd, Drt_(1,8),
    Tone_5_G,  Drt_(1,4),
    Tone_5_G,  Drt_(1,4),

//2
    Tone_5_E,  Drt_(1,4),
    Tone_5_D,  Drt_(1,4),
    Tone_5_C,  Drt_(1,4),
    Tone_5_E,  Drt_(1,4),

//полная версия приведена в файле melody.c проекта MelodyMIDI
};

Отладка – Проект MelodyMIDI

Конечно же, можно писать музыку прямо в контроллер и слушать что получилось. Но процесс прошивки контроллера, все-таки не слишком быстрый. К тому же на большом компьютере с хорошими колонками огрехи в нотах распознаются лучше. Именно для отладки кода мелодий и создан проект MelodyMIDI (QT 5.4.0). Самый главный файл проекта melody.c содержит коды мелодий и функцию melody, возвращающую указатель на нужную мелодию и ее размер. Описание темпов, длительностей нот и их частоты содержатся в файле sound_description.h. Все остальное это обвязка – пользовательский интерфейс, позволяющий протестировать написанный код, преобразовав его в midi файл, который можно прослушать стандартным проигрывателем. Новые мелодии добавляются в файл melody.c по образцу уже написанных:

  • задайте номер новой мелодии с помощью директивы в файле melody.h;
  • создайте массив данных по аналогии с имеющимися в файле melody.c;
  • добавьте созданный массив в функцию melody;
  • задайте название композиции в конструкторе класса MainWindow в файле mainwindow.cpp.

Теперь можно пересобрать и запустить проект. Найдите в выпадающем списке созданную композицию и нажмите кнопку «MIDI». В указанном вами месте создастся новый файл с расширением .mid, который вы сможете прослушать. Исходные файлы проекта и собранный исполняемый файл можно скачать с сайта hawkit.ru - MelodyMIDI.

Проект melody

И наконец то, ради чего всё и делалось – извлечение звука на однокристалке. Привожу часть проекта, взятого из жизни. Проект выполнен на процессоре AT90USB1287, работающем от внешнего кварца 8МГц. Схему подключения бипера к процессору смотрите на рисунке ниже. Единственное серьезное отличие от схемы в начале статьи, это использование p-n-p транзистора, оно вызвано особенностями конкретной реализации и на суть процесса не влияет. Стоит только учесть это и держать ни линии PE7 высокий уровень, пока музыка не проигрывается.

Файлы проекта melody написан для IAR Embedded Workbench for AVR. Их можно добавить в ваш проект и использовать свободно. Все файлы распространяются по лицензии GNU/GPL v.3. Ниже привожу список файлов и их краткое описание.
Папка melody содержит основной модуль проекта:

  • sound_description.h - описание темпов, длительностей нот и их частоты;
  • timer3.c (.h) – аппаратная реализация создания ШИМ на таймере 3;
  • melody.c (.h) – содержит данные мелодий и функции управления воспроизведением.


Папка Release содержит скомпилированный проект в формате, поддерживаемом стандартным программатором AVRProg.

В основном каталоге содержатся:

  • hardware_description.h - содержит описание выводов процессора;
  • config.h – конфигурационный файл проекта;
  • main.c – содержит пример работы с модулем melody.

Исходные файлы проекта и скомпилированный бинарник можно скачать с сайта hawkit.ru/MelodyAVR.

Александр Матяш

16.02.2015

Лицензия Creative Commons
Содержимое сайта www.hawkit.ru созданное автором по имени Александр Матяш, публикуется на условиях лицензии Creative Commons «Attribution» («Атрибуция») 4.0 Всемирная.
Разрешения, выходящие за рамки данной лицензии, могут быть доступны на странице: контакты.