Воспроизведение мелодии Game of Thrones
В этом разделе мы собираем всё вместе в файле main.rs.
К этому моменту у нас уже есть частоты нот, логика тайминга песни и данные мелодии. Здесь мы просто связываем их между собой с помощью ШИМ и таймеров.
Импорты
Добавьте необходимые импорты для ШИМ, таймеров и работы с песнями.
#![allow(unused)]
fn main() {
// Для ШИМ
use embassy_rp::pwm::{Config as PwmConfig, Pwm, SetDutyCycle};
use crate::music::Song;
}
ШИМ и зуммер
В отличие от предыдущего примера, мы клонируем PwmConfig. Конструктор Pwm забирает объект конфигурации, а внутри цикла нам нужно менять top, чтобы задавать частоту ШИМ для каждой музыкальной ноты.
#![allow(unused)]
fn main() {
let mut pwm_config = PwmConfig::default();
pwm_config.top = PWM_TOP;
pwm_config.divider = PWM_DIV_INT.into();
let mut buzzer = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, pwm_config.clone());
}
Создание объекта Song
Создайте Song с темпом, заданным для темы Game of Thrones.
#![allow(unused)]
fn main() {
let song = Song::new(got::TEMPO);
}
Воспроизведение нот
Мелодия проигрывается циклом по массиву MELODY. Каждый элемент содержит частоту ноты и значение длительности.
#![allow(unused)]
fn main() {
// Один раз проигрываем мелодию
for (note, duration_type) in got::MELODY {
let top = get_top(note, PWM_DIV_INT);
pwm_config.top = top;
buzzer.set_config(&pwm_config);
let note_duration = song.calc_note_duration(duration_type);
let pause_duration = note_duration / 10; // 10% от note_duration
buzzer
.set_duty_cycle_percent(50)
.expect("50 is valid duty percentage"); // Ставим скважность 50%, чтобы сыграть ноту
Timer::after_millis(note_duration - pause_duration).await; // Играем 90%
buzzer
.set_duty_cycle_percent(0)
.expect("50 is valid duty percentage"); // Останавливаем тон
Timer::after_millis(pause_duration).await; // Пауза 10%
}
}
Для каждой ноты частота ШИМ обновляется установкой нового значения top. Это заставляет зуммер издавать нужную высоту тона.
Длительность ноты рассчитывается по темпу песни. Большую часть времени нота звучит, а небольшая часть остаётся тихой. Эта короткая тишина помогает отделить ноты друг от друга, благодаря чему мелодия звучит чище.
Зуммер включается установкой скважности 50 процентов и выключается установкой нуля.
Поддержание работы программы
После окончания мелодии этот цикл просто удерживает программу активной.
#![allow(unused)]
fn main() {
loop {
Timer::after_millis(100).await;
}
}
Клонируйте существующий проект
Можно клонировать (или использовать как образец) проект, который я создал, и перейти в папку buzzer-song.
git clone https://github.com/ImplFerris/pico2-embassy-projects
cd pico2-embassy-projects/buzzer-song
Версия на rp-hal
Если хотите увидеть тот же пример, реализованный с помощью rp-hal, его можно найти здесь.
git clone https://github.com/ImplFerris/pico2-rp-projects
cd pico2-rp-projects/got-buzzer