Генератор сигналов на Arduino и DDS модуле AD9833


Если вы решили всерьез заняться радиолюбительством, то вам в вашей мастерской никак не обойтись без генератора сигналов (функционального генератора, Function Generator). Промышленные образцы подобных генераторов могут стоить достаточно дорого, собственными силами генератор сигналов изготовить значительно дешевле.

Внешний вид генератора сигналов на Arduino и DDS модуле AD9833

В этой статье мы рассмотрим создание простейшего генератора сигналов на основе платы Arduino и DDS модуля AD9833, с помощью которого можно будет формировать синусоидальный, прямоугольный и треугольный сигналы с частотой до 12 МГц. Тестировать работу нашего генератора сигналов мы будем с помощью осциллографа, который можно также собрать на основе платы Arduino. Также на нашем сайте вы можете посмотреть проект генератора сигналов синусоидальной и прямоугольной формы только на основе платы Arduino, без использования дополнительных модулей.

Что такое генератор сигналов на основе прямого цифрового синтеза (DDS)

Как следует из названия, генератор сигналов может формировать различные виды сигналов заданной частоты. Аббревиатура DDS (Direct Digital Synthesis) означает прямой цифровой синтез. При этом способе любой сигнал можно сформировать в цифровом виде, а затем преобразовать его в аналоговый вид с помощью цифро-аналогового преобразователя (ЦАП). Чаще всего в современной электронике этот метод используется для формирования синусоидальных сигналов, но с его помощью можно формировать и прямоугольные, и треугольные сигналы, и вообще сигналы любой формы. Поскольку формирование сигналов происходит в цифровой форме в модуле DDS, то можно не только очень быстро переключаться между сигналами различной формы, но и также очень быстро изменять их частоту.

Принцип работы генератора сигналов AD9833

"Сердцем" нашего проекта будет микросхема AD9833, представляющая собой программируемый генератор сигналов и отличающаяся низким энергопотреблением. Микросхема (модуль) AD9833 способна формировать сигналы синусоидальной, прямоугольной и треугольной формы с максимальной частотой до 12 МГц. Таким образом, с помощью программы можно изменять частоту, фазу и форму сигналов на выходе данной микросхемы. Управляется данная микросхема по 3-х проводному интерфейсу SPI, что делает взаимодействие с ней достаточно простым. Функциональная схема микросхемы AD9833 приведена на следующем рисунке.

Функциональная схема микросхемы AD9833

Принцип работы данной микросхемы достаточно прост. Если мы посмотрим на ее функциональную схему, то мы обнаружим в ее составе аккумулятор фазы (Phase Accumulator), чья работа состоит в сохранении всех возможных значений синусоидальной волны, начиная от 0 to 2π. Также в ее схеме присутствуют SIN ROM, который преобразует информацию о фазе в амплитуду, и 10-битный ЦАП, который принимает данные от SIN ROM и преобразует их в соответствующие аналоговые значения напряжения, которые и подаются на выход микросхемы. На выходе микросхемы присутствует программно управляемый выключатель – его можно включать и выключать. Его роль мы рассмотрим далее в статье.

Основные особенности модуля AD9833:

  • цифровое программирование частоты и фазы;
  • потребляемая мощность 12.65 мВт при напряжении 3 В;
  • диапазон выходных частот от 0 МГц до 12.5 МГц;
  • разрешение 28 бит (0.1 Гц при частоте опорного сигнала 25 МГц);
  • синусоидальные, треугольные и прямоугольные выходные колебания;
  • напряжение питания от 2.3 В до 5.5 В;
  • трехпроводной интерфейс SPI;
  • расширенный температурный диапазон: от –40°C до +105°C;
  • опция пониженного энергопотребления.

Вкратце принцип работы данной микросхемы мы рассмотрели, более подробную информацию об этом вы можете посмотреть в даташите на микросхему AD9833.

Расположение выводов микросхемы AD9833 показано на следующем рисунке.

Расположение выводов микросхемы AD9833

Назначение выводов микросхемы:

VCC – плюс питания для цифровых и аналоговых цепей генератора.
DGND – цифровая земля.
SDATA – вход данных интерфейса SPI. Передача осуществляется 16-битными словами.
SCLK – вход тактового сигнала SPI. Используется второй режим работы: (CPOL = 1, CPHA = 0).
FSYNC – выбор микросхемы. Перед началом передачи данных должен быть установлен в 0, по завершении в 1.
AGND – аналоговая земля.
OUT – выход генератора.

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

  1. Плата Arduino Nano (купить на AliExpress).
  2. AD9833 DDS Function Generator (генератор сигналов AD9833) (купить на AliExpress).
  3. OLED дисплей 128х64 (купить на AliExpress - для данного проекта можно покупать модель с 4-мя контактами поскольку используется его подключение по интерфейсу I2C).
  4. Инкрементальный энкодер c кнопкой (Rotary Encoder) (купить на AliExpress - не уверен в том, что в нем есть кнопка, но она точно есть в этом лоте - купить на AliExpress № 2, но он продается, к сожалению, только по 5 штук).
  5. Регулятор напряжения LM7809 (купить на AliExpress).
  6. Конденсаторы 470 мкФ и 220 мкФ (купить на AliExpress).
  7. Конденсатор 104 пФ (купить на AliExpress).
  8. Резистор 10 кОм – 6 шт. (купить на AliExpress).
  9. Тактильный переключатель (Tactile Switches) – 4 шт. (купить на AliExpress).
  10. Зажимной контакт (Screw Terminal) 5.04mm (купить на AliExpress).
  11. Разъем типа "мама" (Female Header) и разъем типа DC Barrel Jack.
  12. Источник питания с напряжением 12 В.

Схема проекта

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

Схема генератора сигналов на основе платы Arduino и DDS модуле AD9833"Сердцем" схемы является модуль AD9833, который подключен к плате Arduino. Для питания схемы используется регулятор напряжения LM7809 с подключенными к нему развязывающими конденсаторами, которые используются для фильтрации нежелательных шумов, способных оказать негативное воздействие на формируемые сигналы.

Управляет работой всей схемы плата Arduino. Для отображения информации используется OLED дисплей 128х64. Для изменения частоты формируемого сигнала мы используем три переключателя: первый устанавливает частоту в Гц, второй – в кГц, а третий – в МГц. Также мы используем кнопку для включения или отключения выхода схемы. И, наконец, в схеме используется инкрементальный энкодер (rotary encoder) вместе с подключенными к нему подтягивающими резисторами (чтобы правильно работали переключатели). Инкрементальный энкодер используется для изменения частоты, а тактильный переключатель внутри него используется для выбора формы сигнала.

Внешний вид собранной конструкции проекта генератора сигналов на Arduino

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

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

Для написания кода программы нам прежде всего необходимо скачать необходимые библиотеки по следующим ссылкам:

Download AD9833 Library by Bill Williams;
Download SSD1306 OLED Library by Adafruit;
Download Adafruit GFX library.

Далее в программе мы подключим заголовочные файлы используемых библиотек. Библиотека AD9833.h используется для работы с DDS модулем AD9833, а библиотека math.h – для выполнения ряда математических операций.

Затем мы объявим все используемые в проекте контакты – для подключения кнопок, переключателей, энкодера, OLED дисплея.

Далее мы объявим все необходимые переменные. В переменной counter мы будем хранить значение, считываемое с инкрементального энкодера. В переменных clockPin и clockPinState будет храниться направление вращения энкодера. Переменная time будет использоваться для борьбы с дребезгом контактов кнопок. В переменной moduleFrequency мы будем хранить рассчитанное значение частоты. Логические переменные set_frequency_hz, set_frequency_Khz и set_frequency_Mhz будут использоваться для хранения состояния модуля. В переменной waveSelect мы будем хранить тип формируемого сигнала, по умолчанию это будет синусоида. Переменная encoder_btn_count будет хранить информацию о нажатиях кнопки на энкодере, с помощью которой будет устанавливаться тип формируемого выходного сигнала.

Затем в функции setup() мы инициализируем последовательную связь для целей отладки. Также мы инициализируем модуль AD9833 с помощью функции begin() и зададим режимы для используемых контактов (на ввод или вывод данных). Еще мы сохраняем состояние контакта CLK_PIN (к нему подключен энкодер) в переменной clockPinState.

Дополнительно мы инициализируем OLED дисплей с помощью функции display.begin(). После этого, если на этом этапе не произошло никаких ошибок, мы очищаем экран дисплея и выводим на него приветственное сообщение, после этого делаем задержку на 2 секунды и вызываем функцию update_display().

Далее, в функции loop() мы будем считывать состояние контакта Clock pin инкрементального энкодера и сохранять его в переменной clockPin. Далее мы с помощью оператора if сравниваем предыдущее и текущее состояние данного контакта, также мы сравниваем его состояние с 1. Если это условие выполняется, мы проверяем состояние контакта DATA_PIN. С помощью этой проверки мы выясняем вращается ли ось энкодера по часовой стрелке (инкрементируем counter) или против часовой стрелки (декрементируем counter). Также мы обновляем clockPinState до текущего состояния.

Далее в коде программы мы должны обнаруживать нажатия кнопок. Мы будем обнаруживать нажатие кнопки, находящейся на энкодере, с помощью условия (digitalRead(BTN_PIN) == LOW && millis() - time > denounce), в этом условии мы сначала проверяем равно ли состояние контакта кнопки значению LOW (то есть нажата ли она). Далее в этом условии мы проверяем закончилась ли задержка, необходимая для борьбы с дребезгом контактов кнопки. Если оба условия выполняются, мы регистрируем успешное нажатие кнопки и инкрементируем значение переменной encoder_btn_count. Если значение переменной encoder_btn_count больше 2, то мы снова его сбрасываем в 0. Значение переменной encoder_btn_count определяет вид формируемого сигнала: 0 – синусоидальный сигнал, 1 – прямоугольный, 2 – треугольный. После выбора формы сигнала мы обновляем состояние дисплея с помощью функции update_display() и обновляем состояние переменной time.

Затем мы в коде программы мы устанавливаем для всех кнопок задержку, необходимую для борьбы с дребезгом их контактов (debounce delay). Поскольку кнопки подключены у нас к аналоговым контактам платы Arduino, мы будем считывать их состояние с помощью функции analogRead. Если считанное аналоговое значение (с выхода АЦП) меньше 30, мы регистрируем нажатие кнопки. Также мы выжидаем задержку 200 мс чтобы удостовериться в том, что это было действительно нажатие кнопки, а не влияние посторонних шумов. Если условие выполняется, то устанавливаем значения соответствующих логических переменных чтобы указать значения Гц, кГц и МГц для нашего генератора сигналов. Также мы обновляем состояние дисплея и переменной time. Эти операции мы производим для всех четырех кнопок, подключенных к плате Arduino.

Теперь рассмотрим нашу функцию update_display(). Дело в том, что мы не сможем просто обновить небольшой кусок экрана дисплея, нам необходимо полностью перерисовать его. Поэтому внутри этой функции мы сначала очистим экран дисплея, затем мы установим размер текста, установим позицию дисплея и выполним команду display.println("Function Function"). Затем мы установим размер текста равный 2 и установим курсор в позицию (0,20) с помощью функции display.setCursor(0, 20).

Далее мы проверим состояние логических переменных, отвечающих за значение частоты, и обновим значение частоты в переменной moduleFrequency. Затем мы проверим состояние переменной waveSelect и определим какой вид сигнала необходимо формировать.

Затем мы снова установим позицию курсора и отобразим на экране дисплея обновленное значение переменной counter. Снова проверим состояние логических переменных, отвечающих за значение частоты, чтобы обновить значение частоты на кране дисплея.

После этого мы проверим состояние переменной btn_state, показывающей нажата кнопка или нет, чтобы высветить на экране OLED дисплея сообщение "Output ON" или "Output OFF".

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

Чтобы проверить работу сконструированного нами генератора сигналов, мы подали питание 12V с адаптера на разъем DC barrel jack нашей конструкции, а также подключили осциллограф к выходу схемы. Также осциллограф мы подключили к компьютеру чтобы визуализировать получаемые нами сигналы.

Подключение осциллографа для тестирования генератора сигналов

После этого мы с помощью инкрементального энкодера установили частоту равную 5 кГц и протестировали формируемый сигнал синусоидальной формы.

Сигнал синусоидальной формы

После этого мы проверили формирование сигнала треугольной формы, также на частоте 5 кГц.

Сигнал треугольной формы

И, наконец, мы проверили формирование сигнала прямоугольной формы.

Сигнал прямоугольной формы

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

Возможные улучшения проекта

Для улучшения внешнего вида проекта и уменьшения нежелательных связей между элементами схемы желательно конструировать ее на печатной плате. Также для повышения качества формируемого сигнала на высоких частотах необходимо использовать коннектор BNC типа. Амплитуда сигнала на выходе нашего генератора сигналов имеет небольшую величину, для ее увеличения целесообразно использовать операционный усилитель. Для регулировки амплитуды сигнала на выходе генератора неплохо бы использовать потенциометр. Также желателен переключатель, с помощью которого можно было бы управлять сдвигом сигнала. Также можно заменить OLED дисплей на какой-нибудь более удобный вид дисплея, чтобы не перерисовывать заново весь экран при каждом обновлении данных – из-за этого, в частности, существенно усложнился код нашей программы.

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

Видео, демонстрирующее работу генератора сигналов

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

(Проголосуй первым!)
Загрузка...
17 980 просмотров

Комментарии

Генератор сигналов на Arduino и DDS модуле AD9833 — 14 комментариев

    • В библиотеке AD9833.h я прямых способов для этого не нашел, но если изменить ее код, то можно.

  1. Спасибо за подробные описание текста программы
    но собрать для прошивки не получается у меня с помощью Arduino IDE
    как можно скачать прошивку ? Спасибо!

    • Анатолий, код программы приведен в статье, а свой комментарий вы оставили только с целью поставить спамную ссылку в своем профиле. Спамить ведь не хорошо

  2. Да уж, я пока понял, что sck и data перепутаны - вспотел. Осликом увидел, что на data ровные импульсы. Но там еще какая-то лажа в коде. После 32кГц частота прыгает на 12,5Мгц

    • К сожалению, мы лично не собирали данный проект, поэтому возможные опечатки в коде программы мы не исправили. Но у статьи уже более 11 тыс. просмотров и больше никто на данный скачок частоты не жаловался. Может быть, данную проблему легко исправить. При подобных ошибках я всегда советую идти от простого к сложному - то есть начинать отладку программы с минимального фрагмента кода и потом постепенно добавлять в него новые фрагменты. Так легче всего найти ошибку в коде

  3. Можно ли на основе этого генератора собрать импедансметр с этими же частотными возможностями?

    • К сожалению, мало знаком с особенностями работы импедансметров, поэтому не могу подсказать ничего конкретного по вашему вопросу

  4. Данную схему копируют с сайта на сайт, но ни кто не удосужился ее проверить. вход SDATA модуля AD9833 необходимо подключать к выходу D11 Nano, а CLK (SCLK, SCK) модуля AD9833 к D13 Nano. На схеме все наоборот. В Данной схеме можно использовать OLED 128X32 c небольшой правкой кода. Но в целом решение не очень удачное и удобное. Что бы добраться до 923kHz крутить энкодер рука устанет. Да и использование трех кнопок для выбора диапазона тоже не очень разумное решение. Вообщем надо полностью переделывать код и кое-что в схемотехнике. Есть мысли поставить на выход усилитель и добавить управляющий таймер с управлением с этого-же энкодера

    • Спасибо за такой подробный комментарий. Лично у меня не было возможности собрать данный проект, поэтому я его только перевел с сайта индийских энтузиастов (ссылка на источник имеется). Судя по количеству просмотров, которые набирают статьи на моем сайте, посвященные созданию различных генераторов сигналов, мои статьи далеко не самые худшие среди аналогичных статей в рунете. Я просто вижу, что на других сайтах иногда ленятся и не переводят некоторые части статьи с первоисточника, например, объяснение кода программы мало кто переводит. Я же стараюсь переводить всю статью полностью.
      Но опечатки на сайте индийских энтузиастов все таки иногда имеются (хотя проекты у них на сайте реально хорошие, одни из лучших в сети). Поэтому хочется сказать спасибо и вам, и другим пользователям нашего сайта, которые указывают на эти опечатки

        • Спасибо что оценили мой труд. Буду признателен если потом вы отпишитесь здесь о том, удалось ли вам реализовать все те усовершенствования в проекте, которые вы хотите в нем сделать

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

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