Будем использовать библиотеку для микроконтроллеров AVR с использованием прерывания таймера | ATmega328
Это библиотека для воспроизведения монофонической музыки с помощью широтно-импульсной модуляции и пьезоэлектрического зуммера. Монофоническая означает, что одновременно может воспроизводиться только одна нота. Тем не менее с ее помощью можно создавать неплохую музыку. При желании можно настроить мигание светодиода в такт музыке.
Все, что вам нужно, – это 16-разрядный таймер, который может быть одним из следующих: timer1, timer3 и timer4 (при условии, что они есть в микроконтроллере) и прерывание с интервалом в 1 мс для размещения основной функции. Это необходимо, потому что ноты должны иметь определенную продолжительность.
Чтобы создать песню, сначала нам нужны музыкальные ноты. Их можно найти в файле «pitches.h». Вот только две октавы из этого файла, которые выглядят так
#define NOTE_C4 262 #define NOTE_CS4 277 #define NOTE_D4 294 #define NOTE_DS4 311 #define NOTE_E4 330 #define NOTE_F4 349 #define NOTE_FS4 370 #define NOTE_G4 392 #define NOTE_GS4 415 #define NOTE_A4 440 #define NOTE_AS4 466 #define NOTE_B4 494 #define NOTE_C5 523 #define NOTE_CS5 554 #define NOTE_D5 587 #define NOTE_DS5 622 #define NOTE_E5 659 #define NOTE_F5 698 #define NOTE_FS5 740 #define NOTE_G5 784 #define NOTE_GS5 831 #define NOTE_A5 880 #define NOTE_AS5 932 #define NOTE_B5 988
Например, NOTE_G4 – это нота G в октаве 4, NOTE_CS5 – это нота до-диез в октаве 5. После каждой ноты указывается ее частота в герцах. Чем выше частота, тем выше высота тона.
Эти ноты можно использовать для создания таких песен, как эта
const int happy_birthday[] PROGMEM = {
NOTE_C4,4, NOTE_C4,8,
NOTE_D4,-4, NOTE_C4, NOTE_F4,
NOTE_E4,-2, NOTE_C4,4, NOTE_C4,8,
NOTE_D4,-4, NOTE_C4, NOTE_G4,
NOTE_F4,-2, NOTE_C4,4, NOTE_C4,8,
NOTE_C5,-4, NOTE_A4, NOTE_F4,
NOTE_E4, NOTE_D4, NOTE_AS4,4, NOTE_AS4,8,
NOTE_A4,-4, NOTE_F4, NOTE_G4, NOTE_F4,-2,
MUSIC_END
};
Заиграет известная песня Happy Bird Day. Массив имеет атрибут PROGMEM, который означает, что данные будут храниться только во флэш-памяти, а не во флэш-памяти и оперативной памяти, как было бы без этого атрибута. Это оченьважно, потому что без этого атрибута оперативная память будет заполняться очень быстро.
После ноты указывается длительность ноты. 1 – это целая нота, 2 – половина ноты, 4 – четверть ноты и так далее. Таким образом, большее число означает более короткую ноту. Отрицательныйначальная длительность означает пунктирную ноту. Для eпример -4 означает пунктирную четвертную ноту, то есть четверть плюс восемнадцатая или длительность ноты * 1.5.
Не у каждой ноты есть длительность. Это значит, что длительность не изменилась. Только когда длительность ноты меняется, после нее ставится число. У каждой ноты может быть длительность, даже если она не меняется, но это только увеличит размер массива.
MUSIC_END — это флаг, обозначающий 0.
Чтобы поставить репризу (паузу) между нотами, используйте REST, длительность. То же, что и NOTE, длительность. REST обозначает 1.
Также используются следующие определения: __CHIP_TUNES_START_MARKER__. __CHIP_TUNES_END_MARKER__, __CHIP_TUNES_GOTO_MARKER__. В некоторых мелодиях есть повторяющиеся фрагменты, и эти маркеры перемещают указатель на фрагмент, который нужно повторить, тем самым экономя много флэш-памяти.
Чтобы узнать, как именно микроконтроллер воспроизводит ноты, изучите основной код. По сути, 16-битный таймер настроен на генерацию частоты ШИМ в зависимости от ноты.
Где взять песни
Ниже я привожу несколько песен, но если вам нужно больше, вы можете найти их по этой ссылке https://dragaosemchama.com/en/2019/02/songs-for-arduino/. Есть много сайтов, где можно найти ноты для разных песен, если вы разбираетесь в теории музыки. Лично я не разбираюсь. Посколькупоскольку песни, представленные по этой ссылке, имеют повторяющуюся длительность, что увеличивает размер массива, я создал заголовочный файл “tunes.h” с некоторыми песнями, из которых я удалил повторяющуюся длительность и повторяющиеся разделы.
Управление пьезоэлектрическим зуммером и его подключение к микроконтроллеру
Есть два способа управления пьезоэлектрическим зуммером с помощью микроконтроллера:
– при подключении зуммера напрямую к микроконтроллеру с помощью 1 или 2 контактов. При использовании 2 контактов зуммер будет звучать громче из-за двухтактного режима
– при использовании NPN-транзистора для управления зуммером и 1 контакта микроконтроллера
Я предпочитаю второй способ, потому что с его помощью можно использовать более высокое напряжение, чем может обеспечить микроконтроллер, и тогда зуммер будет звучать громче.
Библиотека поддерживает оба метода. Если зуммер подключен напрямую к микроконтроллеру, можно использовать два контакта в двухтактном режиме, чтобы сделать звук громче при более низком напряжении, например 5 В. Например, если используется таймер 1, зуммер можно подключить к контактам OCR1A и OCR1B. Таким образом, на зуммер будет подаваться напряжение 10 В, даже если микроконтроллер выдает 5 В.
Управление зуммером напрямую с помощью контактов микроконтроллера
При использовании двух контактов зуммер подключается между OCnA и OCnB n, где n — номер выбранного таймера. Если используется только один контакт, зуммер подключается между OCnA или OCnB и землей.
Рекомендуется последовательно подключить резистор сопротивлением от 10 до 100 Ом, так как зуммер имеет емкость и может создавать нагрузку на драйвер вывода микроконтроллера. Я протестировал его с резистором на 100 Ом, звук хороший.
Управление пьезоэлектрическим звуковым сигналом с помощью NPN-транзистора
Поскольку пьезоэлектрический преобразователь является ёмкостным, резистор, подключённый параллельно зуммеру, также улучшает высокочастотную характеристику, быстрее рассеивая энергию, накопленную в пьезоэлектрическом элементе, когда транзистор выключен. Кроме того, он защищает транзистор от скачков напряжения, поскольку обладает индуктивностью.
Наконец-то код
включает файл “chipTunes.h”. Этот файл включает “pitches.h” и “tunes.h”, поэтому их нужно скачать и поместить в ту же папку, что и “chipTunes.h”.
#include "chipTunes.h"
Выберите таймер: 1, 3 или 4. Эти настройки находятся в файле chipTunes.h в разделе пользовательских настроек.
#define CHIP_TUNES_TIMER CHIP_TUNES_TIMER4
Укажите, где находится контакт. При использовании метода с двумя контактами этот контакт находится там же, где и OCnA. При использовании метода с одним контактом это может быть либо OCnA, либо OCnB. Это пример для контакта PC4.
#define CHIP_TUNES_PIN1_DDR DDRC #define CHIP_TUNES_PIN1_PORT PORTC #define CHIP_TUNES_PIN1_PIN PC4
Если используются 2 контакта, то следующий — это второй контакт. Если используется только 1 контакт, закомментируйте эти строки
#define CHIP_TUNES_PIN2_DDR DDRB #define CHIP_TUNES_PIN2_PORT PORTB #define CHIP_TUNES_PIN2_PIN PB2
Для метода с одним контактом этот параметр указывает, какой канал использовать: OCnA или OCnB
#define CHIP_TUNES_CHANNEL CHANNEL_A
Если вы хотите, чтобы светодиод мигал в такт музыке, установите для этого параметра значение true, в противном случае — false
#define CHIP_TUNES_BLINK_LED 0
Функция настройки
void chipTunes_Init(void)
Эта функция используется для настройки таймера и контактов
Генерация тона с помощью ШИМ
void chipTunes_Tone(uint16_t tone, uint16_t duration_ms)
тон: частота тона в герцах
duration_ms: продолжительность тона в миллисекундах
Эта функция неблокирующая, то есть процессор может выполнять другие задачи во время воспроизведения звукового сигнала. Чтобы эта функция работала, следующий код должен находиться в подпрограмме прерывания с интервалом в 1 мс
if(chipTunes_IsPlaying()) chipTunes_ISR();
Основная функция
void chipTunes_ISR(void)
Эта функция должна находиться внутри функции ISR, которая срабатывает каждые 1 миллисекунду, например так
if(chipTunes_IsPlaying()) chipTunes_ISR();
Здесь вы можете найти библиотеку millis.h для AVR, которая позволяет это сделать “programming-electronics-diy.xyz/2021/01/millis-and-micros-library-for-avr.html”
Воспроизведение песни
void chipTunes_Play(const int *melody, uint8_t tempo)
мелодия: имя массива, содержащего музыкальные ноты.
темп: темп песни. Чем больше число, тем быстрее будет звучать песня.
Запускает таймер и устанавливает флаг, указывающий на то, что в данный момент звучит мелодия.
Останавливает песню или мелодию
void chipTunes_Stop(void)
Настройка громкости
void chipTunes_SetVolume(volume)
громкость: число от 0 до 50. Значение по умолчанию — 50, то есть максимальная громкость.
Это вроде как работает. Значения от 10 до 50 почти не влияют на громкость, но если вам нужен более тихий сигнал, начните с 1.
Проверьте, не играет ли песня или мелодия
char chipTunes_IsPlaying(void)
Если в данный момент воспроизводится песня или мелодия, возвращается 1, в противном случае — 0.
Создание звукового сигнала
void chipTunes_alert_alarm(uint8_t vuvuzela)
vuvuzela: если 0, сигнал тревоги будет звучать как сирена, если 1 — как vuvuzela.
Посмотрите видео, чтобы услышать, как звучат эти звуки. Эта функция является блокирующей и завершает работу после срабатывания будильника. После этого добавляется задержка в 200 мс, потому что обычно будильник нужно включать несколько раз.
Создание списка воспроизведения
Чтобы можно было воспроизвести конкретную песню в заданном темпе, вам понадобится массив для плейлиста и еще один — для темпа. Поумолчанию они выглядят так. Добавьте может быть, еще что-нибудь или закомментируйте то, что не используется
const int *chipTunes_Playlist[] = {
tetris_theme,
fur_elise,
cannon_in_d_pachelbel,
greensleeves,
happy_birthday,
ode_to_joy
};
const uint8_t *chipTunes_Tempo[] = {
144, // тетрис_тема
80, // фур_элиз
100, // cannon_in_d_pachelbel / пушка_in_d_pachelbel
70, // зеленые рукава
140, // с днем рождения
114, // оде_то_джой
};
Пример кода:
#include <avr/io.h>
#include "chipTunes.h"
const int star_wars_theme[] PROGMEM = {
NOTE_AS4,8, NOTE_AS4, NOTE_AS4, //1
NOTE_F5,2, NOTE_C6,
NOTE_AS5,8, NOTE_A5, NOTE_G5, NOTE_F6,2, NOTE_C6,4,
NOTE_AS5,8, NOTE_A5, NOTE_G5, NOTE_F6,2, NOTE_C6,4,
NOTE_AS5,8, NOTE_A5, NOTE_AS5, NOTE_G5,2, NOTE_C5,8, NOTE_C5, NOTE_C5,
NOTE_F5,2, NOTE_C6,
NOTE_AS5,8, NOTE_A5, NOTE_G5, NOTE_F6,2, NOTE_C6,4,
NOTE_AS5,8, NOTE_A5, NOTE_G5, NOTE_F6,2, NOTE_C6,4, //8
NOTE_AS5,8, NOTE_A5, NOTE_AS5, NOTE_G5,2, NOTE_C5,-8, NOTE_C5,16,
NOTE_D5,-4, NOTE_D5,8, NOTE_AS5, NOTE_A5, NOTE_G5, NOTE_F5,
NOTE_F5, NOTE_G5, NOTE_A5, NOTE_G5,4, NOTE_D5,8, NOTE_E5,4, NOTE_C5,-8, NOTE_C5,16,
NOTE_D5,-4, NOTE_D5,8, NOTE_AS5, NOTE_A5, NOTE_G5, NOTE_F5,
NOTE_C6,-8, NOTE_G5,16, NOTE_G5,2, REST,8, NOTE_C5, //13
NOTE_D5,-4, NOTE_D5,8, NOTE_AS5, NOTE_A5, NOTE_G5, NOTE_F5,
NOTE_F5, NOTE_G5, NOTE_A5, NOTE_G5,4, NOTE_D5,8, NOTE_E5,4, NOTE_C6,-8, NOTE_C6,16,
NOTE_F6,4, NOTE_DS6,8, NOTE_CS6,4, NOTE_C6,8, NOTE_AS5,4, NOTE_GS5,8, NOTE_G5,4, NOTE_F5,8,
NOTE_C6,1,
MUSIC_END
};
int main(void){
chipTunes_Init();
chipTunes_Play(star_wars_theme, 108);
while (1){
}
}
// 1ms interrupt. It can be the millis library at this link
// https://www.programming-electronics-diy.xyz/2021/01/millis-and-micros-library-for-avr.html
ISR(){
if(chipTunes_IsPlaying()) chipTunes_ISR();
}
Пример кода для воспроизведения списка воспроизведения мелодий (плейлист):
#include "chipTunes.h"
int main(void){
chipTunes_Init();
const uint8_t NR_OF_TUNES = sizeof(chipTunes_Tempo);
uint8_t tune = 0;
while(1){
// Whait for the song to end then move to the next one
if(chipTunes_IsPlaying() == 0 && NR_OF_TUNES){
// Delay between songs
_delay_ms(2000);
chipTunes_Play(chipTunes_Playlist[tune], chipTunes_Tempo[tune]);
tune++;
if(tune > NR_OF_TUNES - 1) tune = 0;
}
}
}
// 1ms interrupt. It can be the millis library at this link
// https://www.programming-electronics-diy.xyz/2021/01/millis-and-micros-library-for-avr.html
ISR(){
if(chipTunes_IsPlaying()) chipTunes_ISR();
}
Загрузите:
Скачать нижеприведенные файлы в архиве:
– скачать в tar.gz архив
– скачать в zip архиве
v2.0
chipTunes.h (“drive.google.com/file/d/1Foe2PRvEr9C3a48jJi8_oMp_9_R-DtmC/view?usp=sharing”)
chipTunes – the main library code
pitches.h (“drive.google.com/file/d/1WAruVHw9j1-qtg9bpogR97Zuy01HNQMs/view?usp=sharing”)
pitches – contains the musical notes that chipTunes needs
tunes.h (“drive.google.com/file/d/1l03Itp8oo47DQZCP3aYTNnOFJy-kv14V/view?usp=sharing”)
Contains the following songs:
Dart Vader theme (Imperial March) – Star wars
Tetris theme – (Korobeiniki)
Mario Main Theme
Mario Underworld Melody
Fur Elise – Ludwig van Beethoven
Cannon in D – Pachelbel
Greensleeves
Ode to Joy – Beethoven’s Symphony No. 9
Happy Birthday
Большинство песен в разделе “мелодии”.h взяты с этого веб-сайта “dragaosemchama.com/en/2019/02/songs-for-arduino/”, но с удаленной дублирующей продолжительностью. Оставьте ему приятный комментарий. Каждая песня зачисляется отдельно.
Скачать песни можно и здесь “микроник.рус/7563/”
——————–
Примечание:
—————————————-
Скачать оригинал записи в PDF – здесь.
Типы зуммеров
Прежде чем продолжить, я хотел бы прояснить ситуацию с типами зуммеров для тех, кто с ними не знаком.
Существуют пассивные зуммеры (или пьезоэлектрические преобразователи, но слово «зуммер» короче) и активные зуммеры.
Активные пьезоэлектрические зуммеры
В таких зуммерах есть встроенная схема, которая при подаче постоянного напряжения заставляет их издавать звук фиксированной частоты. Они не воспроизводят музыку, но просты в управлении и могут использоваться в качестве звуковых индикаторов. Снаружи они выглядят как пассивные зуммеры.
Пассивные пьезоэлектрические зуммеры
Существует два основных типа пассивных зуммеров: с пьезоэлектрической мембраной и с мембраной внутри резонансного корпуса.
Резонирующий корпус делает звук зуммера громче, а благодаря очень низкому профилю диафрагму можно использовать для изготовления открытки или наручных часов. Пассивные зуммеры должны управляться переменным или импульсным постоянным напряжением (ШИМ).
Существуют также магнитные зуммеры и зуммеры с проводом обратной связи для самовозбуждения. Ссылки на них можно найти в конце этой страницы.
Знаете ли вы: что длительное воздействие постоянного напряжения может привести к выходу из строя зуммера?







