Среда, 24.04.2024, 15:21
Приветствую Вас Гость | RSS
Главная | Каталог статей | Регистрация | Вход
Меню сайта
Реклама Google
Форма входа
Категории раздела
Это нужно знать! [17]
Изучаем AVR [30]
Программаторы [12]
Необходимое ПО [8]
Готовые устройства [73]
Справочная [38]
Инструмент [0]
Технология [8]
Литература [0]
Arduino скетчи [18]
Поиск
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Микроконтроллеры - это просто!
Главная » Статьи » Arduino скетчи

Arduino. Генератор сигналов

При подключении к Arduino динамика с регулятором громкости, в качестве микропрограммы использовался скетч toneMelody из меню Examples->Digital, проигрывающий мелодию после сброса или включения Arduino. Если посмотреть, как устроен код этого скетча, то выясняется, что ноты воспроизводятся с помощью функции tone(), которая схожа с функцией delay() тем, что пока выполняется функция, программа ждёт окончания её выполнения.

Но что, если я захочу например подключить к Arduino несколько кнопок и играть разные ноты, или подключить потенциометр и менять тональность звучащей ноты? Ведь нота должна звучать пока нажата кнопка, то есть мне нужна возможность и воспроизводить звук, и опрашивать порты ввода-вывода одновременно.

Такая возможность у микроконтроллера Arduino есть, но для это мне потребуется освоить прерывания и программирование таймеров.

Методы генерации сигналов с помощью таймеров отличаются в разных режимах таймеров.

Генерация сигналов в нормальном режиме.
В нормальном режиме таймер-счётчик последовательно увеличивает значение регистра TCNTn (где n - номер счётчика) на каждом такте генератора, от которого таймер-счётчик приводится в действие. Когда значение регистра TCNTn достигает максимального, то на следующем такте происходит переполнение счётчика, регистр обнуляется и вызывается прерывание по переполнению TIMERn_OVF_vect, если вызов этого прерывания включен.

Соответственно, метод генерирования сигналов в нормальном режиме применяется один из двух.

В первом случае разрешается переключение состояния вывода OCRnx (где x - это A или B). Это удобно, поскольку не требует тратить на генерацию сигнала процессорного времени, но таким образом можно получить только ограниченное число частот - по количеству значений предделителя. То есть пять частот для таймеров 0 и 1, и 7 частот для таймера 2.

Поэтому чаще в нормальном режиме применяется второй метод, который состоит в том, по прерыванию в регистр TCNTn записывается новое значение счётчика, и таким образом количество частот, которые могут быть сгенерированы, увеличивается примерно в 250 раз для 8-битных таймеров и в 65535 раз для 16-битного таймера.

Тем не менее, второй способ более похож на программную реализацию режима CTC (очистки при совпадении), поэтому этот метод применяется в основном для использования ШИМ в качестве цифро-аналогового преобразователя.

Генерация сигналов в режиме CTC.
Для генерации сигналов в режиме CTC я добавил в схему подключения динамика к Arduino потенциометр R3, для того, чтобы регулировать частоту генерируемого сигнала.

Итак, я собираюсь генерировать сигнал аудиочастоты, то есть в диапазоне от 20 Гц до 22 кГц. Для этого я использую вывод Digital с номером 11, который соответствует выводу OCR2A, то есть выводу Compare Match A таймера-счётчика 2. 

Для установки таймера-счётчика 2 в режим CTC я должен установить биты WGM в значение 2 (бинарное 010). Чтобы включить режим переключения состояния вывода OCR2A при совпадении (Toggle on Compare Match) мне нужно установить биты COM2A в значение 1 (бинарное 01).

Поскольку в этом режиме при совпадении значений регистров OCR2A и TCNT2 происходит обнуление регистра TCNT2, то чем меньше значение регистра OCR2A, тем выше частота сигнала, а чем больше значение регистра OCR2A, тем частота ниже. Минимальная частота сигнала, которую я смогу получить с предделителем /1024, равна согласно формуле из документации, равна 16 МГц / (2 * 1024 * 256) = 30 Гц, а максимальная - 16 МГц / (2 * 1024 * 1) = 7812 Гц, что вполне укладывается в диапазон аудио-частот.

Для выбора в качестве источника тактовых импульсов для таймера-счётчика 2 предделителя /1024, я должен установить биты CS2 в значение 7 (бинарное 111).

Чтобы изменение состояния вывода OCR2A отображалось на состоянии вывода (пина) микроконтроллера, мне нужно перевести пин в режим вывода (OUTPUT).

Таким образом, я создаю новый скетч и добавляю следующий код:

#define R3_PIN       A0
#define SPEAKER_PIN  11

#define T2_WGM   0b010
#define T2_COMA  0b01
#define T2_CS    0b111

void setup() {
  TCCR2A = (T2_COMA << 6) | (T2_WGM & 0b011);
  TCCR2B = ((T2_WGM & 0b100) << 1) | T2_CS;
  OCR2A = 255;
   pinMode(R3_PIN, INPUT);
  pinMode(SPEAKER_PIN, OUTPUT);
}

Инициализация таймера-счётчика завершена, и теперь я добавляю опрос состояния потенциометра R3 для изменения частоты сигнала путём изменения значения регистра OCR2A. Поскольку функция analogRead() возвращает значение от 0 до 1023, то мне нужно его смасштабировать функцией map() в диапазион от 0 до 255.

Соответственно, код функции loop() в этом скетче выглядит так:

void loop() {
  OCR2A = map(analogRead(R3_PIN), 0, 1023, 0, 255);
}

Готово.

 

Генерация сигналов в режиме быстрого ШИМ (Fast PWM).
Использование микроконтроллера Arduino как генератора сигналов в режиме CTC довольно удобно тем, что для этой задачи не требуется процессорное время, но в то же время у этого режима есть существенное ограничение - с его помощью можно генерировать сигналы только определённого набора частот. Методом генерации сигналов в режиме быстрого ШИМ возможно получить большее количество частот, чем позволяет режим CTC.

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

Ниже приведён скетч, который демонстрирует генерирование нот на выводе ШИМ Digital 11, задаваемых пользователем по последовательному порту. Темп игры (длина ноты) задаётся с помощью потенциометра, подключенного к выводу Analog In 0.

Поскольку с конденсатором усилитель класса D звучал несколько странно, я немного изменил схему, удалив из неё конденсатор:

Скачать скетч можно, кликнув по ссылке.

Скомпилировав и загрузив скетч в память Arduino, откройте окно Serial Monitor и установите скорость обмена, заданную в скетче - 57600 бод. Чтобы проиграть гамму, отправьте в Arduino строку символов zxcvbnm, (символ запятая соответствует ноте до второй октавы). Соответственно, рок-н-ролл можно сыграть, отправив строку zcb.zcb.zcbnjnbc. (точка в данном скетче неопределённый символ, поэтому вместо неё будет проиграна пауза).

Записывая демо, я обратил внимание, что громкость нот зависит от их длительности. Спросив себя, почему так происходит, я вспомнил, что для спада ноты используется значение переменной playCounter, которое тем меньше, чем быстрее темп проигрывания нот. Таким образом, я добавил в скетч переменные decayCounter и decay, на основе которых реализовал спад ноты таким образом, чтобы громкость нот не зависела от их длины.

Чтобы облагородить звучание, я добавил в третью версия скетча эффект изменения частоты тона в начале проигрывания ноты. Для этого я добавил переменные счётчика тона toneCounter и приращения тона toneDelta. В третьей версии скетча при проигрывании ноты частота тона увеличивается до частоты ноты. Благодаря этому эффекту звучание стало похоже на электронный бас.

И чтобы стало совсем похоже на настоящий синтезатор, в четвёртую версию я добавил эффект реверберации. Размер буфера определяется константой BUFSIZE, размер которой я установил равным 1096 байт, что совпадает с приращением счётчика генератора волны для ноты до. Это даёт частоту цикла воспроизведения буфера равной 14.26 Гц для частоты дискретизации 15625 Гц. Такой размер буфера даёт более музыкальный саунд, нежели например буфер размером 1024 байта.

Версия скетча с ревербератором.

Затем я решил добавить обрезной фильтр нижних частот, и немножко поэкспериментировав остановился на фильтре восьмого порядка, который мне понравился тем, что в нижней половине регулировки работает как обычный обрезной фильтр НЧ, а в верхней половине добавляет в звук гармоник, которые придают звучанию трубный тембр.

Для регулировки фильтра я добавил в схему ещё один потенциометр, подключив его к выводу Analog In 1.

Версия скетча с цифровым фильтром.

В шестой версии скетча я решил сделать ревербератор стереофоническим, но для этого мне нужно было добавить к Arduino стереофонический линейный выход. Чтобы не слишком заморачиваться, я взял имевшийся под рукой низковольтовый однополярный операционный усилитель мощности KA2209 и на его основе собрал схему, практически повторяющую схему стерео-усилителя, приведённую в даташите.


Строго говоря, это не совсем линейный выход, а скорее выход для наушников с очень тихой громкостью, поскольку линейный выход - это выход с напряжениями плюс/минус 1 Вольт, а в данном случае напряжение только позитивной полярности. Но для этого потребовалось бы либо собрать мостовую схему с виртуальной землёй, либо использовать операционный усилитель с двуполярным питанием, каковое получать от преобразователя напряжения.

Тем не менее, поскольку линейный вход АЦП звуковой карты обычно оснащён автоматической подстройкой нуля (это сделано чтобы не возникало так называемых смещений несущей), то такой вариант как вариант дешёво и сердито я для себя счёл вполне приемлемым.

Версия скетча со стереофоническим ревербератором.

Категория: Arduino скетчи | Добавил: Alex (02.06.2014)
Просмотров: 10908 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Copyright MyCorp © 2024