Динамик MB2
На вашем MB2 есть встроенный динамик — большое чёрное квадратное устройство с надписью «SPEAKER» в центре обратной стороны платы.
Динамик работает так: он перемещает воздух в ответ на сигнал с GPIO-вывода. Когда вывод динамика в высоком уровне (3,3 В), внутренняя диафрагма — «конус динамика» — выдвигается полностью наружу; когда вывод в низком уровне (GND), конус втягивается полностью внутрь. Когда воздух выталкивается наружу и втягивается обратно, он проходит через маленькое прямоугольное отверстие — «порт динамика» — на боковой стороне устройства. Если делать это достаточно быстро, перепады давления создадут звук.
При правильной схеме управления этот конус динамика можно было бы переместить в любое положение в своём диапазоне с помощью соответствующего тока. Это позволило бы довольно хорошо воспроизводить любой звук, как у «обычного» динамика. К сожалению, ограничения аппаратуры MB2, управляющей динамиком, означают, что доступны только крайние положения — полностью внутрь и полностью наружу.
Давайте выталкивать конус динамика наружу и внутрь 220 раз в секунду. Это создаст «квадратную» волну давления с 220 циклами в секунду. Единица «циклов в секунду» — герц; мы получим тон 220 Гц (музыкальная нота «ля» малой октавы, A3), который на этом пронзительном динамике звучит неплохо.
Мы сделаем так, чтобы тон звучал пять секунд, а затем прекратился. Важно помнить, что наша программа хранится во флеш-памяти MB2: тон будет начинаться снова при каждом сбросе или даже включении MB2. Если позволить тону звучать вечно, такое поведение быстро станет очень раздражающим.
Вот код (examples/square-wave.rs).
#![no_main]
#![no_std]
use cortex_m::asm;
use cortex_m_rt::entry;
use embedded_hal::{delay::DelayNs, digital::OutputPin};
use panic_rtt_target as _;
use rtt_target::rtt_init_print;
use microbit::{
hal::{gpio, timer},
Board,
};
/// «Период» — это время одного цикла. Он равен
/// 1/f, где f — частота в Гц. В этом случае
/// время измеряем в миллисекундах.
const PERIOD: u32 = 1000 / 220;
/// Количество циклов для пяти секунд звучания.
const CYCLES: u32 = 5000 / PERIOD;
#[entry]
fn main() -> ! {
rtt_init_print!();
let board = Board::take().unwrap();
let mut speaker_pin = board.speaker_pin.into_push_pull_output(gpio::Level::Low);
let mut timer = timer::Timer::new(board.TIMER0);
for _ in 0..CYCLES {
speaker_pin.set_high().unwrap();
timer.delay_ms(PERIOD / 2);
speaker_pin.set_low().unwrap();
timer.delay_ms(PERIOD / 2);
}
loop {
asm::wfi();
}
}