Имитатор шума прибоя на attiny13 |
Автор ARV | |||||||||
21.09.2008 г. | |||||||||
Только не спрашивайте - зачем! Так уж вышло, что сначала возникла необходимость в нем, а когда был получен результат - необходимость пропала. Ну не пропадать же добру!? Возможно, кому-то пригодится в качестве игрушки, а кому-то алгоритм пригодится... В общем, вот что вышло.
Задача.Сделать генератор, имитирующий шум прибоя. То есть плавно нарастающий шипящий звук, затем так же плавно, но медленнее, спадающий до нуля. Через некоторое время тишины процесс повторяется. (В перспективе планировалось сделать регулируемой скорость «волн» и даже сделать ее случайной - но это требование отпало). Алгоритм.Прежде всего, пришлось решить проблему генерации шипения. Наиболее точно шипению соответствует белый шум, т.е. сигнал, спектр которого «плоский» и «бесконечный». Получение такого сигнала средствами микроконтроллера - нетривиальная задача. В общем случае, белый шум достаточно неплохо имитируется последовательностью прямоугольных импульсов случайной длительности, т.е. можно его получить при помощи ШИМ со случайным заполнением. Главное - получение этого самого «случайного» заполнения. Как известно, аппаратно последовательность импульсов псевдослучайной длительности, реализуется при помощи регистра сдвига с обратными связями через элементы «исключающее или», т.е. примерно по такой схеме:
Число триггеров в регистре сдвига - чем больше, тем более длинной получается неповторяющаяся последовательность импульсов на выходе элемента XOR. Число входов элемента XOR и номера триггеров, с выхода которых на этот элемент подаются сигналы, определяют «полином генератора», т.е., если не вдаваться в математические глубины, характер последовательности. Данная схема имеет одну особенность - если начальное состояние триггеров окажется нулевым - схема работать не будет. Реализация регистра сдвига элементарно реализуется оператором сдвига, элемент XOR - само собой соответствующим оператором, а «полином» - соответствующей константой, биты которой определят и номера разрядов, с которых берутся обратные связи.
Чтобы сгенерированный таким образом шум плавно нарастал по громкости, надо определиться и с характером этого процесса. Я избрал, как наиболее универсальный, табличный способ задания «огибающей», т.е. массив, числа в котором являются масштабными коэффициентами, на которые будут умножаться случайные числа, ну а само произведение будет задавать коэффициент заполнения ШИМ. Итак, алгоритм вырисовывается следующий: получаем случайное число при помощи нашего «генератора», умножаем его на очередной коэффициент из массива огибающей, результат записываем в регистр управления ШИМ-генератора. Через некоторое время эти действия повторяем - в результате наш белый шум будет промодулирован огибающей. Аппаратная поддержка.В микроконтроллере attiny13 имеется всего один аппаратный таймер, который будет использоваться для организации выборки значений огибающей из массива. Модуль захвата-сравнения этого таймера будет настроен на режим ШИМ, причем оба его канала (А и В) на работу в противофазе. Это сделано для того, чтобы иметь на выходе 2 противофазных сигнала, что позволит либо увеличить громкость звукоизлучателя (если он будет подключаться непосредственно к портам контроллера), либо организовать «световые» эффекты, подключив звукоизлучатель к одному выходу, а к другому - светодиод (тогда в такт «волнам» плавно будет вспыхивать и светодиод). Программа.Исходный текст получившейся программы на Си (WinAVR) приведен ниже.
#include <avr/io.h>
#define POLY (0xA001) /* полином генератора случайных чисел */
// константы, задающие характер шума #define SZ 128 /* размер массива огибающей */
//уровень громкости шума
// массив огибающей - 1/4 периода синуса
// прерывание по переполнению таймера - генерация огибающей
} int __attribute__((naked)) main(void) {
union{
} Собственно говоря, я надеюсь, что комментарии в тексте позволят разобраться в программе. Заострю внимание лишь на нескольких нюансах. Для функции main() используется атрибут naked - это позволяет сэкономить несколько байт памяти программ, что для attiny13 с его килобайтом памяти - совсем не лишнее.
При модуляции используется умножение 16-битного числа на 8-битное. По правилам Си результат будет приведен к наибольшему размеру из сомножителей, т.е. к 16 битам, что нас не устраивает из-за потери старших битов. Поэтому используется явное приведение типа первого множителя к unsigned long. C другой стороны, нас интересует только старший байт результата (который будет третьим из четырех - см. комментарии в тексте). Чтобы наиболее просто обратиться к третьему байту результата использована переменная-объединение (union) R. Такой подход позволяет сэкономить несколько байт крохотной памяти программ по сравнению с первым приходящим на ум способом получения того же результата (L>>16) & 0xFF. Итоги.Программа проверялась на макетной плате, к контроллеру подключались звукоизлучатели из китайских игрушек - один с сопротивлением катушки 16 ом, другой - 60. На мой «вкус» - шум вполне похож на шум волны, но несколько утомляет однообразием: слишком ритмичный... Хотя, возможно, кому-то наоборот понравится засыпать под этот ритм... Схема, ввиду ее примитивности, не приводится, надеюсь, номера выводов питания и выходов каналов А и В для ШИМ сумеют найти среди аж 8-и выводов attiny13 все желающие повторить это чудо. Константы, определяющие ритм прибоя, достаточно просто заменяются на соответствующие переменные, которые можно менять в программе либо по случайному закону (при помощи того же генератора случайных чисел), либо при помощи каких-то кнопок. Реализация этой части алгоритма пусть будет на совести тех, кого этот «микро-проект» заинтересует.
Добавить в любимые (10) | Просмотров: 144528
Только зарегистрированные пользователи могут оставлять коментарии. |