Освой Arduino играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Аналоговые выводы

Вольтметр
01.Basics: AnalogReadSerial
Serial Plotter
01.Basics: ReadAnalogVoltage
Светодиод с плавной регулировкой
03.Analog: AnalogInput
03.Analog: AnalogInOutSerial
03.Analog: Smoothing
05.Control: IfStatementConditional

На плате UNO есть шесть выводов, которые подписаны от A0 до A5 (у других плат может быть другое число выводов). Они работают с напряжением от 0 до 5V. Благодаря встроенному АЦП (аналого-цифровой преобразователь), данные входы могут считывать напряжение подаваемое на них. Микроконтроллеры Atmega328, используемые в Arduino UNO, содержат шестиканальный АЦП, разрешение которого составляет 10 бит. Это позволяет на выходе получать значения от 0 до 1023 (всего 1024 градации).

Для чтения показания напряжения есть встроенный метод analogRead(), возвращающий значение от 0 до 1023. Значение 0 относится к 0V, а 1023 к 5V. Таким образом, если мы хотим конвертировать значение от 0 до 5, то нужно произвести деление 1023/5 = 204.6

Имеется также функция analogReference(type)​. Она задаёт опорное напряжение, относительно которого происходят аналоговые измерения. В проектах для новичков она не используется, поэтому не будем обращать на неё внимания.

Кроме того, аналоговые выходы могут работать как цифровые и обозначаются как 14, 15, 16, 17, 18, 19 вместо A0..A5.

И, наоборот, цифровые порты с символом тильды ~ (3, 5, 6, 9, 10, 11) могут работать как аналоговые выходы, используя ШИМ.

Аналоговые выводы, в отличие от цифровых, не нужно объявлять как вход или выход в начале программы.

Изучим простой пример с одним проводом и аналоговым выводом. Соединим проводом порты A0 и 3.3V. Напишем скетч.


int analogPin = A0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  int rawReading = analogRead(analogPin);
  float volts = rawReading / 204.6;
  Serial.println(volts);
  delay(1000);
}

Откройте окно Serial Monitor и наблюдайте за показаниями. Должны выводиться числа, близкие к значению 3.3: 3.1, 3.2, 3.3. Если, не закрывая программу, вытащить конец провода из порта 3.3V и вставить в порт 5V, то показания изменятся, а на экране появятся числа 5.0. Если перекинуть конец провода на GND, то увидим значения 0.

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

Вольтметр

Если мы можем снимать значения из аналоговых портов, то можем использовать микроконтроллер как вольтметр. Достаточно вставить провода в выводы GND и A0 и соединить их с контактами на батарее (минус и плюс соответственно). Вообще такой способ не является суперточным. Хотя он и показывал правдоподобные результаты на пальчиковой батарее 1.5 В и "Кроне" на 9 В, но также показывал результаты, когда провода вообще ни к чему не были присоединены. Но для общего развития оставлю.


/*
  The simplest voltmeter
*/
const int analogIn = A0;

int raw = 0;
float voltage = 0;

void setup() {
  pinMode(analogIn, INPUT);
  Serial.begin(9600);
}

void loop() {
  raw = analogRead(analogIn);
  voltage = (raw * 5.0 ) / 1024.0;
  Serial.print("Raw Value = " );
  Serial.print(raw);
  Serial.print("\t Voltage = ");
  Serial.println(voltage, 3); // 3 цифры после запятой
  delay(500);
}

01.Basics | AnalogReadSerial (Чтение аналоговых выводов через потенциометр)

С помощью потенциометра мы можем менять напряжение и считывать данные с выводов.

Продолжим изучение работы с аналоговыми выводами через пример AnalogReadSerial из меню File | Examples | 01.Basics. Цель урока - плавно изменять напряжение и подавать его на аналоговый вывод, чтобы получить с него текущее значение напряжения.

Нам понадобятся плата Arduino, потенциометр и несколько проводов (или перемычек). Соединяем парные ножки с выводами на плате 5V и GND. Среднюю ножку необходимо соединить с аналоговым выводом на плате, помеченную как A0.

Макет

Не важно, какая из крайних ножек потенциометра будет подключена к 5V, а какая к GND, поменяется только направление, в котором нужно крутить ручку для изменения напряжения. Сам сигнал считывается со средней ножки, которая связана с аналоговым портом. Для считывания аналогового сигнала, принимающего широкий спектр значений, а не просто 0 или 1, подходят только порты, помеченные на плате как ANALOG IN. Они все пронумерованы с префиксом A (A0-A5).

Схема готова. Вращая регулятором потенциометра, мы можем менять сопротивление от 5 Вольт до 0. Arduino позволяет считывать текущее напряжение, которое подаётся на среднюю ножку при помощи аналогового вывода. Результаты могут колебаться от 0 до 1023.

Код


void setup() {
  // инициализируем соединение на скорости 9600 бит в секунду:
  Serial.begin(9600);
}

void loop() {
  // Считываем данные с аналогового вывода A0
  int sensorValue = analogRead(A0);  // получаем текущее значение
  Serial.println(sensorValue); // выводим результат на монитор
  delay(1);        // небольшая задержка для стабильности вывода результатов
}

Код очень простой. При инициализации устанавливаем нужную скорость связи: Serial.begin(9600);. Далее в цикле мы постоянно считываем данные, поступающие с потенциометра при помощи метода analogRead(). Так как значения будут находиться в диапазоне от 0 до 1023, мы можем использовать тип int для переменной sensorValue.

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

Проверка (Serial Monitor)

Запустите программу, а также откройте окно последовательного монитора. Вращая регулятором потенциометра, вы можете наблюдать, как в окне будут меняться значения от 0 до 1023.

Пример интересен своей универсальностью. Потенциометр является ручным делителем напряжения. Существуют другие детали, которые выполняют такую же работу. Например, фоторезистор меняет напряжение в зависимости от освещённости. Также напряжение может меняться от нажатия, от температуры и т.д. При этом нам не нужно менять программу, просто одну деталь меняем на другую и код будет выполняться. Единственное различие будет в выводимых результатах - каждый делитель напряжения имеет свои характеристики и, соответственно, будет давать свои показания.

Проверка (Serial Plotter)

Начиная с версии Arduino IDE 1.6.6, в настройках появился новый инструмент Plotter (Tools | Serial Plotter), позволяющий выводить простенький график. Обратите внимание, что он не может работать одновременно с последовательным монитором, который следует закрыть.

Вращая ручку потенциометра, можем наблюдать изменение графика.

Serial Plotter

01.Basics | ReadAnalogVoltage (Напряжение аналоговых выводов через потенциометр)

Рассмотрим урок ReadAnalogVoltage из меню File | Examples | 01.Basics. Он практически идентичен примеру AnalogReadSerial, только мы будем конвертировать значения от аналогового вывода (0...1023) в значения напряжения (0...5). Для примера нам понадобится потенциометр. Цель урока - плавно изменять напряжение и подавать его на аналоговый вывод, чтобы получить текущее значение напряжения.

Схема прежняя, ничего не меняем. Соединяем парные ножки с выводами на плате 5V и GND. Среднюю ножку необходимо соединить с аналоговым выводом на плате, помеченную как A0.

Макет

Схема готова. Вращая регулятором потенциометра, мы можем менять сопротивление от 5 Вольт до 0. Arduino позволяет считывать текущее напряжение, которое подаётся на среднюю ножку при помощи аналогового вывода. Результаты могут колебаться от 0 до 1023.

Код


void setup() {
  Serial.begin(9600);
}

void loop() {
  // читаем данные с вывода A0:
  int sensorValue = analogRead(A0);
  // Конвертируем данные от 0 до 1023) в значения напряжения (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // Выводим результат
  Serial.println(voltage);
}

Если сравнить два примера, то разница в одной строке float voltage = sensorValue * (5.0 / 1023.0);. В цикле считываем данные, поступающие с потенциометра при помощи метода analogRead(). Так как значения будут находиться в диапазоне от 0 до 1023, мы можем использовать тип int для переменной sensorValue. Используем элементарную математику и делим результат на коэффициент.

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

Запустите программу, а также откройте окно последовательного монитора. Вращая регулятором потенциометра, вы можете наблюдать, как в окне будут меняться значения от 0.00 до 5.00.

Светодиод с плавной регулировкой

Усложним конструкцию, добавив светодиод. Первую часть схему можно было не трогать. Но для экономии в предыдущем примере я соединил ножку потенциометра сразу с портом GND. На этот раз сделаем соединение из двух проводов. Это необходимо, чтобы светодиод тоже мог соединиться с заземлением. Поэтому финальный макет будет следующим.

Макет

Принципиальная схема.

Принципиальная схема

Напишем код.


int potPin = A0;
int ledPin = 9;

void setup() {
  // порт для светодиода на выход
  pinMode(ledPin, OUTPUT);
 
  // пин с потенциометром - вход
  // мы хотим считывать напряжение,
  // выдаваемое им
  pinMode(potPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  // значение напряжения с потенциометра
  int rotation;
  // значение яркости
  int brightness;  
 
  // считываем напряжение с потенциометра от 0 до 1023
  // пропорциональное углу поворота ручки
  rotation = analogRead(potPin);
 
  // в brightness записываем полученное ранее значение rotation
  // делённое на 4. Дробная часть от деления будет отброшена.
  // В итоге мы получим целое число от 0 до 255
  brightness = rotation / 4;
 
  // выдаём результат на светодиод
  analogWrite(ledPin, brightness);

  // выводим результат в Serial Monitor
  Serial.println(brightness);
  delay(1); // задержка для стабильности
}

Практически все инструкции вам знакомы. Тут нужно уяснить момент, что яркость светодиода управляется нашим кодом, а не подачей напряжения через потенциометр. Мы считываем показания потенциометра, как в первом варианте и переводим получаемые значения в диапазон от 0 до 255. Затем воспроизводим старый пример с плавной регулировкой светодиода и подаём ему нужные значения. Теперь при вращении ручки потенциометра мы одновременно управляем степенью накала светодиода. Напомню, что светодиод следует подключить к портам с тильдой, например, ~9

03.Analog: AnalogInput

Небольшая модификация примера с миганием светодиода. Частота мигания будет зависеть от показаний потенциометра. Можно использовать встроенный светодиод или установить свой. Общая схема остаётся как у первого примера.


int sensorPin = A0;    // аналоговый вывод A0 для потенциометра
int ledPin = 13;      // вывод для светодиода
int sensorValue = 0;  // значение, поступаемое от потенциометра

void setup() {
  // устанавливаем режим для светодиода
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // считываем показание с потенциометра
  sensorValue = analogRead(sensorPin);
  // включаем светодиод
  digitalWrite(ledPin, HIGH);
  // делаем задержку на значение от потенциометра в мсек
  delay(sensorValue);
  // выключаем светодиод
  digitalWrite(ledPin, LOW);
  // делаем задержку на значение от потенциометра в мсек
  delay(sensorValue);
}

Получая показания от потенциометра в интервале 0-1023 мы регулируем задержку между миганием светодиода в интервале от 0 до 1.023 секунд.

03.Analog: AnalogInOutSerial

Считываем данные с потенциометра и распределяем их в интервале от 0 до 255 с помощью функции map(). Данный интервал удобно использовать для выводов с PWM (ШИМ). Применим получаемые значения для управления яркостью светодиода, а также будем выводить информацию в Serial Monitor.

Analog


const int analogInPin = A0;  // потенциометр к A0
const int analogOutPin = 9; // светодиод на выводе 9

int sensorValue = 0;        // значения от потенциометра
int outputValue = 0;        // значения для PWM

void setup() {
  Serial.begin(9600);
}

void loop() {
  // считываем данные из потенциометра
  sensorValue = analogRead(analogInPin);
  // распределяем данные из интервала 0-1023 в интервал 0-255
  outputValue = map(sensorValue, 0, 1023, 0, 255);
  // подаём сигнал на светодиод:
  analogWrite(analogOutPin, outputValue);

  // печатаем результаты в Serial Monitor
  Serial.print("sensor = ");
  Serial.print(sensorValue);
  Serial.print("\t output = ");
  Serial.println(outputValue);

  // ждём 2 миллисекунды
  delay(2);
}

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

Analog

03.Analog: Smoothing

Если показания аналогового датчика "прыгают", то имеет смысл вычислить среднее значение за определённый промежуток времени и результат выдавать на экран. Таким образом мы получим более плавные значения.

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

Схема обычная, берём из примеров выше.

Потенциометр


// число показаний для получения среднего значения (подбирается индивидуально)
const int numReadings = 10;

int readings[numReadings];      // массив данных от аналогового вывода
int readIndex = 0;              // текущий индекс
int total = 0;                  // общее значение
int average = 0;                // среднее значение

int inputPin = A0; // Аналоговый вывод А0

void setup() {
  Serial.begin(9600);
  // заполняем массив из 10 элементов нулями
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}

void loop() {
  // вычитаем значение
  total = total - readings[readIndex];
  // считываем с датчика
  readings[readIndex] = analogRead(inputPin);
  // добавляем полученное значение
  total = total + readings[readIndex];
  // переходим на следующую позицию в массиве
  readIndex = readIndex + 1;

  // если достигли конца массива...
  if (readIndex >= numReadings) {
    // ...возвращаемся в начало:
    readIndex = 0;
  }

  // подсчитываем среднее значение
  average = total / numReadings;
  // посылаем данные на компьютер
  Serial.println(average);
  delay(1);        // небольшая задержка для стабильности
}

05.Control: IfStatementConditional

В примере File | Examples | 05.Control | IfStatementConditional рассматривается случай, когда показания достигают определённой величины. При достижении заданного порога включается светодиод. Урок знакомит новичка с оператором условия if (Если).

Схема без изменений (см. рисунки выше). Среднюю ножку потенциометра соединяем с аналоговым выводом A0, остальные две ножки соединяем с питанием 5В и землёй. При желании установите внешний светодиод на цифровой вывод 13 (можно обойтись встроенным светодиодом).


const int analogPin = A0;    // аналоговый вывод для потенциометра
const int ledPin = 13;       // цифровой вывод для светодиода
const int threshold = 400;   // произвольный порог для показаний потенциометра

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // считываем данные с потенциометра
  int analogValue = analogRead(analogPin);

  // Если показания выше чем заданный порог, то включаем светодиод
  if (analogValue > threshold) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW); // иначе держим светодиод выключенным
  }

  // выводим показания на Serial monitor
  Serial.println(analogValue);
  delay(1);        // задержка для стабильности
}

Другие примеры

07.Display: barGraph (Световая шкала и потенциометр)

04.Communication: Graph (Рисуем график в Processing)

Реклама