Меню

Генератор сигналов своими руками на arduino

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

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

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 я приведу таблицу с их допустимыми комбинациями и формой результирующих сигналов на выходе:

OPBITENMODEDIV2Сигнал на выходе VOUT

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°).
  • Выбор формы сигнала.
  • Выбор значения, на которое изменяется частота при вращении ручки энкодера.

Остается только поместить все компоненты в подходящий корпус и получится законченное устройство. Результат работы в следующем ролике:

Генератор синусоиды на Arduino или ЦАП R-2R

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

Предыстория.
У меня есть хороший друг. Тоже «радиолюбитель», самоучка и весьма энергичный молодой человек. Так вот. Попался ему как-то в руки сгоревший «синим пламенем» источник бесперебойного питания (ИБП) – не лучший образец продукции «поднебесной». Починить его оказалось неподъемной задачей.

Однако, трансформатор оказался одним из «живучих» элементов, и Дима задумал изготовить небольшой преобразователь 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 Vanyamba uses Linux – 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 (очистки при совпадении), поэтому этот метод применяется в основном для использования ШИМ в качестве цифро-аналогового преобразователя.

Итак, я собираюсь генерировать сигнал аудио-частоты, то есть в диапазоне от 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 Скачать скетч можно, кликнув по ссылке.

Скомпилировав и загрузив скетч в память 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

Прошлый генератор прямоугольных импульсов на энкодере (“GENERATOR ver.1”) получился неплохим, но ограничение в 8 кГц кого то может не устроить. Конечно, можно его разогнать до 32 кГц, но для этого придется подключать его к компьютеру и лезть в скетч, менять настройки вручную. Для самодостаточного устройства это большой минус.

Мне товарищем AlexBeda было сделано замечание, что разработанный им на Ардуино генератор “выжимал и гораздо больше частоты”. Расценив это замечание как команду к действию, решил попробовать.
Выдалось свободное время, и я смог приспособить его программу для использования в автономном устройстве.

Пришлось доработать скетч для вывода информации на LCD экран через I2C шину, урезать лишнее (на мой взгляд) и поправить некоторые ошибки. Учитывая, что я далеко не программист, пришлось попотеть, подгоняя содержимое топором и граблями.

Кто не знает, как подключить I2C модуль к Ардуино, советую посмотреть видео «Подключаем текстовый LCD 16×2 к arduino по I2C».

Встречайте, генератор прямоугольных импульсов от 1 Гц до 2 МГц с возможность регулировки скважности — “GENERATOR ver.2”. Так же как и первый генератор, все собрано из готовых блоков и трех кнопок, никакой пайки и дополнительных радиоэлементов, что облегчает сборку даже новичку.

Ну и соблюдена основная концепция изделия, оно должно быть изготовлено из ОЧЕНЬ дешевых составляющих. Поэтому недешевый модуль генератора на микросхеме ad9850 здесь не предполагалось использовать.

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

С ростом вырабатываемой данным генератором частоты, незначительно растет погрешность, падает скважность и фронты начинают заваливаться, но в основном генератор вполне точен, выполняет свои функции и позволяет вносить коррективы кнопками. Если бы еще заставить его выдать синусоиду, пилу и лопату :).

Пока думаю, как в старом корпусе расположить кнопки, однако все опробовано и протестировано подключением к осциллографу.

Zoom

Частота 100кГц

Zoom

Частота 200кГц

Zoom

Частота 1 МГц

Zoom

Частота 2 МГц, скважность подправлена до 50%

Состав: Ардуино Nano, LCD 1602 дисплей, I2C модуль, кнопки без фиксации, соединительные провода для макетной платы, корпус и модифицированная программа AlexBeda.

Мне не удалось заставить его показывать скважность в процентах (только в относительных цифрах от 1 до 255, по умолчанию поставил 128=50%), если есть решение, прошу подсказать. Может, кто увидит косяки или лишнее в программном коде, прошу высказаться.

И самое главное, я не придумал где его применить (кроме стенда для промывки форсунок, калибровки щупов осциллографа и проверки шаговых двигателей), подскажите :).А теперь, как заведено, скетч в сообщении.

____________________________________________________

DueSimpleWaveformGenerator

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

Simple Waveform Generator with Arduino Due

This tutorial shows how to make a simple waveform generator using the Arduino and the DAC features of the Arduino Due board.

With push buttons, you will be able to choose a waveform shape (sine, triangular, sawtooth, or square) on both DAC channels and change the frequency of the generated signal.

Hardware Required

  • Arduino Due
  • 10 kilohm potentiometer
  • 2 push buttons
  • 2 x 10 kilohm resistors
  • jumper wires

Circuit

Connect power and ground on your breadboard to the Arduino. In the image below, the red (power) and black (ground) wires connect to the two long vertical rows on the breadboard, providing access to 3.3V and ground.

Connect a wire from digital pin 2 to one leg of a pushbutton. That same leg of the button connects through a pull-down resistor (10-kilohm) to ground. The other leg of the button connects to the 3.3V power.

Wire up another button in the same fashion, but to digital pin 3.

Hook up the potentiometer by connecting one side to power and the other side to ground. The pin in the middle of the potentiometer goes to analog input 0.

Pins DAC0 and DAC1 wil generate the waveform.

Code

The waveforms are stored inside a two-dimensional array where each row represent a different waveform shape. The waveform samples are contained inside the columns, so you can access the waveform table using two indexes:

waveformsTable[waveformIndex][samplesIndex]

With the waveformIndex array, you choose which samples to read. By incrementing the sampleIndex array from 0 to the maximum in a fixed time, you will create the waveform shape. Repeating this procedure continuously and sending the samples values on the DAC output will give you a constant signal.

In order to choose the waveform shape with a push button, match the button press to the waveformIndex increment. You can use the interrupts, triggering the the press event using the RISING option for easy access. So, when the Arduino Due sees a rising edge on the button pin, it will execute the function linked to the interrupt matched with the button:

void waveCh0_select() and void waveCh1_select()

The potentiometer connected to analog pin 0 is used to choose the sample rate and the period of the singal is given by the sample rate multiplied for the number of the samples.

Taking into account the time for the instructions to execute, and adding the time for the analog input (around 40 µS to read the pot), maximum frequency for the signal with this sketch is around 170 Hz.

The sketch is composed of two files. One has the two-dimensional arrays, with the table of the samples for all the waveforms for legibility.

Download the attached file, or if you want to start from scratch you have to create a new folder inside your sketchbook folder and place the two files inside.

The sketch file must have the same name of the folder, and the file with the sample table must be named “Waveforms.h”.

FunctionGenerator.ino

/*   Simple Waveform generator with Arduino Due   * connect two push buttons to the digital pins 2 and 3     with a 10 kilohm pulldown resistor to choose the waveform     to send to the DAC0 and DAC1 channels   * connect a 10 kilohm potentiometer to A0 to control the     signal frequency

 */

#include “Waveforms.h”

#define oneHzSample 1000000/maxSamplesNum  // sample for the 1Hz signal expressed in microseconds

const int button0 = 2, button1 = 3;

volatile int wave0 = 0, wave1 = 0;

int i = 0;

int sample;

void setup() {

  analogWriteResolution(12);  // set the analog output resolution to 12 bit (4096 levels)
  analogReadResolution(12);   // set the analog input resolution to 12 bit

  attachInterrupt(button0, wave0Select, RISING);  // Interrupt attached to the button connected to pin 2

  attachInterrupt(button1, wave1Select, RISING);  // Interrupt attached to the button connected to pin 3
}

void loop() {

  // Read the the potentiometer and map the value  between the maximum and the minimum sample available
  // 1 Hz is the minimum freq for the complete wave
  // 170 Hz is the maximum freq for the complete wave. Measured considering the loop and the analogRead() time
  sample = map(analogRead(A0), 0, 4095, 0, oneHzSample);
  sample = constrain(t_sample, 0, oneHzSample);

  analogWrite(DAC0, waveformsTable[wave0][i]);  // write the selected waveform on DAC0

  analogWrite(DAC1, waveformsTable[wave1][i]);  // write the selected waveform on DAC1

  i++;

  if(i == maxSamplesNum)  // Reset the counter to repeat the wave
    i = 0;

  delayMicroseconds(sample);  // Hold the sample value for the sample time

}

// function hooked to the interrupt on digital pin 2

void wave0Select() {
  wave0++;
  if(wave0 == 4)
    wave0 = 0;
}

// function hooked to the interrupt on digital pin 3

void wave1Select() {
  wave1++;
  if(wave1 == 4)
    wave1 = 0;
}

Waveforms.h

#ifndef _Waveforms_h_
#define _Waveforms_h_

#define maxWaveform 4

#define maxSamplesNum 120

static int waveformsTable[maxWaveform][maxSamplesNum] = {

  // Sin wave
  {
    0x7ff, 0x86a, 0x8d5, 0x93f, 0x9a9, 0xa11, 0xa78, 0xadd, 0xb40, 0xba1,
    0xbff, 0xc5a, 0xcb2, 0xd08, 0xd59, 0xda7, 0xdf1, 0xe36, 0xe77, 0xeb4,
    0xeec, 0xf1f, 0xf4d, 0xf77, 0xf9a, 0xfb9, 0xfd2, 0xfe5, 0xff3, 0xffc,
    0xfff, 0xffc, 0xff3, 0xfe5, 0xfd2, 0xfb9, 0xf9a, 0xf77, 0xf4d, 0xf1f,
    0xeec, 0xeb4, 0xe77, 0xe36, 0xdf1, 0xda7, 0xd59, 0xd08, 0xcb2, 0xc5a,
    0xbff, 0xba1, 0xb40, 0xadd, 0xa78, 0xa11, 0x9a9, 0x93f, 0x8d5, 0x86a,
    0x7ff, 0x794, 0x729, 0x6bf, 0x655, 0x5ed, 0x586, 0x521, 0x4be, 0x45d,
    0x3ff, 0x3a4, 0x34c, 0x2f6, 0x2a5, 0x257, 0x20d, 0x1c8, 0x187, 0x14a,
    0x112, 0xdf, 0xb1, 0x87, 0x64, 0x45, 0x2c, 0x19, 0xb, 0x2,
    0x0, 0x2, 0xb, 0x19, 0x2c, 0x45, 0x64, 0x87, 0xb1, 0xdf,
    0x112, 0x14a, 0x187, 0x1c8, 0x20d, 0x257, 0x2a5, 0x2f6, 0x34c, 0x3a4,
    0x3ff, 0x45d, 0x4be, 0x521, 0x586, 0x5ed, 0x655, 0x6bf, 0x729, 0x794
  }
  ,

  // Triangular wave

  {
    0x44, 0x88, 0xcc, 0x110, 0x154, 0x198, 0x1dc, 0x220, 0x264, 0x2a8,
    0x2ec, 0x330, 0x374, 0x3b8, 0x3fc, 0x440, 0x484, 0x4c8, 0x50c, 0x550,
    0x594, 0x5d8, 0x61c, 0x660, 0x6a4, 0x6e8, 0x72c, 0x770, 0x7b4, 0x7f8,
    0x83c, 0x880, 0x8c4, 0x908, 0x94c, 0x990, 0x9d4, 0xa18, 0xa5c, 0xaa0,
    0xae4, 0xb28, 0xb6c, 0xbb0, 0xbf4, 0xc38, 0xc7c, 0xcc0, 0xd04, 0xd48,
    0xd8c, 0xdd0, 0xe14, 0xe58, 0xe9c, 0xee0, 0xf24, 0xf68, 0xfac, 0xff0,
    0xfac, 0xf68, 0xf24, 0xee0, 0xe9c, 0xe58, 0xe14, 0xdd0, 0xd8c, 0xd48,
    0xd04, 0xcc0, 0xc7c, 0xc38, 0xbf4, 0xbb0, 0xb6c, 0xb28, 0xae4, 0xaa0,
    0xa5c, 0xa18, 0x9d4, 0x990, 0x94c, 0x908, 0x8c4, 0x880, 0x83c, 0x7f8,
    0x7b4, 0x770, 0x72c, 0x6e8, 0x6a4, 0x660, 0x61c, 0x5d8, 0x594, 0x550,
    0x50c, 0x4c8, 0x484, 0x440, 0x3fc, 0x3b8, 0x374, 0x330, 0x2ec, 0x2a8,
    0x264, 0x220, 0x1dc, 0x198, 0x154, 0x110, 0xcc, 0x88, 0x44, 0x0
  }
  ,

  // Sawtooth wave

  {
    0x22, 0x44, 0x66, 0x88, 0xaa, 0xcc, 0xee, 0x110, 0x132, 0x154,
    0x176, 0x198, 0x1ba, 0x1dc, 0x1fe, 0x220, 0x242, 0x264, 0x286, 0x2a8,
    0x2ca, 0x2ec, 0x30e, 0x330, 0x352, 0x374, 0x396, 0x3b8, 0x3da, 0x3fc,
    0x41e, 0x440, 0x462, 0x484, 0x4a6, 0x4c8, 0x4ea, 0x50c, 0x52e, 0x550,
    0x572, 0x594, 0x5b6, 0x5d8, 0x5fa, 0x61c, 0x63e, 0x660, 0x682, 0x6a4,
    0x6c6, 0x6e8, 0x70a, 0x72c, 0x74e, 0x770, 0x792, 0x7b4, 0x7d6, 0x7f8,
    0x81a, 0x83c, 0x85e, 0x880, 0x8a2, 0x8c4, 0x8e6, 0x908, 0x92a, 0x94c,
    0x96e, 0x990, 0x9b2, 0x9d4, 0x9f6, 0xa18, 0xa3a, 0xa5c, 0xa7e, 0xaa0,
    0xac2, 0xae4, 0xb06, 0xb28, 0xb4a, 0xb6c, 0xb8e, 0xbb0, 0xbd2, 0xbf4,
    0xc16, 0xc38, 0xc5a, 0xc7c, 0xc9e, 0xcc0, 0xce2, 0xd04, 0xd26, 0xd48,
    0xd6a, 0xd8c, 0xdae, 0xdd0, 0xdf2, 0xe14, 0xe36, 0xe58, 0xe7a, 0xe9c,
    0xebe, 0xee0, 0xf02, 0xf24, 0xf46, 0xf68, 0xf8a, 0xfac, 0xfce, 0xff0
  }
  ,

  // Square wave

  {
    0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
    0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
    0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
    0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
    0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
    0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
  }

};

#endif

Loading…

цифровая электроника вычислительная техника встраиваемые системы

Генератор сигналов своими руками на Arduino

Каждый инженер, который любит поработать с электроникой, в какой-то момент времени захочет иметь собственную лабораторию. Мультиметр, осциллограф, измеритель LCR, функциональный генератор, двухрежимный источник питания и автоматический трансформатор – это минимальное оборудование для достойной лаборатории. В то время как все они могут быть приобретены, мы также можем легко собрать самостоятельно несколько приборов, таких как генератор функций и двухрежимный источник питания.

В этой статье мы узнаем, как быстро и легко мы можем создать собственный генератор сигналов с помощью Arduino. Этот генератор может создавать прямоугольный сигнал или меандр (5 В / 0 В) с частотой от 1 Гц до 2 МГц, частоту сигнала можно контролировать с помощью регулятора, а скважность (обратная рабочему циклу) жестко закодирована на 50%, но ее легко изменить в программе. Кроме того, генератор может также производить управление частотой.

Ниже приведена полная принципиальная схема этого генератора сигналов на основе Arduino. Как вы можете видеть, у нас есть Arduino Nano, который действует как мозг нашего проекта и ЖК-дисплей 16×2 для отображения значения частоты, которая в настоящее время генерируется. У нас также есть угловой кодер, который поможет нам установить частоту. Подача питания осуществляется от USB-порта самого Arduino.

Схема довольно проста; мы создаем прямоугольный сигнал на выводе D9, который может быть использован как таковой, частота этого прямоугольного сигнала контролируется поворотным кодером. Затем, чтобы получить синусоидальную волну, мы получаем сигнал SPWM (синусоидальная ШИМ) на выводе D5, частота этого сигнала должна быть связана с частотой PWM (ШИМ), поэтому мы заводим этот сигнал ШИМ на контакт D2, чтобы он действовал как прерывание, а затем используем ISR для управления частотой.

Люди, которые используют Arduino, могут быть знакомы с тем, что Arduino может генерировать сигналы ШИМ, просто используя функцию аналоговой записи. Но эта функция ограничивается только контролем рабочего цикла сигнала ШИМ, а не частоты сигнала. Но для генератора сигналов нам нужен сигнал ШИМ, частота которого может контролироваться. Это можно сделать, непосредственно управляя таймерами Arduino и переключая на него контакт GPIO. Но есть некоторые готовые библиотеки, которые делают то же самое и могут использоваться как таковые. Библиотека, которую мы используем, является библиотекой настройки частоты Arduino PWM Frequency Library (https://code.google.com/archive/p/arduino-pwm-frequency-library/downloads).

Есть и некоторые недостатки в этой библиотеке, потому что библиотека изменяет настройки Timer 1 и Timer 2 по умолчанию в Arduino. Следовательно, вы больше не сможете использовать серво-библиотеку или любую другую библиотеку, связанную с таймером. Также функция аналоговой записи на контактах 9,10,11 и 13 использует таймер 1 и таймер 2, поэтому вы не сможете создавать SPWM на этих контактах.

Преимущество этой библиотеки в том, что она не мешает таймеру 0 вашего Arduino, который более важен, чем таймер 1 и таймер 2. Из-за этого вы можете без проблем использовать функцию задержки и функцию millis(). Также контакты 5 и 6 управляются таймером 0, поэтому у нас не будет проблем с использованием аналоговой записи или управления сервомотором на этих контактах.

Поскольку мы знаем, что микроконтроллеры – это цифровые устройства, и они не могут генерировать синусоидальную волну простым кодированием. Но есть два популярных способа получения синусоидальной волны от микроконтроллера – это использование ЦАП и создание синусоидального ШИМ сигнала (SPWM). К сожалению, платы Arduino (кроме Due) не поставляются со встроенным ЦАП для создания синусоидальной волны, но вы всегда можете создать свой собственный ЦАП, используя простой метод R2R, а затем использовать его для создания приличной синусоидальной волны. Но для уменьшения аппаратной работы лучше использовать более оптимальный метод создания сигнала SPWM и затем преобразовать его в синусоидальную волну.

Сигнал SPWM очень похож на PWM, но для него рабочий цикл управляется таким образом, чтобы получить среднее напряжение, подобное напряжению синусоидальной волны. Например, при 100%-ном рабочем цикле среднее выходное напряжение будет 5 В, а для 25% мы будем иметь 1,25 В, таким образом, управляя рабочим циклом, мы можем получить предварительно определенное переменное среднее напряжение, которое является ничем иным, как синусоидальной волной. Этот метод обычно используется в инверторах.

В приведенном выше изображении синим сигналом является сигнал SPWM. Обратите внимание, что рабочий цикл волны изменяется от 0% до 100%, а затем обратно до 0%. График строится в диапазоне напряжения от -1,0 до + 1,0 В, но в нашем случае, поскольку мы используем Arduino, масштаб будет составлять от 0 до 5 В.

Преобразование SPWM в синусоидальную волну требует наличие H-мостовой схемы, которая состоит из минимум 4 коммутаторов питания. Мы не будем углубляться в его принцип работы, поскольку мы не используем его здесь. Эти схемы H-мостов обычно используются в инверторах. Они используют два сигнала SPWM, где один сдвинут по фазе от другого, и оба сигнала применяются к переключателям питания в H-мосте, чтобы включить и выключить диагональные противоположные ключи в одно и то же время. Таким образом, мы можем получить волновую форму, которая похожа на синусоидальную волну, но она будет зашумленная. Чтобы получить чистый результат, мы должны использовать фильтр, подобный фильтру нижних частот, который состоит из катушки индуктивности и конденсатора.

Однако в нашей схеме мы не будем обеспечивать на выходе столь чистый синусоидальный сигнал, поэтому обойдемся простым RC-фильтром. Вы также можете попробовать LC-фильтр для получения лучших результатов, но здесь мы выберем RC для простоты. Значение резистора составляет 620 Ом, а конденсатор – 10 мкФ. На приведенном выше рисунке показан сигнал SPWM (желтый) с вывода 5 и синусоида (синий), который был получен после прохождения через RC-фильтр.

Ниже приведен код программы для создания генератора сигналов на основе Arduino. Он довольно прост и содержит комментарии, но перед компиляцией убедитесь, что вы добавили библиотеку Arduino PWM Frequency Library, иначе вы получите ошибку во время компиляции.

Соберите свое оборудование по схеме и загрузите код. Теперь вы готовы проверить свой проект. Было бы намного проще, если у вас есть осциллограф, но вы также можете проверить его с помощью светодиода.

Подключите щуп к выводу квадратного сигнала и выводу синусоидального сигнала. Используйте два светодиода на этих двух контактах, если у вас нет осциллографа. Включите схему, и вас поприветствует вводное сообщение на ЖК-дисплее. Затем поверните вал энкодера и установите требуемую частоту, чтобы вы могли наблюдать прямоугольную волну и синусоидальную волну, как показано ниже. Если вы используете светодиод, вы должны заметить, что светодиод мигает с разными интервалами в зависимости от частоты, которую вы установили.

цифровая электроника вычислительная техника встраиваемые системы

Генератор сигналов своими руками на Arduino

Каждый инженер, который любит поработать с электроникой, в какой-то момент времени захочет иметь собственную лабораторию. Мультиметр, осциллограф, измеритель LCR, функциональный генератор, двухрежимный источник питания и автоматический трансформатор – это минимальное оборудование для достойной лаборатории. В то время как все они могут быть приобретены, мы также можем легко собрать самостоятельно несколько приборов, таких как генератор функций и двухрежимный источник питания.

В этой статье мы узнаем, как быстро и легко мы можем создать собственный генератор сигналов с помощью Arduino. Этот генератор может создавать прямоугольный сигнал или меандр (5 В / 0 В) с частотой от 1 Гц до 2 МГц, частоту сигнала можно контролировать с помощью регулятора, а скважность (обратная рабочему циклу) жестко закодирована на 50%, но ее легко изменить в программе. Кроме того, генератор может также производить управление частотой.

Ниже приведена полная принципиальная схема этого генератора сигналов на основе Arduino. Как вы можете видеть, у нас есть Arduino Nano, который действует как мозг нашего проекта и ЖК-дисплей 16×2 для отображения значения частоты, которая в настоящее время генерируется. У нас также есть угловой кодер, который поможет нам установить частоту. Подача питания осуществляется от USB-порта самого Arduino.

Схема довольно проста; мы создаем прямоугольный сигнал на выводе D9, который может быть использован как таковой, частота этого прямоугольного сигнала контролируется поворотным кодером. Затем, чтобы получить синусоидальную волну, мы получаем сигнал SPWM (синусоидальная ШИМ) на выводе D5, частота этого сигнала должна быть связана с частотой PWM (ШИМ), поэтому мы заводим этот сигнал ШИМ на контакт D2, чтобы он действовал как прерывание, а затем используем ISR для управления частотой.

Люди, которые используют Arduino, могут быть знакомы с тем, что Arduino может генерировать сигналы ШИМ, просто используя функцию аналоговой записи. Но эта функция ограничивается только контролем рабочего цикла сигнала ШИМ, а не частоты сигнала. Но для генератора сигналов нам нужен сигнал ШИМ, частота которого может контролироваться. Это можно сделать, непосредственно управляя таймерами Arduino и переключая на него контакт GPIO. Но есть некоторые готовые библиотеки, которые делают то же самое и могут использоваться как таковые. Библиотека, которую мы используем, является библиотекой настройки частоты Arduino PWM Frequency Library (https://code.google.com/archive/p/arduino-pwm-frequency-library/downloads).

Есть и некоторые недостатки в этой библиотеке, потому что библиотека изменяет настройки Timer 1 и Timer 2 по умолчанию в Arduino. Следовательно, вы больше не сможете использовать серво-библиотеку или любую другую библиотеку, связанную с таймером. Также функция аналоговой записи на контактах 9,10,11 и 13 использует таймер 1 и таймер 2, поэтому вы не сможете создавать SPWM на этих контактах.

Преимущество этой библиотеки в том, что она не мешает таймеру 0 вашего Arduino, который более важен, чем таймер 1 и таймер 2. Из-за этого вы можете без проблем использовать функцию задержки и функцию millis(). Также контакты 5 и 6 управляются таймером 0, поэтому у нас не будет проблем с использованием аналоговой записи или управления сервомотором на этих контактах.

Поскольку мы знаем, что микроконтроллеры – это цифровые устройства, и они не могут генерировать синусоидальную волну простым кодированием. Но есть два популярных способа получения синусоидальной волны от микроконтроллера – это использование ЦАП и создание синусоидального ШИМ сигнала (SPWM). К сожалению, платы Arduino (кроме Due) не поставляются со встроенным ЦАП для создания синусоидальной волны, но вы всегда можете создать свой собственный ЦАП, используя простой метод R2R, а затем использовать его для создания приличной синусоидальной волны. Но для уменьшения аппаратной работы лучше использовать более оптимальный метод создания сигнала SPWM и затем преобразовать его в синусоидальную волну.

Сигнал SPWM очень похож на PWM, но для него рабочий цикл управляется таким образом, чтобы получить среднее напряжение, подобное напряжению синусоидальной волны. Например, при 100%-ном рабочем цикле среднее выходное напряжение будет 5 В, а для 25% мы будем иметь 1,25 В, таким образом, управляя рабочим циклом, мы можем получить предварительно определенное переменное среднее напряжение, которое является ничем иным, как синусоидальной волной. Этот метод обычно используется в инверторах.

В приведенном выше изображении синим сигналом является сигнал SPWM. Обратите внимание, что рабочий цикл волны изменяется от 0% до 100%, а затем обратно до 0%. График строится в диапазоне напряжения от -1,0 до + 1,0 В, но в нашем случае, поскольку мы используем Arduino, масштаб будет составлять от 0 до 5 В.

Преобразование SPWM в синусоидальную волну требует наличие H-мостовой схемы, которая состоит из минимум 4 коммутаторов питания. Мы не будем углубляться в его принцип работы, поскольку мы не используем его здесь. Эти схемы H-мостов обычно используются в инверторах. Они используют два сигнала SPWM, где один сдвинут по фазе от другого, и оба сигнала применяются к переключателям питания в H-мосте, чтобы включить и выключить диагональные противоположные ключи в одно и то же время. Таким образом, мы можем получить волновую форму, которая похожа на синусоидальную волну, но она будет зашумленная. Чтобы получить чистый результат, мы должны использовать фильтр, подобный фильтру нижних частот, который состоит из катушки индуктивности и конденсатора.

Однако в нашей схеме мы не будем обеспечивать на выходе столь чистый синусоидальный сигнал, поэтому обойдемся простым RC-фильтром. Вы также можете попробовать LC-фильтр для получения лучших результатов, но здесь мы выберем RC для простоты. Значение резистора составляет 620 Ом, а конденсатор – 10 мкФ. На приведенном выше рисунке показан сигнал SPWM (желтый) с вывода 5 и синусоида (синий), который был получен после прохождения через RC-фильтр.

Ниже приведен код программы для создания генератора сигналов на основе Arduino. Он довольно прост и содержит комментарии, но перед компиляцией убедитесь, что вы добавили библиотеку Arduino PWM Frequency Library, иначе вы получите ошибку во время компиляции.

Соберите свое оборудование по схеме и загрузите код. Теперь вы готовы проверить свой проект. Было бы намного проще, если у вас есть осциллограф, но вы также можете проверить его с помощью светодиода.

Подключите щуп к выводу квадратного сигнала и выводу синусоидального сигнала. Используйте два светодиода на этих двух контактах, если у вас нет осциллографа. Включите схему, и вас поприветствует вводное сообщение на ЖК-дисплее. Затем поверните вал энкодера и установите требуемую частоту, чтобы вы могли наблюдать прямоугольную волну и синусоидальную волну, как показано ниже. Если вы используете светодиод, вы должны заметить, что светодиод мигает с разными интервалами в зависимости от частоты, которую вы установили.

Сайт для радиолюбителей

Генератор прямоугольных импульсов в своей основе использует библиотеку TimerOne, возможности библиотеки позволяют генерировать сигнал ШИМ на выводе 9 в диапазоне от 1 мкс до 8,3 сек, в частности в генераторе диапазон ограничен до 200 мс (5 Гц), при желании диапазон можно увеличить до 8,3 сек. Так можно регулировать скважность от 0 до 1023 единиц (10-бит), что соответствует 0 и 100%.

В генераторе импульсов имеется возможность регулировки периода следования импульсов при помощи кнопок подключенных к цифровым входам 6 и 7 Arduino. 13 вход позволяет регулировать скважность (коэффициент заполнения). Возможно кнопочное управление не самое разумное решение, но на данный момент реализована только такая функция.

Для удобства показания длительности и скважности выведены на первый ряд индикатора LCD 16×2, во втором ряду выведены показания частоты. Важно помнить что минимальный шаг регулировки периода следования импульсов 1 мкс, поэтому частота будет меняться дискретно, например 1 мкс это 1 МГц, 2 мкс — 500 кГц, 3 мкс это 333,333 Гц и так далее, по мере уменьшения частоты увеличивается плавность ее регулировки.

Генератор нуждается в доработке, поэтому со временем поменяются органы регулировки, добавятся новые функции.

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

Внешний вид генератора сигналов прямоугольной и синусоидальной формы на Arduino

В этой статье мы рассмотрим как на основе платы Arduino достаточно просто сконструировать генератор сигналов прямоугольной и синусоидальной формы. При формировании сигналов прямоугольной формы данный генератор может формировать прямоугольную волну с перепадами уровней 5V/0V с частотой от 1 Гц до 2 МГц. Частотой формируемого сигнала можно будет управлять с помощью инкрементального энкодера. Коэффициент заполнения (цикл занятости) данного сигнала будет равен 50%, но его можно изменить, внеся соответствующие изменения в программу. Рассматриваемый нами генератор не является промышленным устройством и его не рекомендуется использовать на серьезном производстве, но для домашних условий использования он вполне подойдет.

Также на нашем сайте вы можете посмотреть проекты более «продвинутых» генераторов для формирования сигналов прямоугольной и синусоидальной формы:

  • генератор сигналов на Arduino и DDS модуле AD9833;
  • генератор перестраиваемой частоты 10 кГц – 225 МГц на Arduino и модуле Si5351.

Если же вам нужно исключительно простое решение для формирования сигналов прямоугольной формы с частотой до 1 МГц с помощью платы Arduino, то рекомендуем этот проект.

Необходимые компоненты

  1. Плата Arduino Nano (купить на AliExpress).
  2. Алфавитно-цифровой ЖК дисплей 16х2 (купить на AliExpress).
  3. Инкрементальный энкодер, угловой кодер (Rotary Encoder) (купить на AliExpress).
  4. Резисторы 5,6 кОм и 10 кОм (купить на AliExpress).
  5. Конденсатор 0,1 мкФ (купить на AliExpress).
  6. Перфорированная плата.
  7. Набор для пайки.

Работа схемы

Схема генератора сигналов на основе платы Arduino представлена на следующем рисунке.

Схема генератора сигналов прямоугольной и синусоидальной формы на основе платы ArduinoПлата Arduino Nano управляет всеми процессами в схеме. ЖК дисплей используется для отображения частоты формируемого сигнала, а с помощью углового кодера производится установка частоты сигнала. Также на нашем сайте вы можете прочитать статью о подключении инкрементального энкодера к плате Arduino.

Схема запитывается от USB кабеля Arduino. Необходимые соединения в схеме представлены в следующей таблице.

Контакт платы Arduino Куда подключен
D14 контакт RS ЖК дисплея
D15 контакт RN ЖК дисплея
D4 контакт D4 ЖК дисплея
D3 контакт D5 ЖК дисплея
D6 контакт D6 ЖК дисплея
D7 контакт D7 ЖК дисплея
D10 to Rotary Encoder 2
D11 to Rotary Encoder 3
D12 to Rotary Encoder 4
D9 выход прямоугольного сигнала
D2 контакт D9 платы Arduino
D5 выход SPWM сигнала

В схеме мы будем формировать прямоугольную волну (сигнал прямоугольной формы) на контакте D9 платы Arduino. Его частоту мы будем регулировать с помощью углового кодера. Для формирования синусоидального сигнала мы будем формировать SPWM сигнал (синусоидальный ШИМ (широтно-импульсной модуляции) сигнал) на контакте D5, его частота будет зависеть от частоты сигнала прямоугольной формы, которая будет подаваться на контакт D2 и будет действовать как прерывание и затем мы с помощью процедуры обработки (обслуживания) прерывания будем управлять частотой синусоидального сигнала.

Вы можете собрать схему проекта на макетной или даже на печатной плате, но мы решили спаять ее на перфорированной плате, в результате у нас получилась конструкция, показанная на следующих рисунках:

Вид собранного генератора сигналов на основе платы Arduino на перфорированной плате

Формирование прямоугольного сигнала с изменяемой частотой

Если вы знакомы с Arduino, то вы должны знать что плата Arduino может достаточно просто формировать ШИМ сигнал (с помощью функции analogwrite) на ряде своих контактов. Но с помощью этой функции можно управлять только коэффициентом заполнения (скважностью) ШИМ сигнала, но нельзя управлять его частотой – а это как раз и нужно для нашего генератора сигналов. Управление частотой сигнала прямоугольной формы можно осуществить используя таймеры платы Arduino и непосредственно переключая состояние контактов на их основе. Помочь нам в этом может библиотека Arduino PWM Frequency Library (библиотека управления частотой ШИМ сигнала), более подробно работу с ней мы рассмотрим далее в статье.

Вид сформированного нашим генератором прямоугольного сигнала

Но в использовании этой библиотеки есть ряд слабых сторон. Дело в том, что данная библиотека изменяет настройки по умолчанию Таймера 1 (Timer 1) и Таймера 2 (Timer 2) платы Arduino. В связи с этим вы уже не сможете, к примеру, использовать библиотеку для управления серводвигателем или другие библиотеки, задействующие эти таймеры платы Arduino. Также функция analogwrite на контактах 9,10,11 & 13 использует Timer 1 и Timer 2, следовательно, вы уже не сможете формировать SPWM сигнал (синусоидальный ШИМ сигнал) на этих контактах.

Но преимуществом этой библиотеки является то, что она не мешает работа Таймера 0 (Timer 0) платы Arduino, который в нашем случае является более важным чем Timer 1 и Timer 2 потому что в этом случае вы можете без проблем использовать функцию задержки (delay) и функцию millis(). Также контакты 5 и 6 управляются Таймером 0, поэтому мы без проблем сможем использовать на этих контактах функцию analogwrite или осуществлять управление сервомотором.

Формирование синусоидальной волны (колебания) с помощью Arduino

Мы знаем, что микроконтроллеры являются цифровыми устройствами, поэтому они не могут формировать синусоидальную волну в «чистом» виде. Но есть два способа формирования синусоидальной волны с помощью микроконтроллера: первый заключается в использовании ЦАП (цифро-аналогового преобразователя), а второй — в использовании синусоидального ШИМ сигнала (SPWM). К сожалению, в платах Arduino (за исключением платы Arduino Due) нет встроенного ЦАПа для формирования синусоидальной волны. Конечно, можно было бы использовать внешний ЦАП, но мы решили не усложнять таким образом схему проекта и использовать метод формирования синусоидального ШИМ сигнала с дальнейшим преобразованием его в синусоидальный сигнал (волну).

Что такое SPWM сигнал

SPWM расшифровывается как Sinusoidal Pulse Width Modulation и переводится как синусоидальная широтно-импульсная модуляция (синусоидальная ШИМ). Этот сигнал в определенной степени похож на обычный ШИМ сигнал, но в нем коэффициент заполнения контролируется таким образом чтобы получить среднее напряжение похожее на синусоидальную волну. Например, при коэффициенте заполнения (скважности) 100% среднее выходное напряжение будет 5V, а при коэффициенте заполнения 25% оно будет всего лишь 1.25V, таким образом, управляя скважностью (коэффициентом заполнения) мы можем получить заранее определенные изменяемые значения среднего напряжения, то есть синусоидальную волну. Этот метод обычно используется в инверторах.

Принцип формирования SPWM сигнала показан на следующем рисунке.

Принцип формирования SPWM сигнала

Синим цветом на этом рисунке показан SPWM сигнал. Заметьте, что его скважность (коэффициент заполнения) изменяется от 0% до 100%, а затем снова возвращается в 0%. Представленный график построен для диапазона изменения напряжений от -1.0 до +1.0V, но в нашем случае, поскольку мы используем плату Arduino, масштаб подобного графика будет от 0V до 5V. Мы рассмотрим как в программе для Arduino формировать SPWM сигнал далее в статье.

Преобразование SPWM сигнала в синусоидальную волну

Преобразование SPWM сигнала в синусоидальную волну обычно требует использования схемы H-моста (H-bridge), которая состоит минимум из 4-х переключателей мощности (power switches). Подобные схемы обычно используются в инверторах. Мы не будем в статье подробно рассматривать эти вопросы поскольку нам с помощью нашей синусоидальной волны не нужно запитывать какое-либо устройство, нам всего лишь нужно ее сформировать. К тому же с помощью H-моста невозможно получить чистую синусоидальную волну – для этой цели необходимо использовать фильтр нижних частот (ФНЧ), состоящий из конденсаторов и индуктивностей.

Вид сформированной в нашем генераторе синусоидальной волны

Но мы в целях упрощения проекта для этой цели применили простой RC-фильтр. Если же вы хотите повысить качество формирования синусоидальной волны, то вы можете вместо RC-фильтра применить LC-фильтр. Значение сопротивления резистора в нашем RC-фильтре составляет 620 Ом, а значение емкости конденсатора составляет 10 мкФ (номиналы отличаются от тех, которые приведены в начале статьи в разделе «необходимые компоненты», но я надеюсь в комментариях к данной статье более опытные в этих вопросах специалисты подскажут где же здесь правда – статья переведена с другого сайта и там присутствует эта опечатка, к сожалению). На представленном рисунке желтым цветом показан SPWM сигнал с контакта 5 платы Arduino, а синим цветом — синусоидальный сигнал, полученный после прохождения SPWM сигнала через наш RC-фильтр.

Библиотека для управления частотой ШИМ сигнала в Arduino

Эту библиотеку вы можете скачать по следующей ссылке — Arduino PWM Frequency Library.

По представленной ссылке вы скачаете библиотеку в виде ZIP файла. После извлечения информации из этого ZIP файла вы получите каталог (папку) с именем PWM. Перейдите в папку с библиотеками Arduino IDE (для пользователей операционной системы Windows эта папка будет располагаться по адресу C:UsersUserDocumentsArduinolibraries) и скопируйте туда эту PWM папку. Возможно, в библиотеках Arduino IDE у вас уже есть папка с именем PWM – в этом случае вам ее необходимо заменить на новую (скачанную) папку.

Объяснение программы для Arduino

Полный код программы приведен в конце статьи, здесь же мы рассмотрим его наиболее важные фрагменты. Перед компиляцией программы не забудьте добавить в библиотеки Arduino указанную библиотеку Arduino PWM Frequency Library, иначе компиляция программы будет выдавать вам ошибку.

Нам необходимо формировать ШИМ сигнал с изменяемой частотой на контакте 9 платы Arduino. Эта частота будет устанавливаться с помощью углового кодера, а ее значение будет отображаться на экране ЖК дисплея. А когда ШИМ сигнал будет формироваться на контакте 9 он также будет создавать прерывание на контакте 2 поскольку мы соединили оба этих контакта. Используя это прерывание мы можем управлять частотой SPWM сигнала, который будет формироваться на контакте 5.

Как обычно вначале программы мы должны подключить используемые библиотеки. Библиотека для работы с ЖК дисплеем встроена в Arduino IDE, а библиотеку для изменения частоты ШИМ сигнала мы только что скачали.

#include <PWM.h> //PWM library for controlling freq. of PWM signal

#include <LiquidCrystal.h>

Далее мы объявим глобальные переменные и также дадим имена контактам, к которым подключены ЖК дисплей, инкрементальный энкодер и с которых снимаются формируемые сигналы.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

const int rs = 14, en = 15, d4 = 4, d5 = 3, d6 = 6, d7 = 7; //контакты, к которым подключен ЖК дисплей

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

const int Encoder_OuputA  = 11;

const int Encoder_OuputB  = 12;

const int Encoder_Switch = 10;

const int signal_pin = 9;

const int Sine_pin = 5;

const int POT_pin = A2;      

int Previous_Output;

int multiplier = 1;

double angle = 0;

double increment = 0.2;

int32_t frequency; //частота, которую необходимо установить

int32_t lower_level_freq = 1; //наименьшее значение частоты равно 1Hz

int32_t upper_level_freq = 100000; //максимальная возможная частота составляет 100KHz

Внутри функции setup мы инициализируем ЖК дисплей и последовательную связь (для целей отладки программы), а также зададим режим работы для контактов, к которым подключен угловой кодер. Также мы покажем на экране ЖК дисплея приветственное сообщение.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

  lcd.begin(16, 2); //инициализируем ЖК дисплей

  lcd.print(«Signal Generator»); //приветственное сообщений на 1-й строке

  lcd.setCursor(0, 1);

  lcd.print(«-CircuitDigest «); // приветственное сообщений на 2-й строке

  delay(2000);

  lcd.clear();

  lcd.print(«Freq:00000Hz»);

  lcd.setCursor(0, 1);

  lcd.print(«Inc. by: 1 «);

Serial.begin(9600); //последовательная связь для целей отладки

//задание режима работы контактов

  pinMode (Encoder_OuputA, INPUT);

  pinMode (Encoder_OuputB, INPUT);

  pinMode (Encoder_Switch, INPUT);

Далее мы должны использовать такую важную в нашем случае команду как InitTimerSafe, которая инициализирует timer 1 и timer 2 для формирования ШИМ сигнала с изменяемой частотой. Помните, что как только вы используете эту функцию, все настройки по умолчанию для этих таймеров будут сброшены.

InitTimersSafe(); //инициализируем таймеры, но при этом не трогаем timer 0

Также мы используем внешнее прерывание на контакте 2. То есть всегда, когда будет изменяться состояние контакта 2, будет вызываться процедура обработки прерывания (ISR — Interrupt service routine). В нашем случае этой процедурой обработки прерывания выступает функция generate_sine.

attachInterrupt(0,generate_sine,CHANGE);

Далее, в функции void loop нам необходимо проверять произошел ли поворот оси энкодера и только когда это произошло нам следует корректировать (изменять) частоту ШИМ сигнала. Если вы впервые сталкиваетесь с таким устройством как инкрементальный энкодер, то вначале рекомендуем прочесть статью о его подключении к плате Arduino.

Если ось инкрементального энкодера вращается по часовой стрелке нам необходимо увеличивать частоту формируемого сигнала при помощи изменения коэффициента умножения. По умолчанию мы устанавливаем его значение равным 32768 что соответствует коэффициенту заполнения (скважности) ШИМ 50% потому что 32768 составляет 50% от 65536. Далее, изменяя это значение, мы можем изменять и коэффициент заполнения ШИМ. После установки коэффициента умножения функция SetPinFrequencySafe используется для установки частоты выходного сигнала на контакте 9.

pwmWriteHR(signal_pin, 32768); //устанавливаем скважность (коэффициент заполнения) 50% по умолчанию -> для 16-bit 65536/2 = 32768

SetPinFrequencySafe(signal_pin, frequency);

Внутри функции для обработки прерывания (ISR) нам необходимо написать код для формирования SPWM сигнала. Существует много способов формирования SPWM сигнала в плате Arduino – можно найти даже библиотеки, специально написанные для этой цели. Мы выбрали самый простой из этих способов – мы будем использовать функцию sin(), доступную в Arduino. Функция sin() возвращает изменяющееся значение в диапазоне от -1 до +1 и если мы построим ее зависимость от времени мы как раз получим синусоидальную волну.

После этого все, что нам остается сделать, это преобразовать значение из диапазона от -1 до +1 в диапазон от 0 до 255 и затем передать его в функцию analogWrite. В данном случае мы использовали простое умножение на 255 и затем применили функцию map для преобразования значения из диапазона от -255 до +255 в диапазон от 0 до +255. Затем это значение просто подается на контакт 5 с помощью функции analogWrite. Значение переменной angle (а она у нас имитирует время) увеличивается на 0.2 каждый раз при вызове процедуры (функции) обработки прерывания, что позволяет нам управлять частотой формируемого синусоидального сигнала.

double sineValue = sin(angle);

   sineValue *= 255;

   int plot = map(sineValue, 255, +255, 0, 255);

   Serial.println(plot);

   analogWrite(Sine_pin,plot);

   angle += increment;

Тестирование работы генератора сигналов

Соберите аппаратную часть проекта и загрузите программу в плату Arduino. В идеале тестировать работу данного генератора нужно с помощью осциллографа, но если у вас его нет, то можно использовать простой светодиод – им можно оценить работу схему на частотах, которые видит человеческий глаз.

Тестирование работы генератора сигналов

Подключите зонд к выходу прямоугольной и синусоидальной волны в схеме. Подключите к этим двум контактам светодиоды если у вас нет осциллографа. Подайте питание на схему и вы увидите приветственное сообщение на экране ЖК дисплея. Затем, вращая ручку углового кодера, вы можете установить желаемое значение частоты сигнала. Формируемые сигналы будет наглядно видно на экране осциллографа. Если вы используете для проверки схемы светодиоды, то вы увидите что частота их мигания будет изменяться с вращением ручки углового кодера.

Тестирование генератора сигналов прямоугольной и синусоидальной формы с помощью осциллографа

Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.

Исходный код программы (скетча)

Если вы поняли принцип формирования сигналов, описанный в статье, то понимание кода программы не должно вызвать у вас затруднений.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

#include <PWM.h> //библиотека для управления частотой ШИМ сигнала

#include <LiquidCrystal.h>

const int rs = 14, en = 15, d4 = 4, d5 = 3, d6 = 6, d7 = 7; //контакты к которым подключен ЖК дисплей

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

int Encoder_OuputA  = 11;

int Encoder_OuputB  = 12;

int Encoder_Switch = 10;

int Previous_Output;

int multiplier = 1;

double angle = 0;

double increment = 0.2;

const int signal_pin = 9;  

const int Sine_pin = 5;

const int POT_pin = A2;        

int32_t frequency; //устанавливаемая частота

int32_t lower_level_freq = 1; //наименьшая возможная частота — 1Hz

int32_t upper_level_freq = 100000; //максимальная возможная частота — 100KHz

void setup()

{

  lcd.begin(16, 2); //инициализируем ЖК дисплей

  lcd.print(«Signal Generator»); //приветственное сообщение на 1-й строке

  lcd.setCursor(0, 1);

  lcd.print(«-CircuitDigest «); // приветственное сообщение на 2-й строке

  delay(2000);

  lcd.clear();

  lcd.print(«Freq:00000Hz»);

  lcd.setCursor(0, 1);

  lcd.print(«Inc. by: 1 «);

  Serial.begin(9600); //последовательная связь для целей отладки

  InitTimersSafe(); //инициализируем таймеры не трогая timer 0

//задаем режим работы контактов

  pinMode (Encoder_OuputA, INPUT);

  pinMode (Encoder_OuputB, INPUT);

  pinMode (Encoder_Switch, INPUT);

  Previous_Output = digitalRead(Encoder_OuputA); //считываем начальное значение с Output A углового кодера

attachInterrupt(0,generate_sine,CHANGE);

}

void loop()

{

  if (digitalRead(Encoder_OuputA) != Previous_Output)

   {

     if (digitalRead(Encoder_OuputB) != Previous_Output)

     {

       frequency = frequency + multiplier;

      // Serial.println(frequency);

       pwmWriteHR(signal_pin, 32768); //устанавливаем скважность 50% по умолчанию -> для 16-bit 65536/2 = 32768

       SetPinFrequencySafe(signal_pin, frequency);

       lcd.setCursor(0, 0);

       lcd.print(«Freq:     Hz»);

       lcd.setCursor(5, 0);

       lcd.print(frequency);

     }

     else

     {

       frequency = frequency    multiplier;

      // Serial.println(frequency);

       pwmWriteHR(signal_pin, 32768); // устанавливаем скважность 50% по умолчанию -> для 16-bit 65536/2 = 32768

       SetPinFrequencySafe(signal_pin, frequency);

       lcd.setCursor(0, 0);

       lcd.print(«Freq:     Hz»);

       lcd.setCursor(5, 0);

       lcd.print(frequency);

     }

   }

      if (digitalRead(Encoder_Switch) == 0)

   {

   multiplier = multiplier * 10;

   if (multiplier>1000)

   multiplier=1;

  // Serial.println(multiplier);

   lcd.setCursor(0, 1);

   lcd.print(«Cng. by:     «);

   lcd.setCursor(8, 1);

   lcd.print(multiplier);

   delay(500);

   while(digitalRead(Encoder_Switch) == 0);

   }

   Previous_Output = digitalRead(Encoder_OuputA);  

}

void generate_sine()

{

   double sineValue = sin(angle);

   sineValue *= 255;

   int plot = map(sineValue, 255, +255, 0, 255);

   Serial.println(plot);

   analogWrite(Sine_pin,plot);

   angle += increment;

   if (angle > 180)

   angle =0;

}

Видео, демонстрирующее работу схемы

Источник статьи

Загрузка…

8 054 просмотров

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *