Arduino uno как сделать генератор синусоидального сигнала

от admin

DDS-генератор синусоидального сигнала

В данном проекте рассмотрим изготовление генератора синусоидального сигнала при помощи метода прямого синтеза (DDS-метод). Для реализации этого проекта нам не потребуется какого-либо дополнительного оборудования кроме самого контроллера Arduino. Частотный диапазон генератора от 0 до 16 кГц, с точностью до 1 мкГц! Данное устройство может пригодится не только для генерирования звуковых сигналов, но в тестовом и измерительном оборудовании радиолюбителя. Например в телекоммуникационном оборудовании DDS генератор можно использовать для ЧМ и ФМ модуляции (FSK и PSK).

DDS-метод

В программной части проекта, для реализации DDS метода, нам понадобится 4 вещи:
аккумулятор и tuning word, который в нашем случае состоит из двух long integer переменных;
таблица значений синусоидального сигнала (один период);
цифро-аналоговый преобразователь, который обеспечивается внутренним ШИМ Arduino (analogWrite);
генератор тактовых импульсов (используем внутренний hard-таймер от ATMega).
Большинство значащих байт аккумулятор используется для адресов таблицы синусоидального сигнала. Весь циклический процесс, работает по прерыванию от внутреннего тактового генератора.

Программное обеспечение

Для работы данного скетча на Arduino Diecimila или Duemilenove подключите потенциометр к аналоговому выводу 0 и к GND и +5В. Выход генератора находится на выводе 11, куда вы можете подключить активные колонки, или ФНЧ фильтр описанный ниже.

Результат

Ниже представлена осциллограмма, на верхней части которой изображен ШИМ-сигнал на 11 выходе, а в нижней части этот же сигнал после фильтра низких частот (ФНЧ). Синусоида выглядит не очень чистой, но это в основном из-за ограниченной разрешающей способности цифрового осциллографа.

Осциллограмма DDS-генератора

Спектрограмма показала неожиданно хороший результат. Большой пик — это на частоте около 1000 Гц. Все нежелательные искажения находятся ниже 50 дБ, возникшие из-за того, что использовался 8 битный ЦАП (1/256 = 48 дБ).

Спектрограмма DDS-генератора

Выходной фильтр низких частот

Для начала, вы можете подсоединить 11 пин контроллера к активным колонкам. Но скорее всего, вам еще понадобится ФНЧ-фильтр, который также будет отфильтровывать частоту дискретизации 32 кГц. Ниже представлена схема такого фильтра с частотой среза 12 кГц.

Схема фильтра низких частот

Аппаратная реализация DDS

Данная программная реализация алгоритма DDS имеет некоторые недостатки, связанные с ограниченной скоростью алгоритма программы, а также возможностями микроконтроллера ATMega. Специализированные DDS-микросхемы лишены этих недостатков и покрывают диапазон от 0 до 100 МГц.

Извещатель о прохождении слабого сигнала (Weak Signal Propagation Reporter) — программное обеспечение позволяющее передавать и принимать сигналы радиомаяков, задействуя не только передатчик, но и интернет. При помощи данного DDS-генератора можно генерировать 4 тоновых последовательности частотой 1497.8 1499.3 1500.7 1502.2 Гц.

Arduino uno в качестве генератора прямоугольных импульсов с регулируемой частотой и рабочим циклом

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

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

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

Кухонный таймер Ардуино с энкодером

Сейчас рассмотрим, как сделать таймер на Ардуино своими руками с энкодером и LCD. Принцип управления, подобен предыдущему варианту. Поворотом ручки энкодера можно задать необходимый временной интервал, а нажатием на ручку можно запускать и останавливать обратный отсчет времени. Далее размещена схема сборки проекта на Arduino Nano, этот проект можно собрать и на плате Arduino Uno.

Скетч таймера обратного отсчета времени

Пояснения к коду:
  1. частоту звукового сигнала можно изменить через команду tone();
  2. для скетча потребуется установить библиотеку RotaryEncoder.

Работа схемы

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

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

Элементы платы

Дисплей

Дисплей MT-16S2H-I умеет отображать все строчные и прописные буквы латиницы и кириллицы, а также типографские символы. Для любителей экзотики есть возможность создавать собственные иконки.

Экран выполнен на жидкокристаллической матрице, которая отображает 2 строки по 16 символов. Каждый символ состоит из отдельного знакоместа 5×8 пикселей.

Контроллер дисплея

Матрица индикатора подключена к встроенному чипу КБ1013ВГ6 с драйвером расширителя портов, которые выполняют роль посредника между экраном и микроконтроллером.

Контроллер КБ1013ВГ6 аналогичен популярным чипам зарубежных производителей HD44780 и KS0066, что означает совместимость со всеми программными библиотеками.

I²C-расширитель

Для экономии пинов микроконтроллера на плате дисплея также распаян дополнительный преобразователь интерфейсов INF8574A: микросхема позволит общаться экрану и управляющей плате по двум проводам через интерфейс I²C.

Контакты подключения

На плате дисплея выведено 18 контактов для подведения питания и взаимодействия с управляющей электроникой.

Вывод Обозначение Описание
1 GND Общий вывод (земля)
2 VCC Напряжение питания (5 В)
3 VO Управление контрастностью
4 RS Выбор регистра
5 R/W Выбор режима записи или чтения
6 E Разрешение обращений к индикатору (а также строб данных)
7 DB0 Шина данных (8-ми битный режим)(младший бит в 8-ми битном режиме)
8 DB1 Шина данных (8-ми битный режим)
9 DB2 Шина данных (8-ми битный режим)
10 DB3 Шина данных (8-ми битный режим)
11 DB4 Шина данных (8-ми и 4-х битные режимы)(младший бит в 4-х битном режиме)
12 DB5 Шина данных (8-ми и 4-х битные режимы)
13 DB6 Шина данных (8-ми и 4-х битные режимы)
14 DB7 Шина данных (8-ми и 4-х битные режимы)
15 LED+ Питания подсветки (+)
16 LED– Питания подсветки (–)
17 SDA Последовательная шина данных
18 SCL Последовательная линия тактированния

Обратите внимания, что физические контакты подсветки экрана и , также интерфейс шины I²C и расположены не в порядком соотношении с другими пинами экрана.

Питание

Экран совместим со всеми контроллерами с логическим напряжением от 3,3 до 5 вольт. Но для питания самого индикатора (пин VCC) необходимо строго 5 вольт

Если в вашем проекте нет линии 5 вольт, обратите внимание на дисплей текстовый экран 16×2 / I²C / 3,3 В.

Интерфейс передачи данных

Дисплей может работать в трёх режимах:

  • 8-битный режим — в нём используются и младшие и старшие биты (-)
  • 4-битный режим — в нём используются только младшие биты (-)
  • I²C режим — данные передаются по протоколу I²C/TWI. Адрес дисплея .

Использовать восьмибитный и четырёхбитный режим в данном дисплее не целесообразно. Ведь главное достоинство этой модели именно возможность подключения через I²C.
Если всё-таки есть необходимость использовать 4-битный или 8-битный режим, читайте документацию на текстовый экран 16×2.

Объединение питания

Для подключения питания к дисплею необходимо пять контактов:

Вывод Обозначение Описание
1 GND Общий вывод (земля)
2 VCC Напряжение питания (5 В)
3 VO Управление контрастностью
15 LED+ Питания подсветки (+)
16 LED– Питания подсветки (–)

Но если запаять перемычки и на обратной стороне дисплея, количество контактов питания можно сократить до трёх, объединив цепь питания и подсветки дисплея.

Мы взяли этот шаг на себя и спаяли перемычки самостоятельно.

Выбор адреса

Используя шину можно подключить несколько дисплеев одновременно, при этом количество занятых пинов останется прежним.

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

Капнув припоем на контактные площадки, мы получим один из семи дополнительных адресов:

  • нет припоя, соответственно нет электрического контакта.
  • есть припой, соответственно есть электрический контакт.

Микросхема (модуль) Si5351

Микросхема Si5351 это конфигурируемый через I2C генератор тактовых частот, идеально подходящий для замены кварцев, кварцевых генераторов, генераторов VCXO (voltage-controlled crystal oscillator – кварцевый генератор, управляемый напряжением), синтезаторов с ФАПЧ (PLL), буферов развязки в приложениях, критичных к общей стоимости. Базируясь на архитектуре PLL/VCXO + high resolution MultiSynth fractional divider, Si5351 может генерировать любую частоту до 200 МГц на каждом из выходов с нулевым отклонением от заданного значения (0 ppm error). Для удовлетворения различным требованиям приложений Si5351 выпускается в 3 версиях. Si5351A генерирует до 8 не зависящих друг от друга тактовых сигналов, используя внутренний генератор, что позволяет заменить несколько кварцев или кварцевых генераторов. В Si5351B добавлен внутренний VCXO, что дает возможность заменить как свободно (независимо друг от друга), так и синхронно генерируемые тактовые частоты. Это устраняет необходимость применения дорогих специальных кварцев, предоставляя при этом высокую надежность работы в широком диапазоне настраиваемых частот. Si5351C предоставляет такую же гибкость, но синхронизируется при этом с внешним опорным генератором (CLKIN).

Узнать более подробную информацию о микросхеме Si5351 и ее подключение к плате Arduino вы можете на сайте ее разработчика. Также принципы ее работы неплохо описаны на сайте microsin.net.

Внесение изменений в настройки проекта (User Preferences)

Вы можете изменить следующие строки в скетче:

#define IF 455 //введите вашу IF (промежуточную) частоту, ex: 455 = 455kHz, 10700 = 10.7MHz, 0 = прямое преобразование частоты приемника или радиочастоты генератора, «+» будет добавляться, а «-» будет вычитаться сдвиг промежуточной частоты.#define BAND_INIT 7 // введите ваш начальный диапазон (Band) (1-21) в начале работы проекта, ex: 1 = Freq Generator, 2 = 800kHz (MW – средние волны), 7 = 7.2MHz (40m), 11 = 14.1MHz (20m).#define XT_CAL_F 33000 // коэффициент калибровки модуля Si5351, можно настроить чтобы получить точно 10MHz. Увеличение этого значения будет уменьшать частоту и наоборот.#define S_GAIN 303 //настройка чувствительности входа измерителя мощности (Signal Meter A/D input): 101 = 500mv; 202 = 1v; 303 = 1.5v; 404 = 2v; 505 = 2.5v; 1010 = 5v (max).#define tunestep A0 //контакт, к которому подключена кнопка для настройки шага настройки.#define band A1 //контакт, к которому подключена кнопка для выбора частотного диапазона.#define rx_tx A2 // контакт, к которому подключена кнопка для выбора режима RX / TX, RX = switch open (переключатель открыт), TX = switch closed to GND (переключатель замкнут на землю). В режиме TX частота IF (промежуточная) не учитывается.#define adc A3 //контакт, используемый как вход измерителя мощности (Signal Meter A/D input).

Другие полезные функции библиотеки LiquidCrystal

Есть несколько полезных функций, которые вы можете использовать с объектом LiquidCrystal. Немногие из них перечислены ниже:

  • Если вы просто хотите расположить курсор в верхнем левом углу дисплея без очистки дисплея, используйте home().
  • Существует много приложений, таких как turbo C++ или notepad ++, в которых нажатие клавиши «insert» на клавиатуре меняет курсор. Точно так же вы можете изменить курсор на ЖК-дисплее с помощью blink() или lcd.Cursor().
  • Функция blink() отображает мигающий блок размером 5 × 8 пикселей, а lcd.Cursor() подчеркивание (линия) на позиции, в которую будет записан следующий символ.
  • Вы можете использовать функцию noblink(), чтобы отключить мигающий курсор на дисплее и lcd.noCursor() чтобы скрыть курсор.
  • Вы можете прокрутить содержимое дисплея на один пробел вправо, используя lcd.scrollDisplayRight() или один пробел влево используя lcd.scrollDisplayLeft(). Если вы хотите непрерывно прокручивать текст, вам нужно использовать эти функции внутри цикла for.

Элементы платы

Дисплей

Дисплей MT-16S2H умеет отображать все строчные и прописные буквы латиницы и кириллицы, а также типографские символы. Для любителей экзотики есть возможность создавать собственные иконки.

Экран выполнен на жидкокристаллической матрице, которая отображает 2 строки по 16 символов. Каждый символ состоит из отдельного знакоместа 5×8 пикселей.

Контроллер дисплея

Матрица индикатора подключена к встроенному чипу КБ1013ВГ6 с драйвером расширителя портов, которые выполняют роль посредника между экраном и микроконтроллером.

Контроллер КБ1013ВГ6 аналогичен популярным чипам зарубежных производителей HD44780 и KS0066, что означает совместимость со всеми программными библиотеками.

Контакты подключения

На плате дисплея выведено 16 контактов для подведения питания и взаимодействия с управляющей электроникой.

Вывод Обозначение Описание
1 GND Общий вывод (земля)
2 VCC Напряжение питания (5 В)
3 VO Управление контрастностью
4 RS Выбор регистра
5 R/W Выбор режима записи или чтения
6 E Разрешение обращений к индикатору (а также строб данных)
7 DB0 Шина данных (8-ми битный режим)(младший бит в 8-ми битном режиме)
8 DB1 Шина данных (8-ми битный режим)
9 DB2 Шина данных (8-ми битный режим)
10 DB3 Шина данных (8-ми битный режим)
11 DB4 Шина данных (8-ми и 4-х битные режимы)(младший бит в 4-х битном режиме)
12 DB5 Шина данных (8-ми и 4-х битные режимы)
13 DB6 Шина данных (8-ми и 4-х битные режимы)
14 DB7 Шина данных (8-ми и 4-х битные режимы)
15 LED+ Питания подсветки (+)
16 LED– Питания подсветки (–)

Обратите внимания, что физические контакты подсветки экрана и расположены не в порядком соотношении с другими пинами экрана.

Питание

Экран совместим со всеми контроллерами с логическим напряжением от 3,3 до 5 вольт. Но для питания самого индикатора (пин VCC) необходимо строго 5 вольт

Если в вашем проекте нет линии 5 вольт, обратите внимание на дисплей текстовый экран 16×2 / I²C / 3,3 В.

Интерфейс передачи данных

Дисплей может работать в двух режимах:

  • 8-битный режим — в нём используются и младшие и старшие биты (-)
  • 4-битный режим — в нём используются только младшие биты (-)

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

Примеры работы для Espruino

В качестве примера подключим дисплей к управляющей плате Iskra JS.

Подключение к Iskra JS

Для коммуникации понадобится Breadboard Half и соединительные провода «папа-папа».

Вывод Обозначение Пин Iskra JS
1 GND GND
2 VCC 5V
3 VO GND
4 RS P11
5 R/W GND
6 E P12
7 DB0
8 DB1
9 DB2
10 DB3
11 DB4 P5
12 DB5 P4
13 DB6 P3
14 DB7 P2
15 VCC 5V
16 GND GND

Вывод текста

Для вывода программы приветствия, воспользуйтесь скриптом:

Кирилица

Вывод кирилицы на дисплей с помощью платформы Iskra JS доступен через встроенную в дисплей таблицу знакогенератора.

Таблица знакогенератора

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

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

Так букве соответствует код в шестнадцатеричной системе. Чтобы передать на экран строку «Яndex», необходимо в явном виде с помощью последовательности встроить в строку код символа:

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

Сравните две строки кода для вывода надписи «Яeee»:

Используя полученную информацию выведем на дисплей сообщение «Привет, Амперка!»:

Переключение страниц знакогенератора

Дисплейный модуль хранит в памяти две страницы знакогенератора. По умолчанию установлена нулевая страница. Для переключения между страницами используйте методы:

Дисплей не может одновременно отображать символы разных страниц.

Рассмотрим пример, в котором одна и та же строка будет отображаться по-разному — в зависимости от выбранной страницы.

Полную таблицу символов с кодами можно найти в документации к экрану.

Русификация LCD 1602 I2C дисплея

Перед загрузкой следующего скетча, необходимо установить библиотеку LCD_1602_RUS.h для русификации дисплея 1602 Ардуино. Архив с библиотекой можно скачать на нашем сайте на странице — Библиотеки для Ардуино. После установки библиотеки из архива загрузите в микроконтроллер небольшой пример с кодом для LCD, который значительно упростит для вас вывод кириллицы на дисплей.

Скетч с библиотекой LCD_1602_RUS.h

Как вывести свой символ на LCD 1602

Вывести свой символ или кириллическую букву на дисплей поможет таблица знакогенератора (CGROM). Такой вид памяти в Ардуино, как CGRAM, может хранить собственные символы, но размер памяти ограничен и может вместить лишь 8 собственных символов. Один из нестандартных символов, который пригодится для создания домашней метеостанции — знак градуса. Давайте нарисуем символ.


Создаем свой символ для LCD дисплея 1602

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

Step 3: Future Developments

Could it be battery powered? Yes, just add a 9V PP3 connected to the RAW pin of the Nano. It typically uses 20mA.

Could it be powered by a single lithium cell? I don’t see why not. You should connect the OLED Vdd and its pull-up resistor to the 3.7V battery (I doubt if the 3.3V output of the Arduino would work properly).

A sweep generator is more useful when testing the frequency response of a filter if you can graph amplitude vs frequency. Measuring the amplitude of a signal is tricky — you have to trade off the decay of your envelope detector vs ripple for low frequencies and response time for high frequencies. Having built your amplitude detector, you could feed its output into the ADC of the Arduino of the «Simplest Signal Generator» then send the result, along with the current frequency to the PC.

Генератор сигналов на микросхеме таймера 555

Генератор сигналов на микросхеме таймера 555. Схема электрическая принципиальная

Прежде всего, мы поговорим о генераторе прямоугольного сигнала на микросхеме 555, или, я бы сказал, о нестабильном (астабильном, автоколебательном) мультивибраторе на 555. Эта схема необходима, потому что для проверки частотомера нам необходим сигнал, частота которого известна. Без этого сигнала мы не сможем рассказать о работе частотомера. Если у нас есть прямоугольный сигнал с известной частотой, мы можем использовать его для проверки частотомера на Arduino и для подстройки точности в случае любых отклонений. Макет генератора сигнала на микросхеме таймера 555 показан ниже.

Макет генератора сигналов на микросхеме таймера 555

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

Типовая схема на таймере 555 в автоколебальном режиме

Частота выходного сигнала зависит от резисторов RA и RB и конденсатора C. Формула будет следующей:

Здесь RA и RB – значения сопротивлений, а C – значение емкости. Подставляя значения сопротивлений и емкости в приведенную выше формулу, мы получаем частоту выходного прямоугольного сигнала.

Можно увидеть, что RB на схеме выше заменен в нашей схеме генератора сигналов потенциометром; это сделано для того, чтобы для лучшего тестирования мы могли получить на выходе прямоугольный сигнал переменной частоты. Для простоты можно заменить этот потенциометр простым резистором.

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


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

А вот тут и начинается текст по делу ��

Итак. Синусоида. Значит из цифр (которыми оперирует Ардуинка) нам нужно получить аналоговый сигнал… А значит нам нужен Цифро-Аналоговый Преобразователь (или ЦАП, или DAC -по ненашему).
Меня это не сильно испугало. Я уже сталкивался с ЦАП-ми, а конкретнее в детстве паял вариант R-2R. Те, кто постарше наверняка помнят такие чудесные поделки, как Covox ( http://ru.wikipedia.org/wiki/Covox ). В те годы (примерно 90-ые), мне только доводилось мечтать о звуковой карте, а вот вышеупомянутое устройство, да еще сделанное своими руками – доставило столько приятных минут ��
Итак, сказано – сделано!
Ну, будучи до конца честным, признаюсь. Я для начала поискал готовые решения для Ардуино в просторах Интернета. (Вот один из вариантов, с применением ШИМ-сигнала: http://electronics.stackexchange.com/questions/41738/possible-to-output-sinusoidal-signal-with-an-arduino. Не понравился.)

Итак, нам нужено изготовить простейший цифро-аналоговый преобразователь: R-2R.
Вот буржуйское описание: http://en.wikipedia.org/wiki/Resistor_ladder

(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-ми разрядный, как у нас) был подключен к целому порту. Тогда выводить любое значение в ЦАП — будет очень просто:

Итак, прикидываем на макетке:

Проверяем работоспособность, засылая в порт различные значения. Мультиметром замеряем напряжение на выходе — все очень хорошо. Можем двигаться дальше. С «железной» частью вроде как разобрались.

Теперь математическая составляющая.
Вооружившись школьным учебником алгебры (шучу… шучу, конечно же Википедия!) вспоминаем, что такое Синусоида: http://ru.wikipedia.org/wiki/Синусоида


Адаптируем к нашим условиям. ЦАП может выдавать значения от 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 значений мне показалось «времярасточительным» занятием. НО у меня же есть Ардуинка! (И я ОЧЕНЬ стараюсь использовать ее по полной программе.). Вот ее и заставим произвести нужные мне расчеты.

Вот наша таблица значений :

Набрасываем скетчик для вывода значений таблицы в ЦАП:

Вроде как и все. Но, как говорят французы, «аппетит приходит во время еды», а именно, оказывается нужно две синусоиды.
А, была-не была. Тем более, столько уже проделано. Макетим.

«Допиливаем» скетч, сделаем небольшое смещение синусоид offset 128. (Кстати, огромная благодарность Юре, за идею «склейки» пинов для получения «полного» порта).

Делаем контрольный замер, подключив выходы ЦАП-ов к осциллографу (красиво совмещаем выдаваемые Ардуинкой синусоиды):

Красота! То, что и желали получить. Все, мой приятель остался очень доволен. Я отдал ему прошитую Atmeg-у для дальнейшего применения.

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

Начнём с самого простого: генерация импульса заданной длины, такое часто бывает нужно. Проще всего сделать это на delay() и delayMicroseconds() :

Нужно помнить, что digitalWrite() сам по себе выполняется в районе 3.6 мкс (58 тактов процессора). Для ускорения можно использовать например библиотеку directIO или прямую работу с регистрами портов.

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

Программное

Квадратный сигнал может быть использован для тактирования и управления, а также для генерации звука через усилитель. Самый базовый пример, Blink, по сути тоже является генератором квадратного сигнала:

Если заменить 1000 например на 10 , то получится квадратный сигнал с частотой 50 Гц. Этот способ называется программной генерацией сигнала, то есть микроконтроллер своими силами считает время и сам вручную дёргает ногой. Это как мешает работе остального кода, так и остальной код может сбивать частоту. Такую генерацию можно сделать более мене асинхронной на миллисе:

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

Функция tone()

В ядре Arduino есть встроенная функция для полуаппаратной генерации квадратного сигнала – tone(pin, frequency, duration) :

  • pin – цифровой пин, с которого будет генерироваться сигнал.
  • frequency – частота в Герцах. Диапазон 31.. 65’535 Гц
  • duration – продолжительность сигнала в миллисекундах. Опциональный параметр, если не указывать – сигнал будет генерироваться без остановки.

Для ручной остановки генерации сигнала можно вызвать noTone() . Также у генерации при помощи tone() есть особенности:

  • Генерация является полуаппаратной: пин дёргается МК “вручную” по прерыванию таймера, что на высокой частоте может чуть тормозить код.
  • Генерация использует Timer 2, перенастройка или использование его для других целей (включая ШИМ на пинах D3 и D11 у Nano) отключит активную генерацию или изменит её частоту.
    • При вызове tone() таймер перенастраивается на генерацию, то есть можно использовать таймер в своих целях между вызовами tone() .

    ШИМ сигнал

    Аппаратный таймер позволяет генерировать квадратный сигнал аппаратно и полностью асинхронно работе остального кода, не тратя ни такта процессорного времени: время считается самим таймером, и сам же таймер управляет состоянием ноги МК. Для генерации ШИМ сигнала в среде Arduino есть функция analogWrite(pin, duty) , подробнее мы говорили в ней в уроке про ШИМ. Чтобы сделать ШИМ квадратным, нужно запустить его с duty , равной 128 . Что касается частоты полученного сигнала, то Ардуино настраивает таймеры так, что частота в зависимости от таймера может быть 490 или 980 Гц. Частоту можно изменить с довольно большим шагом, об этом мы говорили в уроке про увеличение частоты ШИМ.

    Аппаратный таймер

    Можно вручную настроить аппаратный таймер на генерацию квадратного сигнала. Тонкости настройки регистров таймера мы в рамках этих уроков не разбираем, но это можно сделать и при помощи библиотеки, например GyverTimers. Работу библиотеки мы разбирали в уроке о прерываниях таймера. Данная библиотека позволяет настроить генерацию квадратного сигнала с максимально возможной точностью и частотой, а также поднять на одном таймере генерацию двух или трёх (Arduino MEGA) меандров со смещением по фазе. Пример:

    ШИМ сигнал

    Аппаратный

    Для генерации ШИМ сигнала с заданным заполнением есть стандартная функция analogWrite(pin, duty) , подробнее обсуждали в уроке про ШИМ сигнал, а частоту можно изменить перенастройкой таймера, как в уроке об увеличении частоты ШИМ. На самом деле таймеры позволяют настроить ШИМ сигнал с более точной или более высокой частотой и другими диапазонами заполнения (до 10 бит), но в ядре Arduino это не предусмотрено. Если такое будет нужно, можно воспользоваться библиотекой GyverPWM. Пример:

    Программный ШИМ

    Программная генерация ШИМ сигнала может пригодиться, если не хватает лишнего таймера или частота ШИМ низкая и не повлияет на остальной код, а он на неё. ШИМ сигнал на “миллисе” можно организовать вот таким образом, переключая выход по двум периодам:

    Функцию PWMgen(заполнение) в данной реализации нужно вызывать как можно чаще в основном цикле программы:

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

    Полуаппаратный ШИМ

    Можно снизить нагрузку на процессор, отдав счёт времени аппаратному таймеру. Примеры на базе GyverTimers (для ATmega328, 2560):

    Как известно, digitalWrite() является очень тяжёлой и долгой функцией, и для генерации софт ШИМ рекомендуется заменить её чем-то более быстрым, например прямым обращением к регистру или вот такой конструкцией (для ATmega328p):

    Если не хватает количества стандартных ШИМ-выходов, можно поднять полуаппаратный ШИМ на таймере на несколько пинов сразу:

    Этот алгоритм является не самым оптимальным, более интересный можно посмотреть в GyverHacks.

    Примечание: во всех трёх алгоритмах используется проверка совпадения со счётчиком counter == pwm_duty . Это сильно снижает использование процессорного времени в прерывании, но при резком уменьшении заполнения может приводить к одиночным “вспышкам” заполнения до максимума, так как условие не выполнится. Для более плавной работы можно сделать counter >= pwm_duty , тогда условие будет каждый раз “подстраиваться” под новое значение заполнения, но установка пина будет осуществляться на каждом тике!

    Можно ввести буферизацию заполнения ШИМ и брать новое значение только при нулевом значении счётчика, это решит проблему:

    Можно применить буферизацию и к остальным алгоритмам.

    Библиотека Servo

    Как известно, RC сервоприводы управляются при помощи ШИМ сигнала с частотой

    50 Гц и длительностью импульса от

    2500 микросекунд. В стандартной библиотеке Servo.h реализована генерация полуаппаратного ШИМ сигнала, причём количество пинов можно менять во время работы. Библиотеку можно использовать как генерацию ШИМ, если его параметры подходят для использования.

    Чтение сигналов

    Чтение цифрового сигнала сводится к измерению времени между его импульсами, то есть изменениями состояния HIGH-LOW: так можно измерить период и частоту квадратного сигнала, заполнение и частоту ШИМ и вообще любой другой сигнал.

    Функция pulseIn()

    В ядре Ардуино есть готовые функции для измерения импульсов:

      pulseIn(pin, value, timeout) – для импульсов от 10 мкс до

    Измеренная мной точность на коротких импульсах: 0.5 мкс

    Обе функции возвращают длину импульса в микросекундах. Возвращают 0, если импульса не было и был достигнут тайм-аут. Обе функции блокирующие, то есть останавливают выполнение кода, пока не поймают импульс или не завершатся по тайм-ауту. Аргументы:

    • pin – цифровой пин (GPIO), на котором ожидается импульс.
    • value – направление импульса, HIGH или LOW .
    • timeout – тайм-аут ожидания импульса в микросекундах. Необязательный параметр, по умолчанию равен 1’000’000 мкс (1 секунда).

    Как это работает: пусть мы настроили импульс на HIGH , функция будет ожидать изменение значения с LOW на HIGH . Если скачок с LOW на HIGH не произошёл за время, установленное тайм-аутом, функция завершит выполнение и вернёт 0.

    Для превращения длины импульса (мкс) в частоту (Гц) достаточно поделить на него секунду (точнее, 1’000’000 мкс).

    Измеряем сигналы вручную

    Квадратный сигнал можно “измерить” вот таким образом:

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

    Считаем импульсы и иногда делаем расчёт:

    Также рассмотрим измерение параметров ШИМ сигнала, например на прерываниях и micros() :

    Библиотека тахометра

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

    “Запоминаем” сигнал

    Также можно очень просто запомнить цифровой сигнал в Arduino для дальнейшего воспроизведения и исследования. Вот пример, который будет работать на любом пине (используется digitalRead() и micros()):

    Измерение начнётся по изменению сигнала и продлится до тех пор, пока не переполнится буфер или работа не завершится по таймауту (в примере выше 1 секунда с последнего импульса). После этого в монитор порта будет выведен начальный уровень сигнала fval и тайминги каждого следующего фронта/спада (изменения). Для примера я подключил ИК приёмник и нажал кнопку на пульте:

    Точность измерения должна быть около 5 мкс на AVR, так как используется тяжёлое чтение пина и микрос. Лучше переписать на прерывания по CHANGE и завести отдельный таймер, тогда точность можно повысить в сотни раз. Код не привожу, так как для разных платформ он будет разный.

    Полученные данные можно использовать для анализа интерфейсов и протоколов, а также можно “воспроизвести” запись. В примере ниже я делаю это отдельным скетчем, вставив тайминги и начальное значение сигнала из лога предыдущего примера.

    Для визуализации подключил дешёвый китайский логический анализатор (ссылка на али, ещё одна) на указанный пин:

    Отлично! Прекрасно виден NEC протокол, его 4-х байтный пакет и код повтора.

    Можно реализовать чтение пакета и его вывод в одной программе, запись дампа в EEPROM/SD для воспроизведения по кнопке и прочих сценариев работы, получив дубликатор цифрового сигнала.

    Читать:
    Как сделать спойлер с названием

Похожие публикации