Даже на микроконтроллерах с ограниченными ресурсами можно реализовать многоголосую музыкальную шкатулку. ATtiny13 обладает 1 килобайтом флеш-памяти (чего хватает на 512 программных инструкций, включая вектора прерываний) и 64 байтами оперативной памяти

Описание

Для вывода звука используется широтно-импульсная модуляция (ШИМ, PWM), микроконтроллеры AVR реализуют широтно-импульсную модуляцию при помощи таймеров.

Поскольку ATtiny13 обладает только одним таймером, его приходится использовать как для генерации ШИМ-сигнала, так и для синхронизации по времени при генерировании звука.

Частота ШИМ должна быть не меньше 20кГц, чтобы его шум не был слышен. При работе микроконтроллера на частоте 9,6МГц, 8-битный таймер переполняется через каждые 256 тактов, 37500 раз в секунду.

Однако, эта частота слишком высока для формирования звука, поэтому используется делитель. В прерывании таймера некая переменная уменьшается на 1, а формирование очередного сэмпла звука происходит в основном теле программы, когда значение этой переменной достигнет нуля, после чего её значение увеличивается на величину делителя (в данном случае - 4). Такой подход позволяет выравнивать звучание, если формирование очередного сэмпла заняло больше времени чем 4 цикла таймера, при этом не сбивается периодичность вызыва обработчика прерывания по переполнению таймера.

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

Поскольку ATtiny не обладают аппаратной поддержкой операции умножения, то умножение при вычислении амплитуды сигнала является узким местом. Для того чтобы ускорить операцию умножения, функция, реализующая его, написана на ассемблере.

Используемые формы сигналов, а также значения частот и мелодия хранятся во флеш-памяти.

Формат мелодии

Вы можете создавать свои мелодии, формат довольно простой:

Каждая нота кодируется одним байтом, старшие 2 бита (7й и 6й) кодируют номер канала (0, 1, 2), или паузу (3).

Если старшие два бита приняли значения 0, 1, или 2, то они кодируют номер канала (голоса) и:

- Если следующий за ними бит (5й) установлен, значит за этой нотой идёт байт кодирующий громкость по этому каналу. Старшие 4ре бита кодируют начальную громкость обертонов (от 0 до 15), нижние - форманты. Громкость запоминается для канала, и эта и все последующие ноты будут звучать с заданной громкостью.

- Младшие 5ть бит (от 4го по 0й) кодируют ноту. 0 - означает остановка звучания на канале. Остальные значения (от 1 до 31) кодируют ноту с шагом в полутон, начиная от "фа#" малой октавы, заканчивая "до" третьей окатвы.

Если старшие два бита - оба единицы, то это означает паузу в тиках до следующей команды. Один тик - это 1/36,6 секунды (=23,7 мс). То есть допустимы паузы от 27,3 мс до 1,72 секунды.