Урок 54. Специфика программирования платы MassDuino UNO LC. Установка программного обеспечения, программирование АЦП, ЦАП, дополнительных цифровых выводов.

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.
  • Распакуйте загруженный архив и скопируйте файлы из папок libraries и hardware в одноименные папки Arduino IDE. У меня они находятся в d:\Arduino\libraries и d:\Arduino\ hardware.
  • Теперь можно:
    • запустить 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 В
}

void loop() {
  Serial.println(analogRead_16bits(A0));
  delay(500);
}

Она в цикле с периодом 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 В
}

void loop() {
}

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

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

void loop() {
  analogWrite(DAC0, x); // загружаем код ЦАП
  x++;
  delay(100);
}

 

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

На плате появились 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 в режим выхода
}

void loop() {
  digitalWrite(E5,HIGH); // PE5 = 1
  delay(2000);
  digitalWrite(E5,LOW); // PE5 = 0
  delay(2000);
}

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

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

// программа вольтметра на MassDuino
#include <TimerOne.h>

#define SAMPLE_NUMBER 49 // число выборок

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; // признак результат измерений готов
  }
}

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

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

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

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

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

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

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

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

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

Программу верхнего уровня можно загрузить по этой ссылке Voltmeter.zip.

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

 

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

Предыдущий урок     Список уроков     Следующий урок

11 комментариев на «Урок 54. Специфика программирования платы MassDuino UNO LC. Установка программного обеспечения, программирование АЦП, ЦАП, дополнительных цифровых выводов.»

  1. здравствуйте, Эдуард
    не могу отправить Вам сообщение через форму обратной связи. Написал в личку администратору форума. Проверьте, пожалуйста

  2. здравствуйте, Эдуард. Случайно стер бутлоадер массдуино . Восстановить не знаю как. ISP-программирование на этом чипе не существует.О чем с извинениями сообщил производитель. Есть SWD но как к нему подобраться-вопрос.Нет ли у вас подобного опыта?

  3. А измерять термопару без ОУ можно 16 битным АЦП? Какая будет точность? Или всё равно ОУ нужен?! Хотелось бы взглянуть как АЦП справляется с термопарой без ОУ!))

    • Считать надо для конкретного АЦП и термопары. Абсолютная разрешающая способность АЦП при ИОН= 2,56 В 39 мкВ. Для термопары ТХА термоэдс примерно 40 мкВ на градус (при 100 градусах). Разрешающая способность примерно соответствует.

  4. Как оцифровать переменное напряжение (т.е.измерять и отрицательное и положительное напряж.)? Возможно меньшей дополн обвязкой?

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

  5. Приветствую, Эдуард.
    Подскажите, где взять библиотеку / модуль «TimerOne.h», использующийся в примере вольтметра.
    Попытался найти в ваших уроках — не смог, видимо, слаб глазами стал. 🙂
    Заранее спасибо.

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

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