четверг, 2 декабря 2021 г.

Генерация звука на ассемблере и ATtiny2313

Помимо дисплеев, светодиодов и прочих средств вывода информации воспринимаемой глазами, микроконтроллеры также способны управлять устройствами вывода звука. Полноценный mp3 плеер сделать на таком простом микроконтроллере как ATtiny2313 будет не просто т.к. он имеет не много памяти (2кб flash памяти) для хранения звуковой информации. Для решения данной проблемы могут быть использованы дополнительные микросхемы памяти связанные с микроконтроллером по интерфейсу например SPI но при этом программисту придется заняться алгоритмами декодирования звука формата mp3 в импульсы на пинах микроконтроллера для вывода звука. Самый простой способ сделать звук используя микроконтроллер - это подключить к его пину маломощный пьезодинамик и подавать на этот пин прямоугольные импульсы. Звуки, при этом, будут обогащены высшими гармониками и простое добавление фильтра не решит проблему полностью т.к. звуки могут быть разных частот и также могут сильно отличаться друг от друга частотами. Однако простые сигналы или простые мелодии, как например в старых часах или игрушках, таким способом генерировать можно. Так можно сделать например сирену для радиоуправляемой игрушки. Ещё звуки в таком формате не занимают много места в памяти. Чтобы генерировать звук определенной частоты, на микроконтроллере, лучше использовать аппаратный таймер т.к. используя его проще рассчитать результат. В ATtiny3213 есть 8ми битный таймер и 16ти битный. Используя второй, без предделителя, можно создавать импульсы с частотой от примерно 7 Гц до примерно 500кГц. 7 Гц - это уже частота инфразвука который человеческая слуховая система не воспринимает а 500кГц - это частота которая намного больше верхнего порога слышимости, поэтому данный диапазон частот подходит и следовательно второй таймер подходит для генерации звука. Если используется таймер то с ним лучше использовать какое нибудь прерывание (т.к. с флагами в основном цикле работать не очень удобно). Можно использовать например прерывание по совпадению или прерывание по переполнению. В первом случае, таймер считает до определенного числа после чего происходит прерывание. Во втором случае таймеру устанавливается определенное число от которого он считает до переполнения после чего происходит прерывание по переполнению. В обработчике прерывания происходит установка нового (или опять старого) числа а также изменение напряжения на пине. Большой разницы в том какой способ использовать нет. Выберем второй т.к. он уже ранее рассматривался в статье https://electe.blogspot.com/2020/08/attiny2313.html. Чтобы генерировать звуки можно например использовать массив в котором будут частоты и длительности. Программа будет перебирать данный массив делать импульсы с определенной частотой определенное время после чего делать импульсы с другой частотой и продолжать это делать в течении другого промежутка времени и так пока массив не закончиться после чего либо повторить заново либо ждать например нажатия кнопки. Для начала можно реализовать циклическое повторение, проверить результат а потом переделать для генерации звука в ответ на какие либо события будет не трудно. Чтобы определить число от которого должен считать таймер для создания импульсов определенной частоты а также определить количество импульсов которое должен пропустить микроконтроллер для формирования задержки, для данного случая, можно использовать формулы:
Где val - число от которого должен считать таймер, delay_counter_max - количество импульсов которое надо пропустить чтобы получилась задержка delay в секундах. Т.к. таймер 16ти битный а микроконтроллер 8ми разрядный то для хранения val в микроконтроллере есть два регистра и следовательно это число надо разделять на две части. Лучше всего это сделать "снаружи" микроконтроллера (чтобы его не перегружать и можно было использовать более простые языки вроде питона или js на которых решить данную проблему проще чем на ассемблере) а массив в микроконтроллер записать в готовом виде. Для формирования такого массива можно использовать программу внизу данной статьи. В верхнее поле вводятся частоты через запятую а в нижнее длительности. После нажатия кнопки "play" проиграется звук и выведется массив а также колличество элементов в нем деленое на 3. Имея массив можно организовать его перебор, в обработчике прерывания, используя операторы условного перехода и пропуска команды и написать программу:

Массив записывается в самом низу после директивы ".db". Eсли одной строки не хватает то на следующей строке, в начале, пишется ".db" (без кавычек) и продолжение массива. В строке 
CPI R17, 46
вместо 46 пишется число которое выдала программа внизу после массива. При этом надо помнить что у ATtiny2313 всего 2кб flash памяти а в регистр нельзя записать больше 255.
Видео по данной теме с тестом устройства:

Программа для генерации массива для генерации звука:
частоты через запятую->
длительности через запятую->

массив генерации звука:
delay_counter_max=

КАРТА БЛОГА (содержание)

2 комментария:

  1. Уважаемый автор, здравствуйте!
    Касается темы: "Генерация звука на ассемблере и ATtiny2313".
    Поясните, пожалуйста, природу образования сформированного массива звуков (тоны и длительности нот), и есть ли конкретная привязка данных
    массива к музыкальному звукоряду определенного регистра.
    Каким образом можно применить изложенный материал к написанию
    программы для реализации той или иной нотной записи?
    Личное: В познании языка и, тем более, в программировании микроконтроллеров, абсолютный новичок, поэтому в арсенале практических
    шагов больше тупиков, нежели практических решений.
    Объективно: Как сгенерировать код тона и длительность звучания любой
    ноты звукоряда? - из множества проработанных сайтов по данной тематике ответа не нашёл. Всё относительно и неопределённо.
    Как инженер-электрик, просмотрев представленный в блоге тематический
    реестр, был удивлён и восхищён широтой затронутого диапазона. Оценивая перечень тем, даже визуально, на Руси принято говорить : - Снимаю шляпу!.. По делам и честь!..
    Надеюсь на объективную информацию в раскрытии понимания основ затронутой тематики. Извините за многословие и, возможно, за некорректность поставленных вопросов в изложении.
    С уважением и надеждой - Никс.

    ОтветитьУдалить
  2. Уважаемый автор, здравствуйте!
    Как начинающий в познании языка Assembler, стою на позиции перехода от азов программирования к реальной практике. С большим интересом читаю материалы Вашего блога, тем более с учётом инженерного образования (инженер-электрик). В частности, остановил своё внимание на теме о генерации звуков. поскольку имею некоторую любительскую практику баяниста. Но, увы!.. Неумеющему плавать, даже лужа после дождя
    кажется океаном.
    Объективно:
    1. Можно ли считать значения массива звуков результатом расчета по приведённым формулам применительно к какому-то музыкальному произведению? Если да, то к какому?..
    2. В формуле определения значения "val" используется символ "f". Является ли этот символ отражением реальной частоты для применённой ноты в конкретном произведении? Имеется ввиду таблица частот музыкального звукоряда по всему диапазону октав.
    3. Каков конкретный расчёт длительностей нот по долям в соответствии с
    построением мелодики звучания? От целой ноты : 4/4 - 1/2 - 1/4 и т.д. , а именно: delay =?
    4. Почему в выражении CPI R17, 46 использована константа именно 46?
    5. Как изложены между собой в массиве Вашей программы коды тона и коды длительности используемых нот?
    6. Какова тактирующая частота МК применительно к данному расчёту?

    Заключение:
    Верно ли моё понимание при попытке написания программы для выбранной мелодии?
    - нотная запись;
    - расчёты "val" , delay и delay_counter_max для каждой ноты выбранной
    мелодии по изложенным в материале формулам;
    - значения "f" брать из таблицы частот звукоряда для каждой ноты с учётом
    октавы её расположения ;
    - остальное в соответствии с последовательностью листинга написанной
    Вами программы.
    Буду признателен и благодарен за любую информацию по затронутой теме.
    С уважением - Н.

    ОтветитьУдалить