Генератор прямоугольных импульсов на ардуино

В этом материале представлен простой генератор сигналов на основе ATtiny85. Он может генерировать треугольные, пилообразные, квадратные и прямоугольные формы сигналов, последовательность импульсов и шум. Частота может быть отрегулирована с помощью поворотного энкодера от 1 Гц до 5 кГц с шагом 1 Гц, а выбранный сигнал и частота отображаются на OLED дисплее.

Этот проект использует всю производительность ATtiny85, где контроллер генерирует 8-битные выборки с частотой дискретизации 16 кГц, декодирует поворотный энкодер, переключается между сигналами и обновляет OLED дисплей через линию I2C.

Вступление

Генератор использует прямой цифровой синтез или DDS для генерации сигналов. Обычно DDS использует таблицу предварительно вычисленного сигнала, такого как синусоида. Для генерации определенной частоты вы шагаете по таблице, выбирая каждую n-ю выборку. Чем меньше число, используемое для шага, тем больше времени требуется, чтобы обойти один цикл значений и тем ниже частота.

ATtiny85 идеально подходит для DDS, так как у него есть внутренний источник тактового сигнала частотой 64 МГц, который вы можете использовать для управления таймером/счетчиком 1 и быстрого цифро-аналогового преобразования. Вот процедура инициализации таймеров/счетчиков для DDS:

  void SetupDDS () {     // Включаем PLL на 64 МГц и используем в качестве источника тактового сигнала для таймера/счетчика 1     PLLCSR = 1 << PCKE | 1 << PLLE;       // Настройка таймера/счетчика 1 для выхода ШИМ     TIMSK = 0;  // Прерывания от таймера отключены     TCCR1 = 1 << PWM1A | 2 << COM1A0 | 1 << CS10;  // Канал A, сброс при совпадении, без предделителя     pinMode(1, OUTPUT);   // Включить выходной контакт ШИМ       // Установка таймера/счетчика 0 для прерывания 20 кГц для вывода выборок.     TCCR0A = 3 << WGM00;  // Быстрый ШИМ     TCCR0B = 1 << WGM02 | 2 << CS00;  // Предделитель на 8     TIMSK = 1 << OCIE0A;  // Прерывание по переполнению таймера     OCR0A = 60;  // Делим на 61   }   </pre> В первой строке включается генератор PLL на 64 МГц с ФАПЧ и выбирается в качестве источника синхронизации для таймера/счетчика 1. Затем таймер/счетчик 1 устанавливается в режиме ШИМ, чтобы он действовал как цифро-аналоговый преобразователь, используя значение в OCR1A для изменения коэффициента заполнения и, следовательно, аналогового выхода. Частота прямоугольной волны определяется OCR1C; мы оставляем значение по умолчанию 255, которое делит тактовую частоту на 256, давая меандр частотой 250 кГц. Таймер/счетчик 0 используется для генерации прерывания вывода выборок. Частота этого прерывания равна системной тактовой частоте 8 МГц, деленной на 8 и делитель 61, что составляет около 16,4 кГц. Прерывание вызывает подпрограмму обработки прерывания ISR (TIMER0_COMPA_vect), которая вычисляет и выводит выборки. К счастью, делитель 61 позволяет нам получить шаг частоты очень близкий к 1 Гц. Например, вот расчет, показывающий, какую частоту вы получаете для значения Jump, равного 4. Процедура обслуживания прерываний вызывается один раз каждые 8000000/(8*61) Гц, и каждый раз, когда Jump добавляется в 16-разрядный фазовый аккумулятор - Acc. Поэтому старший бит Acc будет меняться с частотой: 8000000/(8*61)/(65536/4) или 10006 Гц  

В итоге: изменение значения Jump с шагом 4 даст нам частоту 1 Гц с точностью до 0,1%.

Генерация сигналов

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

Форма сигнала “Меандр”

Эта прямоугольная волна имеет коэффициент заполнения 50% и содержит только нечетные гармоники. Вот осциллограмма формы волны:

image

Для прямоугольной волны мы берем старший байт аккумулятора и сдвигаем его вправо на 7 бит. Поскольку это целое число со знаком, это дает 0, если старший бит равен 0, и 0xFF, если старший бит равен единице:

void Square () {    Acc = Acc + Jump;    int8_t temp = Acc >> 8;    OCR1A = temp >> 7;  }  

Форма сигнала “Прямоугольник”

Форма сигнала “Прямоугольник” имеет рабочий цикл 25%:

image

Прямоугольная волна с рабочим циклом D имеет отсутствующую гармонику n всякий раз, когда n * D является целым числом, поэтому в этой волне отсутствуют 4-я, 8-я, 12-я гармоники и т. Д.

Для прямоугольной волны мы берем старший байт аккумулятора И вместе два верхних бита, затем сдвигаем его на 7 бит вправо. Это дает 0xFF, если старшие два бита были 1 и 0 в противном случае:

void Rectangle () {    Acc = Acc + Jump;    int8_t temp = Acc >> 8;    temp = temp & temp << 1;    OCR1A = temp >> 7;  }  

Форма сигнала “Пульс”

Форма сигнала “Пульс” представляет собой прямоугольную волну с соотношением сигнал/пустота 1:16.

Для пульсовой волны мы берем старший байт аккумулятора И вместе четыре старших бита, затем сдвигаем его на 7 бит вправо. Это дает 0xFF, если старшие четыре бита были 1 и 0 в противном случае:

void Pulse () {    Acc = Acc + Jump;    int8_t temp = Acc >> 8;    temp = temp & temp << 1 & temp << 2 & temp << 3;    OCR1A = temp >> 7;  }  

Форма сигнала “Пила”

Пилообразная форма сигнала содержит все гармоники. Она имеет амплитуду от 0 до 255 в каждом цикле, названную так потому, что выглядит как зуб пилы:

Для пилообразной волны мы просто копируем верхний байт аккумулятора на выход:

void Sawtooth () {    Acc = Acc + Jump;    OCR1A = Acc >> 8;  }  

Форма сигнала “Треугольник”

Форма сигнала “Треугольник” близка к чисто синусоидальной форме, но с добавлением нечетных гармоник на более низких уровнях, чем прямоугольная волна. Он считает от 0 до 255, а затем снова до 0:

Для генерации треугольной волны мы берем старший байт аккумулятора и инвертируем его, когда старший бит равен единице:

void Triangle () {    int8_t temp, mask;    Acc = Acc + Jump;    temp = Acc >> 8;    mask = temp >> 7;    temp = temp ^ mask;    OCR1A = temp << 1;  }  </pre> Форма сигнала "Бензопила" Для забавы я включил изобретенную форму волны, которая представляет собой нечто среднее между пилообразной волной и прямоугольной волной: 

Вот как это генерируется:

void Chainsaw () {    int8_t temp, mask, top;    Acc = Acc + Jump;    temp = Acc >> 8;    mask = temp >> 7;    top = temp & 0x80;    temp = (temp ^ mask) | top;    OCR1A = temp;  }  

Форма сигнала “Шум”

Форма сигнала “Шум” имеет равномерное распределение энергии на всех частотах. Это не зависит от настройки контроля частоты.

Здесь используется генератор псевдослучайных чисел для генерации случайных байтов:

void Noise () {    int8_t temp = Acc & 1;    Acc = Acc >> 1;    if (temp == 0) Acc = Acc ^ 0xB400;    OCR1A = Acc;  }

Схема

Вот схема генератора DSS:

Дисплей я выбрал разрешением 128×32 и интерфейсом I2C. Резистор 33 кОм и конденсатор 0,1 мкФ гарантируют правильную инициализацию дисплея при первом включении питания.

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

Резисторы на 4,7 кОм и конденсаторы на 4,7 нФ образуют двухполосный фильтр нижних частот для фильтрации несущей частоты ШИМ. Сглаживание этой цепи составляет 1/2ПRC, поэтому эти значения дают срез 1/(2*3,14*4700*4,7E10-9), что составляет 7,2 кГц. Выход около 1 В, достаточный для управления усилителем или пьезодинамиком, чтобы повысить амплитуду вы можете использовать активный фильтр.

Поскольку выходной сигнал на PB1 переключается между 0 В и +5 В, в сигнале присутствует смещение + 2,5 В постоянного тока. Смещения можно избежать, взяв выходной сигнал относительно виртуального заземления, созданного двумя резисторами 10 кОм.

Программа

Поворотный энкодер

void SetupRotaryEncoder () {    pinMode(EncoderA, INPUT_PULLUP);    pinMode(EncoderB, INPUT_PULLUP);    PCMSK = 1 << EncoderA;        // Прерывание по изменению состояния вывода    GIMSK = 1 << PCIE;            // Разрешаем прерывания    GIFR = 1 << PCIF;             // Очищаем флаг прерываний  }</pre> Поворот энкодера вызывает процедуру ChangeValue() с логическим аргументом для указания направления. Это увеличивает частоту и обновляет дисплей: void ChangeValue (bool Up) {    int step = 1;    if (Freq >= 1000) step = 100;    else if (Freq >= 100) step = 10;    Freq = max(min((Freq + (Up ? step : -step)), MaxFreq), MinFreq);    PlotFreq(Freq, 1, 7);    Jump = Freq*4;  }  

Генератор может потенциально изменять частоту с 0,25 Гц с шагом 0,25 Гц во всем частотном диапазоне, но для удобства я выбрал изменение частоты с шагом 1 Гц в диапазоне от 1 Гц до 99 Гц, с шагом 10 Гц в диапазоне от 100 Гц до 999 Гц, и с шагом 100 Гц от 1000 Гц до 5000 Гц, но вы можете изменить это.

Кнопка энкодера используется для переключения типов сигналов. Поскольку на ATtiny85 нет свободных выводов, для подключения кнопки я использовал вывод сброса ATtiny85. Переменная Wave используется для подсчета количества сбросов и, следовательно, выбора следующего типа сигнала. Эта переменная определена в программе как .noinit, поэтому компилятор не сбросит его до нуля при сбросе. Текущая частота, Freq, также определяется как .noinit, поэтому она не инициализируется при сбросе.

I2C OLED дисплей

Частота сигнала и значок, представляющий текущую форму сигнала, отображаются на OLED-дисплее 128×32 пикселей. Такие дисплеи доступны в версиях SPI и I2C. Я выбрал версию I2C, потому что для ее управления требуется всего две линии ввода/вывода, а на ATtiny85 доступно только две линии.

Согласно данным, контроллер SSD1306, используемый дисплеем, поддерживает отправку комбинации команд и/или данных, поэтому теоретически вы можете записать весь дисплей в одной 512-байтовой передаче I2C. Сначала я изо всех сил пытался заставить это работать. Оказывается, библиотека Arduino Wire работает путем буферизации данных, которые вы отправляете при вызове Wire.write () , и фактически передает их только при вызове Wire.endTransmission () . Кроме того, длина буферов составляет всего 32 байта, поэтому максимальная длина передачи составляет 32 байта. Одним из обходных путей является запись данных и команд в виде серии отдельных однобайтовых сообщений, что и делает Adafruit в своей библиотеке SSD1306, но это очень неэффективно.

Мое решение состояло в том, чтобы разбить передачи максимум на 32 байта за раз. Например, процедура PlotChar() отправляет 24 байта для символа двойного размера, так что это можно сделать за одну передачу.

Частота и значок отображаются в виде двойных символов, чтобы сделать дисплей более читабельным. Символы определяются массивом CharMap [] [] . Иконки осциллограмм создаются из двух символов. В эту программу я включил только определения для цифр, символов “Гц” и значков сигналов, но вы можете добавить полный набор символов, если хотите отображать другие символы.

Выбор формы волны

Наиболее очевидный способ позволить вам выбрать форму сигнала – это использовать оператор case или серию операторов if, чтобы выбрать часть кода для соответствующей формы сигнала в зависимости от значения глобальной переменной; например, это будет выглядеть примерно так:

ISR(TIMER0_COMPA_vect) {    if (Wave == 0) {      // Код для формы сигнала "Треугольник"    } else if (Wave == 1) {      // Код для формы сигнала "Пила"    } else if (Wave == 2) {      // Код для формы сигнала "Прямоугольник"    } else {      // Код для формы сигнала "Шум"    }  }  

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

void Sawtooth () {    Acc = Acc + Jump;    OCR1A = Acc >> 8;  }  

Мы определяем тип wavefun_t, который является функцией без аргументов и без возвращаемого значения:

typedef void (*wavefun_t)();  

а затем определите массив адресов подпрограммы формы волны с помощью:

tconst int nWaves = 4;  wavefun_t Waves[nWaves] = {Triangle, Sawtooth, Square, Noise};  

Чтобы изменить форму волны, мы выполняем:

Wave = (Wave + 1) % nWaves;  Wavefun = Waves[Wave];  

Процедура обработки прерывания становится:

ISR(TIMER0_COMPA_vect) {    Wavefun();  }

Компиляция программы

Я скомпилировал программу, используя Spence Konde’s ATTiny Core. Выберите тип МК ATtiny25/45/85 под заголовком ATtinyCore в меню Board. Затем выберите Timer 1 Clock: CPU , BOD: Disabled, ATtiny85: 8 МГц (внутренний). Выберите Burn Bootloader для правильной установки fuse битов. Затем загрузите программу с помощью ISP (внутрисистемное программирование). Я использовал плату разработчика Sparkfun Tiny AVR.

Калибровка частоты

Точность этого генератора зависит от точности внутреннего 8 МГц тактового сигнала ATtiny85. Чтобы получить максимально точную частоту, вы можете откалибровать внутренний генератор, используя регистр OSCCAL. Самый простой способ – проверить частоту с помощью частотомера. Если у вас нет измерителя частоты, подключите пьезодинамик к выходу, выберите прямоугольную волну с частотой 1 Гц и подсчитайте щелчки с помощью секундомера!

Разместите:

OSCCAL = 128;  

в начале setup() и перекомпилируйте программу с различными значениями OSCCAL, изменяя это значение сначала большими шагами, а затем меньшими шагами по мере приближения к правильной частоте.

Использование ATtiny861

В этом проекте возможности устройства в основном ограничены количеством линий ввода/вывода, доступных в ATtiny85. Чтобы расширить функционал, вы можете использовать ATtiny861, который имеет тот же высокоскоростной генератор PLL, что и ATtiny85, но и содержит более 15 линий ввода/вывода. Это позволит вам подключить внешний кристалл для более точного управления частотой и переключатели, чтобы обеспечить более удобный выбор формы волны и диапазона частот.

Обновления

Описание:

Исходный код, макет печатной платы Eagle

Размер файла: 23.04 KB Количество загрузок: 228

 

  • Автор: David Johnson-Davies

Метки: DDS, Генератор, Arduino, ATtiny85, SSD1306

” onclick=”window.open(this.href,’win2′,’status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=640,height=480,directories=no,location=no’); return false;” rel=”nofollow”> Печать

Порты поддерживающие ШИМ обозначены ~

Привет! Продолжаем говорить про ардуино. Сегодня речь пойдет про широтно-импульсную модуляцию или шим. Что это, как использовать, при чем здесь ардуино? Давайте разбираться.

В прошлый раз мы говорили про написание своей собственной функции. Пожалуйста, посмотрите тот пост, если уже забыли или пропустили его.

Функции. Урок 3. Ардуино

В предыдущих статьях мы рассматривали возможности ардуино по приему и выводу цифровых сигналов. В этом случае мы можем вывести на пин напряжение 0 или 5 вольт. Что считается логическим 0 и 1 соответственно. И также мы можем считать напряжение на пине. Например, когда используем кнопку.

Но часто необходимо использовать напряжение между 0 и 5 вольтами. Чтобы вывести такое напряжение платы ардуино uno недостаточно. Можно использовать ардуино due или подключить внешнюю схему цифроаналогового преобразователя.

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

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

На плате ардуино uno, контакты 3, 5, 6, 9, 10, 11 поддерживают вывод ШИМ сигнала.

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

  • Ардуино UNO
  • Макетная плата
  • Перемычки
  • 4 Резистора номиналом 220 Ом
  • 4 Светодиода 5 мм
  • Кабель USB

analogWrite()

Чтобы использовать возможности шим, рассмотрим новую функцию analogWrite().

Функция analogWrite() принимает два аргумента: номер пина для вывода и 8 разрядное число от 0 до 255, которое будет выводиться на контакте.

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

Загрузим программу из меню File — Examples — Basics — Fade.ino и соберем простую схему на макетной плате. Нам понадобятся один резистор, один светодиод и несколько перемычек.

Принципиальная схема подключения для шим сигнала

Текст программы

int led = 9;           // the PWM pin the LED is attached to int brightness = 0;    // how bright the LED is int fadeAmount = 5;    // how many points to fade the LED by  // the setup routine runs once when you press reset: void setup() {   // declare pin 9 to be an output:   pinMode(led, OUTPUT); }  // the loop routine runs over and over again forever: void loop() {   // set the brightness of pin 9:   analogWrite(led, brightness);    // change the brightness for next time through the loop:   brightness = brightness + fadeAmount;    // reverse the direction of the fading at the ends of the fade:   if (brightness <= 0 || brightness >= 255) {     fadeAmount = -fadeAmount;   }   // wait for 30 milliseconds to see the dimming effect   delay(30); }

В тексте программы все уже должно быть понятно, чуть позже мы модифицируем ее и разберем подробнее. Пока что нас интересует только функция analogWrite() которая устанавливает на пин 9 напряжение 5 вольт, но особым способом.

Скважность

Скважность — это отношение периода повторения импульсов к длительности импульса. Чтобы лучше это понять рассмотрим графики.

ШИМ представляет собой изменение скважности прямоугольной последовательности импульсов. Скважность можно трактовать как процент времени, когда прямоугольный импульс имеет уровень HIGH, ко всему периоду повторения. Скважность 50% означает, что половину периода сигнал имеет высокий уровень, а половину — низкий.

ШИМ и скважность

Функция analogWrite() устанавливает скважность последовательности прямоугольных импульсов в зависимости от значения, передаваемого ей.

На графиках видно, что для сигнала со скважностью 25% значение HIGH действует в течение четверти периода, а остальные 75% времени установлено значение LOW. Частота прямоугольной последовательности импульсов в случае Arduino составляет приблизительно 490 Гц. Другими словами, уровень сигнала меняется от высокого (5 В) к низкому (0 В) приблизительно 490 раз каждую секунду.

Как видим, напряжение, подаваемое на светодиод, на самом деле не понижается, почему же при уменьшении скважности наблюдается спад яркости свечения светодиода? Это связано с особенностью нашего зрения. Если светодиод включается и выключается один раз за 1 мс (при скважности 50%), то вам кажется, что яркость свечения светодиода составляет приблизительно 50% от максимальной, потому что переключение происходит быстрее, чем глаза могут это зафиксировать. Ваш мозг фактически усредняет сигнал и создается впечатление, что светодиод работает на половине яркости.

Теперь изменим программу и соберем более интересную схему.

Принципиальная схема подключения светодиодов и шим

Подключим все 4 светодиода к шим портам ардуино через резисторы. Катоды всех диодов подключим к общей земле. Используем контакты 3, 6, 9 и 11.

Объявим массив светодиодов, счетчики и настроим пины на вывод.

int brightness = 0; int fadeAmount = 5;  int leds[] = {3, 6, 9, 11}; int j=0; int delta=1; void setup() {   pinMode(leds[0], OUTPUT);   pinMode(leds[1], OUTPUT);   pinMode(leds[2], OUTPUT);   pinMode(leds[3], OUTPUT); }

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

void fade(int i){    for(brightness=0; brightness <= 255; brightness+=fadeAmount){     analogWrite(leds[i], brightness);     delay(10);   }   for(brightness=255; brightness >= 0; brightness-=fadeAmount){     analogWrite(leds[i], brightness);     delay(10);   }      }

А в основном цикле loop() будем вызывать функцию и последовательно передавать ей номер массива. В конце меняем знак переменной delta, чтобы цикл шел в обратном направлении.

void loop() {   for(j=0;j<=3;j+=delta){     fade(j);     if (j < 0 || j >= 3) {delta = -delta;}   } }
ШИМ эффект на светодиоде

Полный текст программы

int brightness = 0;  int fadeAmount = 5;  int leds[] = {3, 6, 9, 11}; int j=0; int delta=1; void setup() {   pinMode(leds[0], OUTPUT);   pinMode(leds[1], OUTPUT);   pinMode(leds[2], OUTPUT);   pinMode(leds[3], OUTPUT); }  void fade(int i){   for(brightness=0; brightness <= 255; brightness+=fadeAmount){     analogWrite(leds[i], brightness);     delay(10);   }   for(brightness=255; brightness >= 0; brightness-=fadeAmount){     analogWrite(leds[i], brightness);     delay(10);   } }  void loop() {   for(j=0;j<=3;j+=delta){     fade(j);     if (j < 0 || j >= 3) {       delta = -delta;     }   } }

Заключение

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

Транзистортестер LCR-T4 Динамик 3W 4R 2″ (53мм) Осциллограф Jinhan JDS2012A Вольтметр + амперметр встраиваемый цифровой 100В 100А Richmeters 101 8-канальный MOSFET модуль Регулируемый блок питания DPS5015 0-50В 0-15А

Новинки

Power Delivery триггер 9В / 12В PDC004

 Power Delivery триггер PDC004 на 9 или 12В – модуль, отдающий зарядному устройству или павербанку команду на включение определенного выходного напряжения. Модуль со..

47.00грн

Термовоздушная паяльная станция (паяльный фен) 858A

 Простая, компактная и недорогая воздушная паяльная станция (паяльный фен) 858A с аналоговой регулиловкой температуры и скорости воздушного потока. Диапазон рег..

985.00грн

Блок питания 5В 3А Type-C с кнопкой

Сетевой блок питания с выходным напряжением 5В и током 3А. Выходной разъем – Type-C. Может использоваться как блок питания для Raspberry Pi или другой электроники что име..

130.00грн

Безкорпусный импульсный блок питания 5В 0.7А (3.5Вт)

 Безкорпусный импульсный блок питанияAC-DC5V на 5В 700мА (макс. мощность – 3.5 Вт). Может использоваться для питания различной электроники и автоматики малой мощност..

42.00грн

Резистор многооборотный 3590S-2-103L 10 кОм

 Многооборотный (10 оборотов) проволочный резистор (потенциометр) 3590S-2-103L на 10 кОм (kOhm).  Предназначен для плавного и точного изменения сопротивления в пр..

50.00грн

Мембранный насос (12 В 1.5л/мин)

 Мембранный самовсасывающий водяной насос (помпа) модель 365 DC 12V.  Предназначен для подачи и перекачки води в системах опреснения, в работе аквариумов, кофе ма..

100.00грн

OLED I2C / IIC LCD 128×32 0.91″ графический дисплей

 Миниатюрный графический OLED дисплей с разрешением 128×32 пикселей и диагональю 0.91″.   Дисплей выполнен на технологии OLED, благодаря ..

70.00грн

Шпиндель для ЧПУ 300W 12-48В 12000об/мин

 Коллекторный шпиндель постоянного тока мощностью 300Вт. Внешний диаметр – 52мм. Скорость вращения – 12000 оборотов в минуту (при напряжении 48В).  В комплекте идет па..

1 050.00грн

Импульсный блок питания 24В 10.5А (250Вт)

 Импульсный блок питания 24В 10.5А (250Вт) в перфорированном металлическом корпусе. Может использоваться для питания различной электроники и автоматики, мощных ..

420.00грн

Список деталей:  

(4x) Миниатюрная кнопка с фиксацией.

(8x) Резистор 10кОм 0.25Вт.  

(9x) Резистор 20кОм 0.25Вт.

(1x) Потенциометр 50кОм.

(1x) Потенциометр для регулировки громкости для компенсации нелинейности человеческого слуха 10кОм.

(1x) Потенциометр со встроенным выключателем 10кОм.

(1x) Стерео аудио разъем 1/8.

(1x) Керамический дисковый конденсатор 1000пФ 50В.

(1x) Резисторы 4,7кОм 0.25Вт.

(1x) 8 контактная панелька для микросхем.  

(1x) ОУ LM386.

(2x) Электролитический конденсатор 220мкФ 35В(любой от 200 до 300мкФ).

(1x) Arduino Uno REV 3.

(1x) Arduino Proto Shield.

(4x) Белый супер яркий светодиод.

(4x) Резистор 740 Ом 0.25Вт.

(1x) Резистор 300 Ом 0.25Вт.

Дополнительные материалы:

Термоусадка.

Провод №22.

Припой.

Дрель со сверлами.

Термоклей.

Клей

Подготовка Arduino Proto Shield

Arduino Proto Shield – это удобный способ добавления своей схемы к Arduino, но я решил немного его урезать, чтобы он занимал меньше места в корпусе.  Сначала я укоротил выводы при помощи кусачек. Потом я убрал шести контактный разъем. После этого я удалил разъемы с верхней части платы.

Корпус

Я решил использовать лазерный резак для изготовления корпуса.  Я разработал корпус используя AutoCAD, Autodesk 123D Make, и Corel Draw. Все файлы проекта можно скачать внизу статьи. Если у вас нет доступа к лазерному резаку, вы можете сделать все детали корпуса вручную по двумерным чертежам.

На картинке показаны отверстия на передней панели:

(3x) 7мм отверстие для потенциометров усиления, частоты и ШИМ.

(3x) 7мм отверстие для четырех кнопок – синусоидальный, треугольный, прямоугольный и  пилообразный сигналы.

(1x) 10мм отверстие для аудио разъема.

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

Также есть прямоугольное (высота11мм, ширина 12 мм) отверстие для USB-порта Arduino в задней части устройства.

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

Пайка проводов к кнопкам

Припаяйте 10 кОм резистор к одному из выводов каждой кнопки. Припаяйте зеленый провод к месту соединения кнопки и резистора и красный провод к резистору как показано на фото. Черный провод припаяйте к другому контакту кнопки. Все эти соединения надо заизолировать термоусадкой во избежание короткого замыкания.

Установка аудио разъема

Свинтите пластиковый корпус с аудио разъема. Припаяйте красный провод к двум стерео контактам и черный провод к GND как показано на фотографии. Я использовал термоклей для предотвращения короткого замыкания и дополнительной фиксации проводов и пайки. После этого, вставьте гнездо в отверстие в корпусе и закрепите его термоклеем.

Установка кнопок

Снимите с кнопок верхнюю часть и установите их в корпус, зафиксировав термоклеем. После его высыхания, установите верхнюю часть кнопок обратно.

R2R ЦАП на Arduino Shield

Припаяйте восемь резисторов 20кОм на Arduino Proto Shield. Один из выводов каждого резистора должен быть подключен к цифровым контактам Arduino 0-7.

Припаяйте семь  резисторов 10кОм на Arduino Proto Shield так, чтобы они были между выводами ранее припаянных восьми резисторов 20 кОм.

Припаяйте резистор 10кОм на Arduino Proto Shield так, чтобы один вывод резистора 10кОм был присоединён к цифровому контакту 0 Arduino, а другой вывод к GND.

Панелька для микросхем

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

Фильтр нижних частот

В качестве ФНЧ (Фильтр Нижних Частот) выступают резистор и конденсатор, соединенные последовательно. ФНЧ пропускает низкие частоты и подавляет ступеньки на сигнале.

Вот как я рассчитал номиналы компонентов в своем ФНЧ:

Частота среза = 1/(2*pi*R*C)

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

Если я использую резистор 300 Ом, и хочу иметь частоту среза 50 кГц:

50000 = 1/(6.28*300*C)

C = 1.06*10^-8 F

Если немного округлить:

C = 0.01 мкФ

Подключите один вывод резистора 300 Ом к резистору 10 кОм, подключенному к цифровому выводу 7. Подключите конденсатор к другому выводу резистора 300 Ом. Второй вывод конденсатора подключается к GND.

Усилитель

Подключите положительный вывод конденсатора 220мкФ к соединению резистора и конденсатора в ФНЧ. Второй вывод конденсатора 220мкФ подключается к резистору 20 кОм, второй вывод которого подключается к 3 выводу панельки для микросхемы. Резистор 4.7 кОм подключается между 3 и 4 контактами панельки. К 4 выводу панельки подключается GND.

Подключите положительный вывод второго конденсатора 200мкФ к 5 контакту  панельки. Позже, второй его вывод будет к подключен к потенциометру «Усиление». Подключите 6 контакт панельки к Vin, 2 контакт к GND и вставьте микросхему в панельку.

Подключение потенциометра “Усиление”

Громкость или усиление звукового сигнала будет управляться аудио потенциометром 10 кОм с выключателем.  Подключите выход усилителя и GND к потенциометру, как показано на фото. Средний контакт это аудио выход, который будет подключен непосредственно к разъему.

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

Подключение батареи

Подключить черный провод от разъема для батареи к GND Arduino Shield. Один провод от выключателя в потенциометре подключите к красному проводу, а второй провод от выключателя потенциометра к Vin Arduino Shield. Пока не подсоединяйте батарею.

Подключение аудио разъема

Соедините выход усилителя (отрицательный вывод конденсатора подключенного к 5 пятому выводу панельки) с красным проводом присоединенным к аудио разъему раньше. Черный провод подключите к GND Arduino Shield.

Подключение кнопок

Подключите все красные провода от кнопок к 5В и все черные провода к GND Arduino shield. Подключите зеленые провода к аналоговым контактам  0-3 в следующем порядке:

Аналоговый контакт 0 = Прямоугольный

Аналоговый контакт 1 = Треугольный

Аналоговый контакт 2 = Пилообразный

Аналоговый контакт 3 = Синусоидальный

Подключение потенциометров “Частота” и ШИМ

Подключите красный, черный, и зеленый провода к потенциометрам 10кОм и 50кОм, как показано на фотографии. Подключите красный провод к 5В и черный провод к GND Arduino shield. Подключите зеленые провода к аналоговым контактам 4 (ШИМ) и 5 (Частота).

Установка потенциометров

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

Подключение светодиодов

Подсоедините резистор 470 Ом к катоду каждого из четырех светодиодов. Припаяйте черный провод ко второму выводу резистора и красный провод к аноду светодиода. Заизолируйте всё термоусадкой во избежание короткого замыкания. Припаяйте черные провода от всех четырех светодиодов на GND Arduino shield. Припаяйте красные провода  к цифровым контактам 8-11.

Установка светодиодов

Приклейте светодиоды в корпусе так, что каждый из них подсвечивал один символ на передней панели :

Цифровой контакт 8 = Прямоугольный

Цифровой контакт 9 = Треугольный

Цифровой контакт 10 = Пилообразный

Цифровой контакт 11 = Синусоидальный

Черный свето рассеиватель

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

Программа

Прошейте Arduino кодом в файле function_generator.ino. В коде используются прерывания по таймеру на частоте 100 кГц для отправки новых данных в ЦАП. Остальная часть кода следит за состоянием кнопок и потенциометров.  Так как прерывания происходят на высокой частоте, я должен сделать программу обработки прерываний в  ISR(TIMER1_COMPA_vect){} как можно короче. Математические операции с плавающей точкой и с помощью функции sin() занимают слишком много времени. Я рассмотрел с нескольких проектов, и получил это: Для треугольного и пилообразного сигнала я создал переменные sawByte, triByte, sawInc, и triInc. Каждый раз, когда частота меняется, я подсчитываю сумму на которую частота треугольного и пилообразного сигналов должна измениться с частотой 100 кГц:

triInc = 511/period; if (triInc==0){ triInc = 1; } sawInc = 255/period; if (sawInc==0){ sawInc = 1; }

То есть все, что должно быть сделано в прерывании, является простой математикой:

case 1://triangle if((period-t) > t); if (t == 0){ triByte = 0; } else{ triByte += triInc; } } else{ triByte -= triInc; } if (triByte>255){ triByte = 255; } else if (triByte<0){ triByte = 0; } wave = triByte; break; case 2://saw if (t=0){ sawByte=0; } else{ sawByte+=sawInc; } wave = sawByte; break; </pre>

Для синусоидально сигнала, я написал простой скрипт на Python, который выводит 20000 значений  127+127 sin(х) за один полный цикл:

import math for x in range(0, 20000): print str(int(127+127*math.sin(2*math.pi*x*0.00005)),)+str(“,”),

Я сохранил этот массив в памяти Arduino под названием sine20000[] и беру из него значения которые необходимо отправить в ЦАП. Это намного быстрее, чем вычислять значения каждый раз.

Последние штрихи

Подключите shield к Arduino. Подключите 9В батарею к разъему. Закрепите эти элементы внутри корпуса. Убедитесь, что USB-порт Arduino доступен снаружи. После запуска вы должны увидеть светящийся индикатор синусоиды.

Установка задней панели и ручек

Просверлите четыре отверстия на задней панели и закрепите её с помощью винтов. Привинтите ручки на потенциометры.

Тестирование

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

Вы заметите, что прямоугольный сигнал является единственным, который по настоящему регулируется от 1 Гц до 50 кГц. Поскольку частота дискретизации 100 кГц, синусоидальный, треугольный, и пилообразный сигналы становятся немного неузнаваемыми примерно после 25 кГц (4 отсчета за такт-100kHz/25kHz). Пилообразный и треугольный сигналы понижаются примерно 100 Гц, иначе значения triInc и sawInc станут настолько низким, что они округляются до нуля. Синусоидальный сигнал понижается до 1 Гц, но на самом деле  до 5Гц, так как Arduino имеет достаточно памяти только для хранения около 20 тыс. значений.

Скачать файлы к проекту

Оригинал статьи на английском языке (перевод: Александр Касьянов для сайта cxem.net)

image 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 – выход генератора.

Попробуем подключить этот модуль к Ардуино и научиться им управлять. Для начала ознакомимся с его функциональной схемой: image AD9833 состоит из следующих основных частей: два регистра выбора частоты, аккумулятор фазы, два регистра выбора фазы и сумматор смещения фазы (вместе эти компоненты составляют генератор с цифровым управлением – NCO), SIN ROM для преобразования информации о фазе в амплитуду и 10-разрядный цифро-аналоговый преобразователь. Из схемы видно, что данные с интерфейса SPI передаются в управляющий регистр, регистры выбора фазы и частоты. Именно они определяют сигнал на выходе генератора. И программирование генератора сводится к изменению содержимого указанных регистров.

Управляющий регистр

Это 16-разрядный регистр, управляющий работой генератора. Подробное описание его битов приведено ниже в таблице. Схема из даташита также наглядно демонстрирует их назначение: image

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

OPBITEN MODE DIV2 Сигнал на выходе 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 (2π / 212) * PHASEREG соответственно, значение для регистра фазы вычисляется по формуле: PHASEREG = PHASE*212 / 2π

Тестовая программа для AD9833 на Ардуино

Теперь мы можем написать первую программу для AD9833. Схема подключения модуля AD9833 к Ардуино и скетч приведены ниже. image С подключением все просто: общение с модулем происходит по интерфейсу 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 для генерации сигнала синусоидальной, треугольной и прямоугольной форм.

Вот как выглядит выходной сигнал генератора в виртуальном осциллографе:

image
Синусоидальный сигнал (биты MODE и OPBITEN сброшены в 0)
image
Треугольный сигнал (MODE = 1, OPBITEN = 0)
image
Прямоугольный сигнал (OPBITEN = 1, MODE = 0, DIV2 = 1)
image
Прямоугольный сигнал (OPBITEN = 1, MODE = 0, DIV2 = 0)

Обратите внимание: при генерации синусоидальных и треугольных импульсов, когда сигнал снимается с выхода ЦАП, его амплитуда изменяется в диапазоне 38мВ…0,65В. При генерации импульсов прямоугольной формы мы имеем дело с обычным цифровым сигналом с соответствующими уровнями напряжения. Так в последних двух осциллограммах логической единице соответствует напряжение ~4,5В.

Генератор на AD9833 с дисплеем и энкодером

Разобравшись с управлением AD9833 можно приступать к созданию генератора с интерфейсом управления и индикацией. Для этого добавим в нашу схему энкодер вращения и жидкокристаллический дисплей: Ранее я писал о том, как можно сделать меню на Ардуино с энкодером вращения. И сейчас я взял такое меню за основу скетча, добавив в него функционал для работы с AD9833. Скачать скетч можно по ссылке. При включении питания AD9833 настраивается на генерацию синусоидального сигнала частотой 100Гц, соответствующая информация отображается на дисплее. Вращая ручку энкодера можно изменять его частоту, а при нажатии вызывается меню. В меню доступны следующие опции:

  • Установка частоты (можно задать произвольное значение от 1 до 12,5МГц).
  • Установка фазы (0 – 360°).
  • Выбор формы сигнала.
  • Выбор значения, на которое изменяется частота при вращении ручки энкодера.

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

Оцените статью
Рейтинг автора
5
Материал подготовил
Илья Коршунов
Наш эксперт
Написано статей
134
А как считаете Вы?
Напишите в комментариях, что вы думаете – согласны
ли со статьей или есть что добавить?
Добавить комментарий