Генератор регулируемой частоты на Arduino Nano — Сообщество «Электронные Поделки» на DRIVE2
Дело было вечером делать было нечего)
Итак, встречайте — генератор с частотомером на борту.
После успешного проекта по сборке пультоскопа решил собрать генератор и частотомер. Вот что из этого вышло:Формы сигнала: синус DDS, треугольник DDS, прямоугольник DDS, правая пила DDS, левая пила DDS.Характеристики взял с страницы автора”генерации таймером:Генерация прямоугольного сигнала 0.
4 Мгц,минимальный шаг регулировки частоты в диапазоне 0…2,8кГц — 1Гцсвыше 2,8кГц минимальный шаг постепенно возрастает.Регулировка коэффициента заполнения (скважности) 1.100%в диапазоне 1Гц.80кГц регулировка производится с разрешением 1%Свыше 80кГц разрешение (шаг) регулировки скважности увеличивается.
При изменении рабочей частоты в диапазоне 1Гц-80кГц выбранная скважность сохраняется,а при изменении частоты свыше 80кГц сбрасывается на 50 %,
но в режиме регулировки скважности её можно снова изменять.
Тех. Характеристики генерации сигнала через DDS:Почему-то в оригинальной статье автора алгоритма DDS о характеристиках нет ни слова.Указана только максимальная частота -65кГц.
Откуда её взял автор непонятно, я поставил ограничение на 100кГц C увеличением частоты сильно падает разрешение получаемого сигнала на высоких частотах.
А конкретно, в диапазонах:0…6,25 кГц — разрядность от 256 до 128 градаций6,25…12,5 кГц — разрядность от 128 до 64 градаций12,5…25кГц -разрядность от 64 до 32 градаций25кГц…50кГц -разрядность от 32 до 16 градаций50кГц…100кГц -разрядность от 16 до 8 градацийПомимо этого с увеличением частоты вырастает джиттер,особенно заметно на сигналах с резкими фронтами (прямоугольник, пила).Но на точно установленных частотах 6,25кГц ; 12,5кГц ; 25кГц; 50кГц; 100 кГц джиттера нет, их можно использовать для точных измерений. Остальные частоты для большинства применений тоже подойдут.Но если нужен идеальный сигнал -то только генерация таймером.”Во всех диапазонах DDS минимальный шаг регулировки частоты — 1Гц.Характеристики частотомера, измеряемая частота 1Гц … 7,999 МГц, при превышении частоты начинает привирать.Есть еще входы на вольтметр, он встроен в меню, но я его не использовал.
Полный размер
Плата устройства
За основу взял проект с сайта Ардуино.ру. Проект повторен и проверен несколькими комрадами. Я перевел меню на Русский язык, развел печатную плату и спаял)В проекте используется Arduino Nano, LCD Nokia 5110 и энкондер “одношаговый”.Управление: кнопка переключения режимов переключает последовательносинус DDS, треугольник DDS, прямоугольник DDS, правая пила DDS,
левая пила DDS. частота генерации таймером, скважность генерации таймером
Кнопка на энкодере переключает шаг изменения частоты 1000-1-10-100в режиме регулировки скважности(6) нажатие на кнопку переключает энкодер в режим (5).При старте есть возможность выбора режима, генератор-вольтметр. После обратного отсчета автоматом включается генератор.Подсветка включается комбинацией — удерживая кнопку энкондера нажать кнопку режима послеотпустить кнопку энкондера.
Файлы проекта будут доступны по ссылке
UPD //Проект запускается без танцев с бубнами, с первого раза.
Источник: https://www.drive2.ru/c/459214330949321469/
Генератор сигналов на AD9833
AD9833 – это программируемый генератор сигналов с низким энергопотреблением. Позволяет генерировать сигналы с частотой до 12.5МГц синусоидальной, треугольной и прямоугольной формы. Программирование осуществляется с использованием трехпроводного интерфейса SPI и не составляет труда.
Ниже приведены основные характеристики микросхемы:
- Цифровое программирование частоты и фазы.
- Потребляемая мощность 12.65 мВт при напряжении 3 В.
- Диапазон выходных частот от 0 МГц до 12.5 МГц.
- Разрешение 28 бит (0.1 Гц при частоте опорного сигнала 25 МГц).
- Синусоидальные, треугольные и прямоугольные выходные колебания.
- Напряжение питания от 2.3 В до 5.5 В.
- Трехпроводной интерфейс SPI.
- Расширенный температурный диапазон: от –40°C до +105°C.
- Опция пониженного энергопотребления.
Более подробную информацию вы можете найти в даташите.
В характеристиках также заявлено, что микросхема не требует внешних компонентов, но здесь производитель лукавит: обвязка и источник опорной частоты все же нужны. На Али продаются модули AD9833 с необходимой обвязкой и кварцевым генератором на 25 МГц, как раз с таким модулем я и собираюсь экспериментировать.
Данный модуль имеет следующие выводы:
- VCC – плюс питания для цифровых и аналоговых цепей генератора.
- DGND – цифровая земля.
- SDATA – вход данных интерфейса SPI. Передача осуществляется 16-битными словами.
- SCLK – вход тактового сигнала SPI. Используется второй режим работы: (CPOL = 1, CPHA = 0).
- FSYNC – выбор микросхемы. Перед началом передачи данных должен быть установлен в 0, по завершении в 1.
- AGND – аналоговая земля.
- OUT – выход генератора.
Попробуем подключить этот модуль к Ардуино и научиться им управлять.
Для начала ознакомимся с его функциональной схемой:AD9833 состоит из следующих основных частей: два регистра выбора частоты, аккумулятор фазы, два регистра выбора фазы и сумматор смещения фазы (вместе эти компоненты составляют генератор с цифровым управлением – NCO), SIN ROM для преобразования информации о фазе в амплитуду и 10-разрядный цифро-аналоговый преобразователь.
Из схемы видно, что данные с интерфейса SPI передаются в управляющий регистр, регистры выбора фазы и частоты. Именно они определяют сигнал на выходе генератора. И программирование генератора сводится к изменению содержимого указанных регистров. Это 16-разрядный регистр, управляющий работой генератора. Подробное описание его битов приведено ниже в таблице.
Схема из даташита также наглядно демонстрирует их назначение:
15, 14 | DB15, DB14 | Чтобы AD9833 понял, что принятое по SPI 16-битное слово содержит новое значение для управляющего регистра, два старших бита в слове должны быть установлены в 0. |
13 | B28 | Регистры частоты AD9833 имеют разрядность 28 бит, поэтому для изменения их содержимого требуется передача двух 16-битных слов. Однако в некоторых случаях требуется изменить только старшую или младшую часть регистра частоты. Здесь и используется данный признак: B28 = 1 говорит о том, что необходимо обновить регистр частоты целиком и его новое значение будет передано двумя последовательными записями. Первая запись содержит 14 младших бит, вторая 14 старших бит. Первые два бита в обеих записях определяют регистр частоты, в который будет записано передаваемое значение и должны быть одинаковыми. Обновление регистра частоты происходит после получения полного слова, поэтому запись промежуточного значения в регистр исключена. B28 = 0 позволяет обновить отдельно старшую или младшую часть регистра. Какая именно часть будет изменена определяется управляющим битом HLB. |
12 | HLB | Бит HLB определяет, какая из частей регистра частоты (младшая или старшая) будет перезаписана. Используется при B28 = 0. При B28 = 1 значение этого бита игнорируется. HLB = 1 позволяет обновить старшие 14 бит регистра частоты; HLB = 0 позволяет обновить младшие 14 бит регистра частоты. |
11 | FSELECT | Бит FSELECT определяет, какой из регистров используется в аккумуляторе фазы – FREQ0 или FREQ1. |
10 | PSELECT | Бит PSELECT определяет, данные какого из регистров PHASE0 или PHASE1 добавляются к выходу аккумулятора фазы. |
9 | Зарезервирован | Данный бит зарезервирован и должен быть установлен в 0. |
8 | RESET | RESET = 1 сбрасывает внутренние регистры генератора в 0. Сброс не затрагивает регистры управления, частоты и фазы. |
7 | SLEEP1 | При SLEEP1 = 1 запрещается внутреннее тактирование, приостанавливается работа NCO и выход генератора остается в своем текущем состоянии. При SLEEP1 = 0 тактирование разрешено. |
6 | SLEEP12 | При SLEEP12 = 1 отключается внутренний ЦАП. Это может быть полезно для генерации прямоугольных импульсов, при которой не требуется выполнение цифро-аналоговых преобразований. При SLEEP12 = 0 внутренний ЦАП активен. |
5 | OPBITEN | Данный бит вместе с битом MODE управляют выходом генератора. При OPBITEN = 1 внутренний ЦАП отключается от выхода VOUT и для генерации выходного сигнала используется значение старшего значащего бита с входа ЦАП, что позволяет получить на выходе генератора прямоугольные импульсы. |
4 | Зарезервирован | Данный бит зарезервирован и должен быть установлен в 0. |
3 | DIV2 | Используется в паре со значением OPBITEN = 1. При DIV2 = 1 значение старшего значащего бита данных с входа ЦАП подается напрямую на выход VOUT. DIV2 = 0 позволяет задействовать делитель частоты и уменьшить частоту выходного сигнала вдвое. При OPBITEN = 0 значение данного бита игнорируется. |
2 | Зарезервирован | Данный бит зарезервирован и должен быть установлен в 0. |
1 | MODE | Данный бит вместе с битом OPBITEN управляют выходом генератора. При OPBITEN = 1 бит MODE должен быть установлен в 0. Значение MODE = 0 позволяет получить на выходе генератора синусоидальный сигнал. При MODE = 1 на выходе будет треугольный сигнал. |
Зарезервирован | Данный бит зарезервирован и должен быть установлен в 0. |
И для лучшего понимания назначения битов OPBITEN, MODE и DIV2 я приведу таблицу с их допустимыми комбинациями и формой результирующих сигналов на выходе:
X | Синусоидальный | ||
1 | X | Треугольный | |
1 | Прямоугольный с частотой F/2 | ||
1 | 1 | Прямоугольный с частотой F | |
1 | 1 | X | Зарезервировано |
Генератор AD9833 имеет 2 регистра частоты и 2 регистра фазы разрядностью 28 бит и 12 бит соответственно.
Выбор активного регистра частоты осуществляется установкой управляющего бита FSELECT: при FSELECT = 0 активным является FREQ0; при FSELECT = 1 активен регистр FREQ1. Результирующая частота на выходе генератора определяется следующим образом:
(FMCLK / 228) * FREQREG,
где FMCLK – это опорная частота, FREQREG – значение, загруженное в активный регистр частоты. Таким образом, если мы хотим получить на выходе генератора сигнал с частотой 400Гц при опорной частоте 25МГц, в активный регистр должно быть загружено значение:
FREQREG = FOUT*228 / FMCLK = 400Гц * 228 / 25МГц ≈ 4295
Для того чтобы загрузить значение FREQREG в регистр частоты необходимо, старшие биты передаваемого по SPI значения установить в 01 для загрузки в FREQ0 или 10 для загрузки в FREQ1.
Напомню, что общение с AD9833 осуществляется по SPI 16-битными словами.
Фаза выходного сигнала определяется следующим образом:(2π / 212) * PHASEREG соответственно, значение для регистра фазы вычисляется по формуле:
PHASEREG = PHASE*212 / 2π
В приведенных формулах PHASEREG – это значение активного регистра фазы. Выбор активного регистра осуществляется установкой управляющего бита PSELECT: при PSELECT = 0 активным является PHASE0; при PSELECT = 1 активен регистр PHASE1.
При записи нового значения в регистр фазы старшие биты должны быть установлены в 11, а выбор регистра, в который должно быть записано значение, осуществляется установкой бита 13: при нулевом его значении будет обновлен регистр PHASE0; при установке указанного бита в 1 будет обновлен регистр PHASE1. 12й бит не используется, а биты с 0 по 11 содержат значение для регистра фазы.
Разрядность регистра частоты в 28 бит при опорной частоте 25МГц обеспечивает шаг 0.1Гц для установки частоты сигнала на выходе. А 12-битный регистр фазы обеспечивает разрешение 2π/4096.
Тестовая программа для AD9833 на Ардуино
Теперь мы можем написать первую программу для AD9833. Схема подключения модуля AD9833 к Ардуино и скетч приведены ниже.
С подключением все просто: общение с модулем происходит по интерфейсу SPI, для которого на Ардуино отведены следующие пины: D10 – SS (Slave Select – выбор ведомого), к нему подключаем вывод FSYNC модуля. D11 – MOSI (Master Out Slave In – выход ведущего, вход ведомого), к нему подключаем вывод SDATA. D13 – SCK (Serial Clock – Тактовый сигнал), к нему подключаем вывод SCLK. void setup() { SPI.begin(); WriteAD9833(0x2100); WriteAD9833(0x50C7); WriteAD9833(0x4000); WriteAD9833(0xC000); WriteAD9833(0x2000); } void WriteAD9833(uint16_t Data){ SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV2, MSBFIRST, SPI_MODE2)); digitalWrite(SS, LOW); delayMicroseconds(1); SPI.transfer16(Data); digitalWrite(SS, HIGH); SPI.endTransaction();
} void loop() { WriteAD9833(0x2000); delay(5000); WriteAD9833(0x2002); delay(5000); WriteAD9833(0x2020); delay(5000); WriteAD9833(0x2028); delay(5000); }В данном скетче выполняются следующие действия:
- При первом вызове функции WriteAD9833 производится установка управляющего регистра: бит RESET устанавливается в 1 для выполнения сброса; бит DB28 устанавливается в 1 для перезаписи всего содержимого регистра частоты; биты FSELECT и PSELECT содержат 0, поэтому для генерации выходного сигнала будут использоваться регистры FREQ0 и PHASE0.
- Следующие два вызова передают значение 4295 в регистр частоты FREQ0. Данное значение умещается в 14 младших разрядах, поэтому в старшие разряды регистра записываем нули.
- Сдвиг по фазе не требуется – запишем в регистр PHASE0 значение 0
- Последним вызовом WriteAD9833 в процедуре setup снимаем бит RESET, разрешая тем самым работу генератора. Результирующий сигнал поступает на вывод VOUT.
- Следующие вызовы WriteAD9833 в функции loop обновляют содержимое управляющего регистра, перебирая комбинации битов MODE, OPBITEN и DIV2 для генерации сигнала синусоидальной, треугольной и прямоугольной форм.
Вот как выглядит выходной сигнал генератора в виртуальном осциллографе:
Синусоидальный сигнал (биты MODE и OPBITEN сброшены в 0) |
Треугольный сигнал (MODE = 1, OPBITEN = 0) |
Прямоугольный сигнал (OPBITEN = 1, MODE = 0, DIV2 = 1) |
Прямоугольный сигнал (OPBITEN = 1, MODE = 0, DIV2 = 0) |
Обратите внимание: при генерации синусоидальных и треугольных импульсов, когда сигнал снимается с выхода ЦАП, его амплитуда изменяется в диапазоне -300мВ…300мВ. При генерации импульсов прямоугольной формы мы имеем дело с обычным цифровым сигналом с соответствующими уровнями напряжения. Так в последних двух осциллограммах логической единице соответствует напряжение ~4,5В.Разобравшись с управлением AD9833 можно приступать к созданию генератора с интерфейсом управления и индикацией. Для этого добавим в нашу схему энкодер вращения и жидкокристаллический дисплей:
Ранее я писал о том, как можно сделать меню на Ардуино с энкодером вращения. И сейчас я взял такое меню за основу скетча, добавив в него функционал для работы с AD9833. Скачать скетч можно по ссылке. При включении питания AD9833 настраивается на генерацию синусоидального сигнала частотой 100Гц, соответствующая информация отображается на дисплее. Вращая ручку энкодера можно изменять его частоту, а при нажатии вызывается меню. В меню доступны следующие опции:
- Установка частоты (можно задать произвольное значение от 1 до 12,5МГц).
- Установка фазы (0 – 360°).
- Выбор формы сигнала.
- Выбор значения, на которое изменяется частота при вращении ручки энкодера.
Остается только поместить все компоненты в подходящий корпус и получится законченное устройство. Результат работы в следующем ролике:
Источник: https://tsibrov.blogspot.com/2018/06/ad9833.html
Генератор с возможностью регулировки частоты и скважности за 100 руб — Community «Arduino для автомобиля» on DRIVE2
Был момент, мне как то понадобился генератор.Да ещё и со специфическими требованиями.Основной импульс с регулируемой частотой и скважностью+ пачка импульсов запускаемая по синхроимпульсу(можно от основного импульса)Пачка — с регулируемым количеством, скважностью и задержкой от основного импульса.
На днях подумал, что мало ли, может кому-то пригодится…такие специфические требования навряд ли у кого то будут,
а вот простой генератор с возможностью регулировки частоты и скважности может кому-то и пригодится.
Вырезал из кода все прибамбасы
касаемые генерации пачки по синхроимпульсу
и решил выложить сюда.
Информация о режиме, частоте и скважности выводится в терминал.Естественно, не нужно возлагать на него какие-то фантастические надежды.Это всего лишь программная генерация,чем выше частота, тем более искажёнными будут фронты.Частоту выжимал около 1 мГц,
если поменять кварц, то можно и более попробовать выжать.
Скетч и необходимые для работы библиотеки внизу страницы——————-#include “CyberLib.h”
#include // PWM должно быть заглавными буквами
bool p1, p2, p3;int pwm = 9; // the pin that the pwm outint32_t f=100; //стартовая частота
int duty=128; //стартовая скважность
bool success;
int mode=1;// 1 — частота ШИМ// 2 — ширина ШИМ// 3 — Сохранение настроек
// 4 — Загрузка настроек
void setup(){Serial.begin(115200);Serial.println(“Init device”);Serial.println(“mode: PWM Frequency HZ”);InitTimersSafe();
bool success = SetPinFrequencySafe(pwm, f);
D9_Out; //Настраиваем пин D9 на выход
// пины кнопокD4_In; //Настраиваем пин D4 на входD5_In; //Настраиваем пин D5 на вход
D6_In; //Настраиваем пин D6 на вход
D4_High;D5_High;
D6_High;
}
void loop(){label:p3=D4_Read;p2=D5_Read;
p1=D6_Read;
if (p1==LOW && p2==HIGH && p3==HIGH) //при нажатии кнопки 2 + кнопки 3{mode++;if (mode>5){mode=1;}switch (mode){case 1:Serial.println(“mode: PWM Frequency HZ”); // Частота сигнала
break;
case 2:Serial.println(“mode: PWM Duty %”); // Ширина импульса
break;
case 3:Serial.println(“mode: Save Data”); // Сохранение параметров
break;
case 4:Serial.println(“mode: Load Data”); // загрузка параметров
break;
// default:}delay_ms(300);
}
if (p3==LOW && p2==HIGH && p1==HIGH) //при нажатии кнопки 1 + кнопки 2{switch (mode){case 1: // если режим 1 (регулировка частоты), то прибавляем частотуf++;success = SetPinFrequencySafe(pwm, f);pwmWrite(pwm, duty);Serial.println(f);
break;
case 2: // если режим 2 (регулировка скважности), то прибавляем сважностьduty++;if (duty>255) duty=255;success = SetPinFrequencySafe(pwm, f);pwmWrite(pwm, duty);Serial.println(duty);
break;
case 3:WriteEEPROM_Long(0, f);WriteEEPROM_Byte(10, duty);Serial.println(“Data saved!”);
break;
case 4:f = ReadEEPROM_Long(0);duty = ReadEEPROM_Byte(10);success = SetPinFrequencySafe(pwm, f);
pwmWrite(pwm, duty);
Serial.println(“Data loaded!”);
break;}
delay_ms(100);
}
if (p2==LOW && p1==HIGH && p3==HIGH) //при нажатии кнопки 1 + кнопки 3{switch (mode){case 1: // если режим 1 (регулировка частоты), то отнимаем частотуf–;if (f
Источник: https://www.drive2.com/c/469956834430550966/
Генератор синусоиды на Arduino или ЦАП R-2R
Предыстория.
У меня есть хороший друг. Тоже «радиолюбитель», самоучка и весьма энергичный молодой человек. Так вот. Попался ему как-то в руки сгоревший «синим пламенем» источник бесперебойного питания (ИБП) – не лучший образец продукции «поднебесной». Починить его оказалось неподъемной задачей.
Однако, трансформатор оказался одним из «живучих» элементов, и Дима задумал изготовить небольшой преобразователь 12В в 220В для какого-то применения (в купе с автомобильным аккумулятором) на дачном участке.
Немного погуглив и собрав кучу распечаток из Интернета, он обратился ко мне (зная мои поделки на Ардуино) со странным вопросом: «А «красивую» синусоиду твоя Ардуина может генерить?»
А вот тут и начинается текст по делу 🙂 Итак. Синусоида.
Значит из цифр (которыми оперирует Ардуинка) нам нужно получить аналоговый сигнал… А значит нам нужен Цифро-Аналоговый Преобразователь (или ЦАП, или DAC -по ненашему).
Меня это не сильно испугало. Я уже сталкивался с ЦАП-ми, а конкретнее в детстве паял вариант R-2R.
Те, кто постарше наверняка помнят такие чудесные поделки, как Covox ( ). В те годы (примерно 90-ые), мне только доводилось мечтать о звуковой карте, а вот вышеупомянутое устройство, да еще сделанное своими руками – доставило столько приятных минут 🙂
Итак, сказано – сделано!
Ну, будучи до конца честным, признаюсь. Я для начала поискал готовые решения для Ардуино в просторах Интернета. (Вот один из вариантов, с применением ШИМ-сигнала: Не понравился.)
Итак, нам нужено изготовить простейший цифро-аналоговый преобразователь: R-2R.
Вот буржуйское описание:
(B7..B0 — это биты, B7 — старший, B0 — младший). Своё название (R-2R) данный ЦАП получил из-за номиналов применяемых в нём резисторов с сопротивлениями R и 2*R. Сопротивления по идее могут быть любыми (1k-2k; 10k-20k и т.д). Однако, я чаще всего встречал варианты с номиналами 1k и 2k. Как же эта штука работает? Каждый вход ЦАПа вносит свою лепту в выходной сигнал пропорционально своей «значимости». Т.е. левый вход оказывает самое большое влияние на выходной сигнал (половина опорного напряжения), следующий за ним ¼, следующий – 1/8 и т.д. Ну а самый последний (правый) вход изменяет выходной сигнал на ничтожные милливольты. Подставляя значение битов на входе ЦАП выходное напряжение можно рассчитать так:
Uвых=Uпит * (B7 * 1/2 + B6 * 1/4 + B5 *1/8+ B4*1/16+B3*1/32+B2*1/64+B1*1/128+B0*1/256).
Если выставить на вход ЦАП-а значение 255 (бинарное 11111111), то получаем самый высокий выходной сигнал. Если же 00000000 — ноль. Uпит – напряжение питания микроконтроллера.
Таким образом, наш восьмибитный ЦАП способен выдать 256 различных напряжений с шагом около 20 милливольт, при опорном напряжении 5 Вольт. Желательно чтобы ЦАП (8-ми разрядный, как у нас) был подключен к целому порту.
Тогда выводить любое значение в ЦАП — будет очень просто:
PORTD = 215;
Итак, прикидываем на макетке:Проверяем работоспособность, засылая в порт различные значения. Мультиметром замеряем напряжение на выходе — все очень хорошо. Можем двигаться дальше. С «железной» частью вроде как разобрались. Теперь математическая составляющая.
Вооружившись школьным учебником алгебры (шучу… шучу, конечно же Википедия!) вспоминаем, что такое Синусоида:
Адаптируем к нашим условиям. ЦАП может выдавать значения от 0 до 255. Причем, за нулевое значение (мы будем оперировать только целыми положительными числами) примем 127. Длительность волны примем 255 шажков (опять же для удобства). Т.е.
, для одного периода значение функции поменяется 255 раз. Естественно, чем больше «шажков» мы уместим в этот период, тем точнее получим синусоиду.Синим цветом я постарался обозначить значения напряжения, получаемые на выходе ЦАП, при «контрольных» значениях точек на оси Х.
Общая формула синусоиды:
Y=a+b*SIN(c*X)
Итак, наша синусоида стартует со значением 127 (для ЦАП) и заканчивается этим значением. Для этого, вводим значение смещения по оси У а=127. a характеризует сдвиг графика по оси Oy. Чем больше a, тем выше поднимается график.
Значение синуса может меняться от -1 до 1 (Кто бы мог подумать!!!). Чтобы растянуть график по вертикали, вводим второе значение b, характеризующее растяжение графика по оси Oy. Чем больше увеличивается b, тем сильнее возрастает амплитуда колебаний; Ну, тут тоже понятно, что при максимальном значении в (254-127) b=127
с характеризует растяжение графика по оси Ox.
Длина периода =2*Pi. Мы условились, что этот период мы делим на 255 «шагов». Т.е., 255-ый шаг должен иметь значение 2*Pi. Для нашего случая С=2*Pi*(1/255) или 2*Pi*0.0392 или Pi*0.007843
Окончательно получаем следующую формулу расчета: Y=127+127*SIN(Pi*X*0.007843).
(Желающие получить БОЛЕЕ точные результаты, могут использовать, допустим 512 шажков. Только нужно пересчитать константу). Давайте проверим нашу формулу на «ключевых» значениях X:
0 (0) = 127 64 (Pi/2) =253 128(Pi) =125 192 (3*Pi/2) =0
255 (2Pi) =126
Весьма правдоподобно. Итак далее, тут можно поступить двумя способами: высчитывать значение по ходу дела – способ НАВЕРНЯКА не самый быстрый, а можно заранее рассчитать эти значения и брать их из таблицы. Я предпочел второй способ. Программист из меня не важный (Бейсик – в детстве, Паскаль – в школе, ФОРТРАН – в институте), поэтому я не стал тратить время на поиски того же Борланд паскаля или изучение Питона, «напрягом» знакомого программиста… Как впрочем и на калькуляторе высчитывать 255 значений мне показалось «времярасточительным» занятием. НО у меня же есть Ардуинка! (И я ОЧЕНЬ стараюсь использовать ее по полной программе.). Вот ее и заставим произвести нужные мне расчеты. /* Расчет таблицы для значений синусоиды, с выводов в монитор ком-порта */ void setup(){ Serial.begin(9600); } void loop(){ for (int i=0;i 2 – сдвигаем (отбрасываем первые 2 бита, которые будем выводить в порт Б // (PORTC & 0b11000000) | (i >> 2) выставляем только оставшиеся 5 бит в порту С PORTC = (PORTC & 0b11000000) | (i >> 2); // (PORTB & 0b11100111) – обнуляем только три используемых бита // (i & 0b00000011) – обнуляем неиспользуемые биты // (PORTB & 0b11100111) | (i & 0b00000011) – выставляем нужные биты в порту Б PORTB = (PORTB & 0b11100111) | (i & 0b00000011); } #define offset 128 void loop() { for (int i = 0, j = i + offset; i < 256; i++, j++) { PORTD = sin_tab[i]; pp(sin_tab[j]); if (j == 255) j = 0; delayMicroseconds(75); } } Делаем контрольный замер, подключив выходы ЦАП-ов к осциллографу (красиво совмещаем выдаваемые Ардуинкой синусоиды):Красота! То, что и желали получить. Все, мой приятель остался очень доволен. Я отдал ему прошитую Atmeg-у для дальнейшего применения. Про дальнейшую судьбу его устройства — это отдельная история, не входящая в рамки данного опуса. P.S. Вот фото того устройства, ради которого все это и было проделано 🙂
Источник: http://robocraft.ru/blog/2911.html
Генератор сигнала (т.н. функциональный генератор) может быть использован для тестирования и отладки схем. Я часто использую его для проверки частотных характеристик электронных компонентов, например ОУ и датчиков. Этот генератор сигналов построен на плате Arduino.
Он может выдавать четыре типа сигнала: синусоидальный, треугольный, прямоугольный и пилообразный, частота каждого из которых может регулироваться от 1Гц до 50 кГц. Частота, длительность импульса и амплитуда (усиление) сигналов управляется тремя потенциометрами.
Я также добавил опциональный светодиодный индикатор, который указывает какой сигнал сейчас на выходе.
Список деталей:
(4x) Миниатюрная кнопка с фиксацией.
(8x) Резистор 10кОм 0.25Вт.
(9x) Резистор 20кОм 0.25Вт.
(1x) Потенциометр 50кОм.
(1x) Потенциометр для регулировки громкости для компенсации нелинейности человеческого слуха 10кОм.
(1x) Потенциометр со встроенным выключателем 10кОм.
(1x) Стерео аудио разъем 1/8.
(1x) Керамический дисковый конденсатор 1000пФ 50В.
(1x) Резисторы 4,7кОм 0.25Вт.
(1x) 8 контактная панелька для микросхем.
(1x) ОУ LM386.
(2x) Электролитический конденсатор 220мкФ 35В(любой от 200 до 300мкФ).
(1x) Arduino Uno REV 3.
(1x) Arduino Proto Shield.
(4x) Белый супер яркий светодиод.
(4x) Резистор 740 Ом 0.25Вт.
(1x) Резистор 300 Ом 0.25Вт.
Дополнительные материалы:
Термоусадка.
Провод №22.
Припой.
Дрель со сверлами.
Термоклей.
Клей
Подготовка Arduino Proto Shield
Arduino Proto Shield – это удобный способ добавления своей схемы к Arduino, но я решил немного его урезать, чтобы он занимал меньше места в корпусе. Сначала я укоротил выводы при помощи кусачек. Потом я убрал шести контактный разъем. После этого я удалил разъемы с верхней части платы.
Корпус
Я решил использовать лазерный резак для изготовления корпуса. Я разработал корпус используя AutoCAD, Autodesk 123D Make, и Corel Draw. Все файлы проекта можно скачать внизу статьи. Если у вас нет доступа к лазерному резаку, вы можете сделать все детали корпуса вручную по двумерным чертежам.
На картинке показаны отверстия на передней панели:
(3x) 7мм отверстие для потенциометров усиления, частоты и ШИМ.
(3x) 7мм отверстие для четырех кнопок – синусоидальный, треугольный, прямоугольный и пилообразный сигналы.
(1x) 10мм отверстие для аудио разъема.
Я вырезал изображения всех четырех сигналов для того чтобы их можно было подсвечивать, но вы можете просверлить простые отверстия 5мм для светодиодов под каждой кнопкой.
Также есть прямоугольное (высота11мм, ширина 12 мм) отверстие для USB-порта Arduino в задней части устройства.
Я сделал корпус из дерева, поэтому мне пришлось склеивать все его части кроме задней панели, которое я приклею после сборки устройства.
Пайка проводов к кнопкам
Припаяйте 10 кОм резистор к одному из выводов каждой кнопки. Припаяйте зеленый провод к месту соединения кнопки и резистора и красный провод к резистору как показано на фото. Черный провод припаяйте к другому контакту кнопки. Все эти соединения надо заизолировать термоусадкой во избежание короткого замыкания.
Установка аудио разъема
Свинтите пластиковый корпус с аудио разъема. Припаяйте красный провод к двум стерео контактам и черный провод к GND как показано на фотографии. Я использовал термоклей для предотвращения короткого замыкания и дополнительной фиксации проводов и пайки. После этого, вставьте гнездо в отверстие в корпусе и закрепите его термоклеем.
Установка кнопок
Снимите с кнопок верхнюю часть и установите их в корпус, зафиксировав термоклеем. После его высыхания, установите верхнюю часть кнопок обратно.
R2R ЦАП на Arduino Shield
Припаяйте восемь резисторов 20кОм на Arduino Proto Shield. Один из выводов каждого резистора должен быть подключен к цифровым контактам Arduino 0-7.
Припаяйте семь резисторов 10кОм на Arduino Proto Shield так, чтобы они были между выводами ранее припаянных восьми резисторов 20 кОм.
Припаяйте резистор 10кОм на Arduino Proto Shield так, чтобы один вывод резистора 10кОм был присоединён к цифровому контакту 0 Arduino, а другой вывод к GND.
Панелька для микросхем
Использовать панельки для микросхем хорошо, потому что благодаря им микросхема не перегревается при пайке и может быть легко заменена в случае поломки. Припаяйте панельку для микросхемы, как показано на фотографии.
Фильтр нижних частот
В качестве ФНЧ (Фильтр Нижних Частот) выступают резистор и конденсатор, соединенные последовательно. ФНЧ пропускает низкие частоты и подавляет ступеньки на сигнале.
Вот как я рассчитал номиналы компонентов в своем ФНЧ:
Частота среза = 1/(2*pi*R*C)
Согласно теореме Найквиста, сигналы не может иметь частоту больше чем половина частоты дискретизации. Если бы я использовал частоту дискретизации 100 кГц, то максимальная возможная частота была бы 50 кГц.
Если я использую резистор 300 Ом, и хочу иметь частоту среза 50 кГц:
50000 = 1/(6.28*300*C)
C = 1.06*10^-8 F
Если немного округлить:
C = 0.01 мкФ
Подключите один вывод резистора 300 Ом к резистору 10 кОм, подключенному к цифровому выводу 7. Подключите конденсатор к другому выводу резистора 300 Ом. Второй вывод конденсатора подключается к GND.
Усилитель
Подключите положительный вывод конденсатора 220мкФ к соединению резистора и конденсатора в ФНЧ. Второй вывод конденсатора 220мкФ подключается к резистору 20 кОм, второй вывод которого подключается к 3 выводу панельки для микросхемы. Резистор 4.7 кОм подключается между 3 и 4 контактами панельки. К 4 выводу панельки подключается GND.
Подключите положительный вывод второго конденсатора 200мкФ к 5 контакту панельки. Позже, второй его вывод будет к подключен к потенциометру «Усиление». Подключите 6 контакт панельки к Vin, 2 контакт к GND и вставьте микросхему в панельку.
Подключение потенциометра “Усиление”
Громкость или усиление звукового сигнала будет управляться аудио потенциометром 10 кОм с выключателем. Подключите выход усилителя и GND к потенциометру, как показано на фото. Средний контакт это аудио выход, который будет подключен непосредственно к разъему.
Также подключить провода к нижнему и левому контактам сзади как на фотографии. Это выключатель, который потом будет подключен к питанию.
Подключение батареи
Подключить черный провод от разъема для батареи к GND Arduino Shield. Один провод от выключателя в потенциометре подключите к красному проводу, а второй провод от выключателя потенциометра к Vin Arduino Shield. Пока не подсоединяйте батарею.
Подключение аудио разъема
Соедините выход усилителя (отрицательный вывод конденсатора подключенного к 5 пятому выводу панельки) с красным проводом присоединенным к аудио разъему раньше. Черный провод подключите к GND Arduino Shield.
Подключение кнопок
Подключите все красные провода от кнопок к 5В и все черные провода к GND Arduino shield. Подключите зеленые провода к аналоговым контактам 0-3 в следующем порядке:
Аналоговый контакт 0 = Прямоугольный
Аналоговый контакт 1 = Треугольный
Аналоговый контакт 2 = Пилообразный
Аналоговый контакт 3 = Синусоидальный
Подключение потенциометров “Частота” и ШИМ
Подключите красный, черный, и зеленый провода к потенциометрам 10кОм и 50кОм, как показано на фотографии. Подключите красный провод к 5В и черный провод к GND Arduino shield. Подключите зеленые провода к аналоговым контактам 4 (ШИМ) и 5 (Частота).
Установка потенциометров
Снимите шайбы и гайки с потенциометров перед установкой в корпус, чтобы позволить им стать вплотную с деревом. После установки потенциометров закрепите их гайками.
Подключение светодиодов
Подсоедините резистор 470 Ом к катоду каждого из четырех светодиодов. Припаяйте черный провод ко второму выводу резистора и красный провод к аноду светодиода. Заизолируйте всё термоусадкой во избежание короткого замыкания. Припаяйте черные провода от всех четырех светодиодов на GND Arduino shield. Припаяйте красные провода к цифровым контактам 8-11.
Установка светодиодов
Приклейте светодиоды в корпусе так, что каждый из них подсвечивал один символ на передней панели :
Цифровой контакт 8 = Прямоугольный
Цифровой контакт 9 = Треугольный
Цифровой контакт 10 = Пилообразный
Цифровой контакт 11 = Синусоидальный
Черный свето рассеиватель
Приклейте свето рассеиватель на вырезы в передней панели с внутренней стороны. Я использовал кусок черного пластикового мешка для мусора.
Программа
Прошейте Arduino кодом в файле function_generator.ino. В коде используются прерывания по таймеру на частоте 100 кГц для отправки новых данных в ЦАП. Остальная часть кода следит за состоянием кнопок и потенциометров. Так как прерывания происходят на высокой частоте, я должен сделать программу обработки прерываний в ISR(TIMER1_COMPA_vect){} как можно короче.
Математические операции с плавающей точкой и с помощью функции sin() занимают слишком много времени. Я рассмотрел с нескольких проектов, и получил это: Для треугольного и пилообразного сигнала я создал переменные sawByte, triByte, sawInc, и triInc.
Каждый раз, когда частота меняется, я подсчитываю сумму на которую частота треугольного и пилообразного сигналов должна измениться с частотой 100 кГц:
triInc = 511/period; if (triInc==0){ triInc = 1; } sawInc = 255/period; if (sawInc==0){ sawInc = 1; }
То есть все, что должно быть сделано в прерывании, является простой математикой:
case 1://triangle if((period-t) > t); if (t == 0){ triByte = 0; } else{ triByte += triInc; } } else{ triByte -= triInc; } if (triByte>255){ triByte = 255; } else if (triByte
Источник: http://shemopedia.ru/generator-signalov-na-arduino.html
Ускоряем свою Arduino
Месяца 3 назад, как и многие горе-электроники, купил себе на мой тогдашний взгляд самую навороченную микропроцессорную плату из семейства Arduino, а именно Seeeduino Mega, на базе процессора Atmega1280.
Побаловавшись всласть вращающимся сервоприводом и моргающим светодиодом, встал вопрос: «зачем же я её купил?». Я работаю одним из ведущих конструкторов на одном крупном военном Зеленоградском заводе, и в данный момент веду проект по разработке метрологического средства измерения.
В данной задаче существует бесконечное множество проблем, которые требуют индивидуального решения. Одной из таких задач является управление шаговым двигателем без шумов и с шагом не 1.8 градуса, как сказано в документации шагового двигателя, а до 0.0001 градуса.
Казалось бы, задача сложна и нерешабельна, но, повозившись немного со схемами управления, пришёл к выводу, что всё реально и возможно. Требуется только генерация двух сигналов специфичной формы и со сдвигом фаз и частотой изменения напряжения до 1 МГц.
(Подробное исследование шагового мотора и раскрытие всех тайн управления напишу в следующей статье) Сразу же в голове стали появляться проблески надежды, что я не зря потратил 1500 рублей на свою красненькую Seeeduino, и я, набравшись энтузиазма, начал разбираться.
Первоначальный ужас:
Подключив микропроцессорную плату к осцилографу, и написав цикл digitalWrite(HIGH), и ниже digitalWrite(LOW), на осцилографе обнаружил довольно унылый меандр с частотой 50Гц. Это кошмар. Это крах, подумал я, на фоне требуемых 1Мгц.
Далее, через осцилограф, я изучил еще несколько скоростей выполнения: AnalogRead() — скорость выполнения 110 мкс. AnalogWrite() — 2000 мкс SerialPrintLn() — при скорости 9600 около 250мкс, а при максимальной скорости около 3мкс.
DigitalWrite() — 1800мкс DigitalRead() — 1900мкс На этом я, всплакнув, чуть не выкинул свою Seeeduino. Но не тут-то было!
Глаза боятся, руки делают!
Не буду рассказывать свои душевные муки и описывать три долгих дня изучения, лучше сразу скажу всё как есть!
Подняв всю возможную документацию на Arduino и на процессор Atmega1280, исследовав опыт зарубежных коллег, хочу предложить несколько советов, как заменять чтение/запись:
Улучшаем AnalogRead()
#define FASTADC 1 // defines for setting and clearing register bits #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif void setup() { int start ; int i ; #if FASTADC // set prescale to 16 sbi(ADCSRA,ADPS2) ; cbi(ADCSRA,ADPS1) ; cbi(ADCSRA,ADPS0) ; #endif Serial.begin(9600) ; Serial.print(“ADCTEST: “) ; start = millis() ; for (i = 0 ; i < 30000 ; i++) analogRead(0) ; Serial.print(millis() - start) ; Serial.println(" msec (30000 calls)") ; } void loop() { }
Результат: скорость 18,2 мкс против бывших 110 мкс.
Кстати, максимальная скорость АЦП Атмеги как раз 16мкс. Как вариант — использовать другую микросхему, заточенную именно под АЦП, которая позволит уменьшить скорость до 0,2мкс (читать ниже, почему)
Улучшаем digitalWrite()
Каждая Arduino/Seeeduino/Feduino/Orduino/прочаяduino имеет порты. Каждый порт — 8 бит, которые сначала надо настроить на запись. Например, на моей Seeeduino PORTA — c 22 по 30 ножку. Теперь всё просто.
Управляем с 22 по 30 ножки с помощью функций PORTA=B00001010 (битовая, ножки 23 и 25 — HIGH) или PORTA=10 (десятичная, всё так же)
Результат = 0,2мкс против 1800мкс, которые достигаются обычным digitalWrite()
Улучшаем digitalRead()
Практически то же самое, что и в улучшении с digitalWrite(), но теперь настраиваем ножки на INPUT, и используем, например: if (PINA==B00000010) {…} (если на ножке 23 присутствует HIGH, а на 22 и 24-30 присутствует LOW)
Результат выполнения этого if() — 0.2мкс против 1900мкс, которые достигаются обычным digitalRead()
Улучшаем ШИМ модулятор, или analogWrite()
Итак, есть данные, что digitalRead() исполняется 0,2мкс, и ШИМ модулятор имеет дискретность 8 разрядов, минимальное время переключения ШИМ 51,2мкс против 2000 мкс. Используем следующий код:
int PWM_time=32; //Число, которое мы как бы хотим записать в analogWrite(PIN, 32) for (int k=0;k
Источник: https://habr.com/post/141442/
Vanyamba uses Linux – 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 (очистки при совпадении), поэтому этот метод применяется в основном для использования ШИМ в качестве цифро-аналогового преобразователя.
Итак, я собираюсь генерировать сигнал аудио-частоты, то есть в диапазоне от 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 >5); // Спад ноты (decay) while(waitForInterrupt); // Ожидание прерывания OCR2A = (out >> 8) & 0xFF; // Вывод текущего значения волны на вывод ШИМ OC2A waitForInterrupt = true; // Установка флага ожидания прерывания }}
unsigned int getNote(char key) // Преобразование клавиши в приращение счётчика{ // генератора волны for(unsigned char n = 0; n < 14; ++n) { if (keys[n] == key) { return notes[n]; } } return notes[0]; // Если клавиша не определена, проиграть паузу}
Скачать скетч можно, кликнув по ссылке.
Скомпилировав и загрузив скетч в память 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 Вольт, а в данном случае напряжение только позитивной полярности. Но для этого потребовалось бы либо собрать мостовую схему с виртуальной землёй, либо использовать операционный усилитель с двуполярным питанием, каковое получать от преобразователя напряжения.
Тем не менее, поскольку линейный вход АЦП звуковой карты обычно оснащён автоматической подстройкой нуля (это сделано чтобы не возникало так называемых смещений несущей), то такой вариант как вариант дешёво и сердито я для этой проекта счёл вполне приемлемым.
Версия скетча со стереофоническим ревербератором.
Демо скетча со стереофоническим ревербератором.
Источник: https://sites.google.com/site/vanyambauseslinux/arduino/arduino-generator-signalov
Урок 37. Широтно-импульсная модуляция в Ардуино
В уроке узнаем о широтно-импульсной модуляции, о реализации этого способа управления в контроллерах Ардуино, о режимах и функциях работы с ШИМ в Ардуино.
Предыдущий урок Список уроков Следующий урок
Прервемся на урок от разработки контроллера холодильника, для того чтобы научиться работать с широтно-импульсным модулятором Ардуино.
В нашей разработке используется именно такой способ регулирования мощности на элементе Пельтье.
Широтно-импульсная модуляция.
Широтно-импульсная модуляция (ШИМ) это способ управления мощностью на нагрузке с помощью изменения скважности импульсов при постоянной амплитуде и частоте импульсов.
Можно выделить две основные области применения широтно-импульсной модуляции:
- Во вторичных источниках питания, различных регуляторах мощности, регуляторах яркости источников света, скорости вращения коллекторных двигателей и т.п. В этих случаях применение ШИМ позволяет значительно увеличить КПД системы и упростить ее реализацию.
- Для получения аналогового сигнала с помощью цифрового выхода микроконтроллера. Своеобразный цифро-аналоговый преобразователь (ЦАП). Очень простой в реализации, требует минимума внешних компонентов. Часто достаточно одной RC цепочки.
Принцип регулирования с помощью ШИМ – изменение ширины импульсов при постоянной амплитуде и частоте сигнала.
На диаграмме можно увидеть основные параметры ШИМ сигнала:
- Ui – амплитуда импульсов ;
- Ton – время активного (включенного) состояния сигнала;
- Toff – время отключенного состояния сигнала;
- Tpwm – время периода ШИМ.
Даже интуитивно понятно, что мощность на нагрузке пропорциональна соотношению времени включенного и отключенного состояния сигнала.
Это соотношение определяет коэффициент заполнения ШИМ:
Kw = Ton / Tpwm.
Он показывает, какую часть периода сигнал находится во включенном состоянии. Может меняться:
- от 0 – сигнал всегда выключен;
- до 1 – сигнал все время находится во включенном состоянии.
Чаще используют процентный коэффициент заполнения. В этом случае он находится в пределах от 0 до 100%.
Среднее значение электрической мощности на нагрузке строго пропорционально коэффициенту заполнения. Когда говорят, что ШИМ равен, например, 20%, то имеют в виду именно коэффициент заполнения.
Формирование аналогового сигнала.
Если сигнал ШИМ пропустить через фильтр низких частот (ФНЧ), то на выходе фильтра мы получим аналоговый сигнал, напряжение которого пропорционально коэффициенту заполнения ШИМ.
U = Kw * Ui
В качестве ФНЧ можно использовать простейшую RC цепочку.
Из-за неидеальной характеристики такого фильтра частота среза должна быть минимум на порядок меньше частоты ШИМ. Для простого RC фильтра частота среза вычисляется по формуле:
F = 1 / (2 π R C).
- При повышении частоты среза ФНЧ на выходе фильтра увеличиваются пульсации с частотой ШИМ.
- При уменьшении частоты среза фильтра снижается время реакции выходного аналогового сигнала на изменения ширины импульсов.
Из этого вытекает главный недостаток широтно-импульсной модуляции. Метод способен синтезировать только достаточно медленные аналоговые сигналы или требует применения фильтров низких частот с высокой добротностью, сложных в реализации.
Я бы рекомендовал:
- В случае, когда к быстродействию аналогового сигнала жестких требований нет выбирать заведомо заниженную частоту среза фильтра.
- Если необходимо оптимизировать быстродействие аналогового преобразователя, то лучше промоделировать схему.
Даже простейшие моделирующие программы вычисляют уровень пульсаций достаточно точно. Вот результаты моделирования на SwCAD для ШИМ частотой 500 Гц и RC фильтрами с частотами среза 500 Гц, 50 Гц и 5 Гц. Зеленым цветом показана диаграмма ШИМ, синим – напряжение на выходе RC фильтра.
Частота среза 500 Гц (10 кОм, 32 нФ).
Частота среза 50 Гц (10 кОм, 320 нФ).
Частота среза 5 Гц (10 кОм, 3,2 мкФ).
Точность преобразования широтно-импульсных модуляторов определяется погрешностью амплитуды импульсов (т.е.
стабильностью питания микроконтроллера) и значением падения напряжения на ключах цифровых выходов микроконтроллера. Как правило, точность ШИМ микроконтроллеров невысока.
Добиться высокой точности ШИМ преобразования можно с помощью дополнительной схемы с аналоговыми ключами и источником опорного напряжения.
К недостаткам использования широтно-импульсных модуляторов в качестве ЦАП также следует отнести высокое выходное сопротивление. Оно определяется сопротивлением резистора RC фильтра и не может быть низким из-за малой нагрузочной способности выходов микроконтроллера.
Широтно-импульсные модуляторы в Ардуино.
Платы Ардуино на базе микроконтроллеров ATmega168/328 имеют 6 аппаратных широтно-импульсных модуляторов. Сигналы ШИМ могут быть сгенерированы на выводах 3, 5, 6, 9, 10, 11.
Управление аппаратными ШИМ осуществляется с помощью системной функции analogWrite().
void analogWrite(pin, val)
Функция переводит вывод в режим ШИМ и задает для него коэффициент заполнения. Перед использованием analogWrite() функцию pinMode() для установки вывода в режим “выход” вызывать необязательно.
Аргументы:
- pin – номер вывода для генерации ШИМ сигнала.
- val – коэффициент заполнения ШИМ. Без дополнительных установок диапазон val от 0 до 255 и соответствует коэффициенту заполнения от 0 до 100 %. Т.е. разрядность системных ШИМ в Ардуино 8 разрядов.
analogWrite(9, 25); // на выводе 9 ШИМ = 10%
Частота ШИМ Ардуино 488,28 Гц.
Для генерации ШИМ используются все три таймера Ардуино.
Таймер | Используется для генерации ШИМ на выводах |
Таймер 0 | выводы 5 и 6 |
Таймер 1 | выводы 9 и 10 |
Таймер 2 | выводы 3 и 11 |
Если таймер используется для других целей, например для прерывания, то параметры ШИМ соответствующих выводов могут не соответствовать указанным выше.
Поэтому, при использовании библиотек MsTimer2, TimerOne или им подобных некоторые выводы в качестве ШИМ сигналов использовать нельзя.
Увеличение частоты и разрядности ШИМ Ардуино.
Система Ардуино устанавливает на всех выводах ШИМ параметры:
- частота 488,28 Гц;
- разрешение 8 разрядов (0…255).
Очень низкая частота. Для большинства приложений совершенно не допустимая.
В разработке контроллера элемента Пельтье, начатой в предыдущем уроке, частота ШИМ должна быть не менее 30-50 кГц. В интернете достаточно много предложений по увеличению частоты ШИМВо всех описываются методы увеличения частоты до 31 кГц. В принципе приемлемый вариант, но мне захотелось большего.
Я разобрался с Таймером 1 микроконтроллера ATmega168/328, перевел ШИМ в быстродействующий режим и добился частоты ШИМ Ардуино до 62,5 кГц. Заодно я научился менять разрядность ШИМ. Чтобы в следующий раз не копаться в документации на микроконтроллеры ATmega168/328 я свел всевозможные варианты ШИМ для таймера 1 в таблицу.
Строчки из правого столбца для выбранного варианта необходимо написать в функции setup().
Варианты параметров ШИМ на выводах 9 и 10 Ардуино (таймер 1).
Разрешение | Частота ШИМ | Команды установки режима |
8 бит | 62 500 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x09; |
7 812,5 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x0a; |
|
976,56 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x0b; |
|
244,14 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x0c; |
|
61,04 Гц | TCCR1A = TCCR1A & 0xe0 | 1; TCCR1B = TCCR1B & 0xe0 | 0x0d; |
|
9 бит | 31 250 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x09; |
3 906,25 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x0a; |
|
488,28 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x0b; |
|
122,07 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x0c; |
|
30,52 Гц | TCCR1A = TCCR1A & 0xe0 | 2; TCCR1B = TCCR1B & 0xe0 | 0x0d; |
|
10 бит | 1 5625 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x09; |
1 953,13 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x0a; |
|
244,14 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x0b; |
|
61,04 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x0c; |
|
15,26 Гц | TCCR1A = TCCR1A & 0xe0 | 3; TCCR1B = TCCR1B & 0xe0 | 0x0d; |
Следующий скетч генерирует на выводе 9 ШИМ с частотой 62,5 кГц и коэффициентом заполнения примерно 10 %.
void setup() {
// ШИМ 8 разрядов, 62,5 кГц
TCCR1A = TCCR1A & 0xe0 | 1;
TCCR1B = TCCR1B & 0xe0 | 0x09;
analogWrite(9, 25); // на выводе 9 ШИМ=10%
}
void loop() {
}
Это максимально возможная частота ШИМ Ардуино для большинства плат (с частотой генератора 16 мГц).
В следующем уроке вернемся к разработке контроллера элемента Пельтье.
Предыдущий урок Список уроков Следующий урок
Источник: http://mypractic.ru/urok-37-shirotno-impulsnaya-modulyaciya-v-arduino.html