Цап для ардуино своими руками

Добавил пользователь Евгений Кузнецов
Обновлено: 19.09.2024

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

Для того чтобы отправлять данные в DACC порциями можно использовать PDC, но он отправляет данные без паузы, т.е. ожидает когда очередное полуслово будет принято железом и тут же отправляет следующее. Для вывода звука нам этого недостаточно, т.к. данные должны записываться с конкретной частотой. Здесь нам на помощь приходит один из режимов работы DACC, а именно он умеет использовать TC в качестве триггера. А значит, нам остается настроить на нужную частоту TC и сказать DACC, чтобы он использовал один из каналов TC.

TC настраивается на режим “waveform”. Для этого в регистр Ra записывается значение каунтера, при котором на выходе появляется сигнал, а в регистр Rc значение (в нашем случае Ra + 1), при котором выходной сигнал сбрасывается. Таким образом, мы формируем сигнал заданной частоты, который передаем на вход DACC.

При использовании PDC нужно учитывать, что он не умеет передавать данные из ROM, только из RAM.

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

Этот модуль я использую в другом проекте, там звук я вывожу при получении очередного пакета через USB, так что задача не нагружать процессор была выполнена.
Также можно отправлять звуковые данные с заранее рассчитанной паузой между пакетами, например, если размер пакета 512 полуслов, а частота звука 8 кГц, то пауза между отправкой будет 512 / 8000 = 64 мс.

Было бы неплохо избавиться от копирования данных, если мы точно уверены, что они поступают не из ROM. А еще PDC умеет передавать сразу два пакета, это тоже можно использовать.

Динамически изменяя частоту звука можно сгладить неравномерности в его наполнении. Например, при заполнении буфера на 2/3 его объема чуть-чуть увеличиваем частоту, чтобы он быстрее опустошался.

bossac.exe – утилита из Arduino IDE
Имя COM-порта указывайте свое.
Файл прошивки найдете в каталоге Debug или Release вашего проекта.

В Atmel Studio есть огромное количество примеров для Arduino Due, очень советую их изучить.

MassDuino UNO lC

В уроке расскажу о программировании расширенных функций платы MassDuino UNO LC.

В предыдущем уроке я писал о новой уникальной плате MassDuino UNO LC. Несмотря на низкую цену платы ее функциональные возможности значительно шире по сравнению с аналогами на микроконтроллере ATmega328.

Самое весомее преимущество MassDuino UNO LC - АЦП высокого разрешения (до 16 бит). Это позволяет значительно увеличить точность измерения аналоговых сигналов, отказаться от дополнительных усилителей. У меня есть желание переработать многие предыдущие учебные проекты на эту плату и создать новые.

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

При этом цена платы всего 250 рублей, это меньше чем стоимость даже китайского Arduino UNO R3.

Купить MassDuino UNO LC

Программировать плату так же просто, как и Ардуино на микроконтроллерах ATmega328. Я покажу это на конкретных примерах. Собственно отличия заключаются в управлении дополнительными ресурсами платы. Все программы из предыдущих уроков будут работать на MassDuino UNO LC без каких-либо изменений.

Установка программного обеспечения MassDuino в интегрированную среду Arduino IDE.

Плата MassDuino UNO LC настолько совместима с Arduino UNO, что можно в Arduino IDE задать тип платы UNO и спокойно загружать скетч. Но тогда не будут доступны дополнительные функции MassDuino.

Лучше установим плату, как положено. Тем более это очень простая операция.

  • Загрузите на компьютер пакеты необходимых файлов:
    • для Arduino IDE версий 1.5 – 1.6.5 по этой ссылке;
    • для Arduino IDE версий 1.6.6 и старше по этой ссылке.
    • запустить Arduino IDE;
    • выбрать Инструменты -> Плата;
    • убедиться, что в списке появилась плата MassDuino MD-328D;
    • при необходимости, выбрать ее.

    Установка MassDuino UNO lC

    Все. Установка закончена.

    Работа с аналогово-цифровым преобразователем (АЦП).

    У платы MassDuino UNO LC 8 аналоговых входов. A0-A5 выведены на стандартный разъем, еще 2 (A6 и A7) подключены к дополнительному, разъему.

    Распиновка MassDuino UNO lC

    При каждом измерении разрешающую способность АЦП можно задать 10, 12 и 16 бит. От разрядности АЦП зависит время преобразования. Поэтому надо выбирать компромисс между точностью измерения и временем преобразования.

    Разрешение Число градаций выходного кода Время преобразования
    Заявлено в документации Измерено мной
    10 бит 1024 300 мкс 282 – 289 мкс
    12 бит 4096 768 мкс 747 – 760 мкс
    16 бит 65536 8 мс 7900 мкс

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

    Разрешение Функция
    10 бит analogRead()
    12 бит analogRead_12bits()
    16 бит analogRead_16bits()

    Для 10 разрядного разрешения все как в платах с ATmega328, ничего не поменялось.

    Напряжение источника опорного напряжения (ИОН), а значит и верхняя граница напряжения входного сигнала АЦП, задается функцией analog Reference(). Возможны следующие варианты.

    Напряжение ИОН Функция
    5 В (питание микроконтроллера) analogReference(DEFAULT)
    Внутренний ИОН 2, 56 В analogReference(INTERNAL2V56)
    Напряжение входа AREF analogReference(EXTERNAL)

    Например, при ИОН равном 2,56 В диапазон входного сигнала АЦП составляет 0 … 2,56 В. Если задано максимальное разрешение, то абсолютная разрешающая способность измерителя будет 2,56 / 65536 = 39 мкВ.

    Простейшая программа проверки АЦП выглядит так.

    // простейшая проверка АЦП
    void setup()
    Serial.begin(9600); // последовательный порт, 9600
    analogReference(INTERNAL2V56); // ИОН = 2,56 В
    >

    Она в цикле с периодом 0,5 секунд выводит через монитор последовательного порта код АЦП в десятичном виде.

    Почему-то показывает максимальный код не 65535, а 65520, но измеряет точно.

    Отображать на экране значение измеренного напряжения в вольтах можно так.

    Serial.println(((float)analogRead_16bits(A0)) * 2.56 / 65536. ,5);

    К сожалению, мне не известны метрологические параметры АЦП. Надеюсь, что компания INHAOS опубликует подробное техническое описание микроконтроллера MD-328D.

    Про АЦП мне больше писать нечего.

    Работа с цифро-аналоговым преобразователем (ЦАП).

    У платы MassDuino UNO LC появились 2 цифро-аналоговых преобразователя. Это не ШИМ, которые:

    • требуют применения фильтров низких частот;
    • обладают не высоким быстродействием;
    • имеют не высокую точность.

    Это настоящие ЦАП, точные, быстрые, с источником опорного напряжения. Их можно использовать в качестве управляемого ИОН в прецизионных аналоговых схемах. На них можно формировать образцовое напряжение для компараторов и многое другое.

    Выход первого ЦАП является альтернативной функцией для цифрового вывода 4. Второй подключен к дополнительному выводу PE5.

    Распиновка MassDuino UNO lC

    Разрешающая способность ЦАП 8 разрядов, что соответствует 256 градациям входного кода.

    Опорное напряжение, а значит и диапазон выходного аналогового сигнала может быть 1,25 В или 2, 56 В.

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

    pinMode(DAC0, ANALOG); // для ЦАП 0, вывод 4

    pinMode(DAC1, ANALOG); // для ЦАП 1, вывод PE5

    Задать опорное напряжение можно функциями:

    Опорное напряжение Функция
    1,25 В analogReference(DEFAULT)
    2,56 В analogReference(INTERNAL2V56)

    Теперь можно использовать привычную функцию analogWrite():

    analogWrite(4, 255); // установить максимальное напряжение ЦАП 0

    analogWrite(4, 127); // установить 50% напряжения ЦАП 0

    analogWrite(DAC1, 63); // установить 25% напряжения ЦАП 1

    Я измерил время выполнения analogWrite() для ЦАП. Получилось 6,13 мкс.

    Вот пример программы, устанавливающей постоянные напряжения на выходах ЦАП.

    // проверка ЦАП
    void setup()
    analogReference(INTERNAL2V56); // ИОН = 2,56 В
    pinMode(DAC0, ANALOG); // вывод 4 назначаем как ЦАП0
    pinMode(DAC1, ANALOG); // вывод PE5 назначаем как ЦАП1

    analogWrite(DAC0, 199); // устанавливаем на ЦАП0 2 В
    analogWrite(DAC1, 80); // устанавливаем на ЦАП1 0,8 В
    >

    Это пример реализации генератора линейно изменяющегося напряжения (ГЛИН). Скорость изменения я специально сделал медленную, чтобы можно было отследить вольтметром. Период цикла 25,6 секунд.

    // проверка ЦАП
    byte x=0;
    void setup()
    analogReference(INTERNAL2V56); // ИОН = 2,56 В
    pinMode(DAC0, ANALOG); // вывод 4 назначаем как ЦАП0
    >

    Управление дополнительными цифровыми выводами.

    На плате появились 4 дополнительных дискретных выводов PE0, PE2, PE4 и PE5.

    Распиновка MassDuino UNO lC

    Работа с ними не отличается от управления стандартными выводами.

    Функция pin Mode() задает режим, вход или выход.

    pinMode(E5, OUTPUT); // вывод PE5 в режим выхода

    Для установки состояния используем привычную функцию digitalWrite().

    digitalWrite(E5,HIGH); // PE5 = 1

    digitalWrite(E5,LOW); // PE5 = 0

    Вот простейшая программа для проверки работы вывод PE5.

    // проверка вывода PE5
    void setup()
    pinMode(E5, OUTPUT); // вывод PE5 в режим выхода
    >

    Она каждые 2 секунды инвертирует состояние выхода PE5.

    Для обращения к дополнительным выводам можно использовать либо символьные имена E0-E5, либо привычные номера выводов.

    Вывод Имя Номер вывода (программный)
    PE0 E0 20
    PE2 E2 22
    PE4 E4 24
    PE5 E5 25

    digitalWrite(25,HIGH); // PE5 = 1

    Проект вольтметра высокого разрешения с регистратором на компьютере.

    Для примера я разработаю вольтметр с разрешающей способностью 16 бит. В качестве средства индикации буду использовать компьютер. Просто лень подключать к плате дисплей.

    Диапазон измерения вольтметра будет 0…2,56 В. Опять же лень подключать делитель напряжения. Но если вы внимательно читали предыдущие уроки, то всегда сможете добавить эти компоненты. Сейчас я хочу показать программу вольтметра.

    • измерять значение аналогового входа;
    • усреднять его (делать цифровую фильтрацию);
    • вычислять по коду АЦП напряжение;
    • передавать напряжение через последовательный порт на компьютер.

    Все это мы делали в уроке 13.

    Период измерения я задал 0,5 сек.

    Схема вольтметра это переменный резистор, подключенный средним выводом к входу A0, а крайними выводами к земле и цепи 5 В.

    Вольтметр мы собираемся делать точный. Поэтому попробуем компенсировать наводки сети частотой 50 Гц. Для этого сделаем несколько выборок АЦП и усредним результат.

    Единственный не понятный вопрос период выборок. В режиме 16 битного преобразования АЦП MassDuino производит измерение за 8 мс. Нам надо усреднить так, чтобы выборки равномерно распределились по интервалу периода сети 20 мс. В этом случае будет максимальное подавления наводок сети 50 Гц. Когда быстродействие АЦП было 100 мкс, это труда не вызывало.

    Если выбрать время одной выборки, например, 10 мс, то все выборки будут попадать в одну и ту же временную точку синусоиды сети. 10 мс - время кратное периоду сети. Можете подумать, на эту тему, посчитать. Я эмпирически выбрал период выборок АЦП 10,204 мс. Период измерения 500 мс я разделил не на 50 выборок, а на 49. Получилось 49 выборок АЦП на период измерения 500 мс. Может быть, я и не прав. Возможно, есть лучшее, с точки зрения подавления наводок сети, значение периода выборок.

    Вот скетч программы.

    byte sampleCount=0; // счетчик выборок
    unsigned long sumA0=0; // переменные для суммирования кодов АЦП
    unsigned long averageA0=0; // сумма кодов АЦП
    boolean flagReady=false; // признак готовности данных измерения

    void setup()
    Serial.begin(9600); // инициализируем порт, скорость 9600
    Timer1.initialize(10204); // инициализация таймера 1, период 10,2 мс
    Timer1.attachInterrupt(timerInterrupt, 10204); // задаем обработчик прерываний
    analogReference(INTERNAL2V56); // ИОН = 2,56 В
    >

    void loop()
    if ( flagReady == true )
    flagReady= false;
    // пересчет в напряжение и передача на компьютер
    Serial.println((float)(averageA0 / SAMPLE_NUMBER) * 2.56 / 65536., 5);
    >
    >

    // -------------------------------------- обработчик прерывания 10,2 мс
    void timerInterrupt()
    sampleCount++; // +1 счетчик выборок усреднения
    sumA0+= analogRead_16bits(A0); // суммирование кодов АЦП

    // проверка числа выборок усреднения
    if ( sampleCount >= SAMPLE_NUMBER )
    sampleCount= 0;
    averageA0= sumA0; // перегрузка среднего значения
    sumA0= 0;
    flagReady= true; // признак результат измерений готов
    >
    >

    Скетч можно загрузить по ссылке:

    Зарегистрируйтесь и оплатите. Всего 60 руб. в месяц за доступ ко всем ресурсам сайта!

    Я не знаю, что здесь объяснять. Все это уже “разжевано” в уроке 13. Там же написано, как подключить резисторный делитель для увеличения диапазона входного напряжения.

    Запустил монитор последовательного порта. Проверил, все работает.

    Результаты измерения

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

    Окно программы Вольтметр

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

    Окно регистратора вольтметра

    Эту диаграмму я как художник-абстракционист рисовал ручкой переменного резистора.

    Программу верхнего уровня можно загрузить по ссылке:

    Зарегистрируйтесь и оплатите. Всего 60 руб. в месяц за доступ ко всем ресурсам сайта!

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

    Попытаюсь в следующем уроке вернуться к протоколу ModBus, но уверенности в этом уже нет.

    Модуль собран на микросхеме PCF8591, это 8 битный четырех канальный ЦАП и АЦП в одном корпусе.

    Описание модуля:

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

    Модуль имеет интерфейс I2C и подключается как и любое другое устройство с I2C, достаточно соединить выходы SDA и SCL и дать питание 5 вольт на модуль.


    На примере Arduino Leonardo и модуля RTC, PCF8591 подключается аналогичным образом

    Возможно для PCF8591 написаны библиотеки, но общение с микросхемой очень простое и можно обойтись двумя функциями, одной для чтения значения с АЦП, и второй для записи значения в ЦАП.

    Как он работает, можно посмотреть в видео.

    Видео:

    Мы прошли два предыдущих шага, научившись проигрывать мелодию с помощью ШИМ-а и SD/MMC карточки. Теперь настала пора качеству!

    Первое, что нужно сделать — обзавестись SPI ЦАП-ом. Почему SPI? — у Arduino крайне мало портов для ЦАП-а с параллельным интерфейсом, да и рациональнее использовать последовательный. Самый дешевый (и единственный доступный): MCP4921. либо другой совместимый.


    12Bit, ну почти 16 :); Rail-to-Rail; и стоит копеечку.

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

    Схема для частоты дискретизации ~22KHz: R2 и C2 — фильтр несущей частоты.

    Схема для частоты дискретизации >>22KHz: Здесь фильтр вообще не нужен.

    Также не следует забывать, что в общую цепь питания ЦАП нужно поставить конденсатор(ы) емкостью 0.1uF.

    Если вы питаете ЦАП от 3.3v, то Arduino нужно также запитать от этого источника, либо использовать конвертер уровней!

    Протокол у ЦАП-а прост как дважды два. CS и LDAC — можно и вовсе прижать к земле.


    Биты данных

    Что весьма интересно: такой же ЦАП стоит в Arduino Wave Shield, поэтому можно не изобретать велосипед снова, а использовать их библиотеку WaveHC, которая вполне подойдет для наших целей. Но прежде необходимо подключить к Arduino SD/MMC карту, если вы еще это не сделали. Желательно, чтобы провод от SD/MMC был коротким и защищен от помех.


    Далее, поменяем конфигурационный файл библиотеки:

    Теперь мы можем воспроизводить .wav файлы формата: PCM 16-bit MONO 44KHz(а может и больше) .

    Загрузим тестовый скетч:

    Читайте также: