Воспроизводим музыку через пьезодинамик на микроконтроллерах (Atmega328)

Будем использовать библиотеку для микроконтроллеров 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 – здесь.

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

Существуют пассивные зуммеры (или пьезоэлектрические преобразователи, но слово «зуммер» короче) и активные зуммеры.

Активные пьезоэлектрические зуммеры
В таких зуммерах есть встроенная схема, которая при подаче постоянного напряжения заставляет их издавать звук фиксированной частоты. Они не воспроизводят музыку, но просты в управлении и могут использоваться в качестве звуковых индикаторов. Снаружи они выглядят как пассивные зуммеры.

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

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

Существуют также магнитные зуммеры и зуммеры с проводом обратной связи для самовозбуждения. Ссылки на них можно найти в конце этой страницы.

Знаете ли вы: что длительное воздействие постоянного напряжения может привести к выходу из строя зуммера?

Добавить комментарий