Top.Mail.Ru

Как подключить потенциометр к Ардуино. Аналоговые входы.

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

Теоретическая часть.

Введение.

Для начала освежим в памяти ключевой нюанс использования цифровых пинов. Он прост и незатейлив - уровень сигнала на цифровом выводе может принимать два разных значения - высокий уровень (5 В), либо низкий (0 В). Опять же, я в рамках курса по Arduino использую Arduino Uno, микроконтроллер (ATmega328) на которой питается от 5 В. В случае другой платы и другого контроллера, например Arduino Due (SAM3X8E), которая использует 3.3 В, цифровые пины, а также все остальные модули, оперируют уже с этими значениями (а не с 5 В, как все та же Arduino Uno). Я же дальше буду все описывать для Uno ввиду ее распространенности и популярности, так что не забывайте об этих деталях, если у вас другая плата.

На этом лирическое отступление закончено, двигаемся дальше. Аналоговые входы, в отличие от цифровых, могут работать с аналоговыми же сигналами, величина которых может принимать любое значение от 0 до 5 В. Давайте разбавим текст небольшой наглядной иллюстрацией:

Аналоговые и цифровые сигналы.

Для цифрового входа у нас было два варианта:

Состояние входа Напряжение
Логический 0 от -0.5 В до 1.5 В (0.3 * Vcc)
Логическая 1 от 3.0 В (0.6 * Vcc) до 5.5 В (Vcc + 0.5 В)

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

Опорное напряжение АЦП Arduino.

Микроконтроллер может измерить напряжение от 0 Вольт до значения опорного напряжения, для которого возможен целый ряд вариантов:

  • DEFAULT - дефолтный вариант, опорное напряжение равно напряжению питания микроконтроллера
  • INTERNAL - внутренний источник напряжения, 1.1 В - для ATmega168 и ATmega328P, 2.56 В - для ATmega32U4 и ATmega8 (не доступно для Arduino Mega)
  • INTERNAL2V56 - внутренний источник на 2.56 В (только для Arduino Mega)
  • INTERNAL1V1 - внутренний источник на 1.1 В (только для Arduino Mega)
  • EXTERNAL - внешнее опорное напряжение, поданное на вход AREF (от 0 до 5 В)

По умолчанию в качестве опорного используется напряжение питания, то есть все те же 5 Вольт для Arduino Uno и большинства плат из линейки Ардуино. Далее следует ряд внутренних источников опорного напряжения, доступных для той или иной платы. Они отличаются непосредственно значением напряжения.

Тут может возникнуть логичный вопрос - зачем использовать, к примеру, источник на 1.1 В, который позволит измерить аналоговое напряжение от 0 до 1.1 В, если можно просто использовать напряжение питания и измерять от 0 до 5 В. То есть в чем смысл ограничивать себе же допустимый диапазон? Этот нюанс мы разберем чуть позже, буквально в следующем разделе.

А список вариантов завершает внешний источник опорного напряжения, который подключается к выводу AREF платы, для Arduino Uno:

Arduino Uno AREF.

Сами же аналоговые входы Arduino промаркированы буквой A, Uno на своем борту имеет 6 таких входов, соответственно, вот они все здесь (A0 - A5):

Аналоговые входы Arduino Uno.

С этим разобрались, на очереди следующий пункт.

Разрядность АЦП и расчет напряжений.

Модуль АЦП в микроконтроллерах AVR является 10-ти битным (для большинства Arduino-совместимых плат, для некоторых же есть возможность использовать разрешение в 12 бит), то есть результат измерения может принимать значения от 0 до 1023. Число 1023 в двоичной системе представляет из себя следующий набор из единиц: 1111111111. Как видите, здесь их ровно 10 штук, то есть 10 битов, поэтому 1023 и является максимально возможным вариантом в данном случае. Вот некоторые из возможных результатов с АЦП и соответствующие им напряжения в Вольтах:

Измеренное значение Напряжение
0 0 В
205 1 В
614 3 В
1023 5 В

Резюмируя, отметим следующий факт (здесь подразумеваем, что в качестве опорного напряжения используется напряжение питания): мы можем измерить напряжение от 0 до 5 В, при этом данному диапазону соответствуют числа от 0 до 1023, то есть 1024 разных значения. Таким образом, из полученного с АЦП 10-битного значения можно рассчитать величину напряжения на аналоговом входе в Вольтах:

U = \frac{ ADC_{res} \cdot 5 \medspace В}{1024}

Здесь ADC_{res} - результат аналого-цифрового преобразования, U - искомое напряжение в Вольтах.

Вот так все просто и незатейливо, но в то же время четко и логично 👍 И на этой мажорной ноте мы возвращаемся к вопросу о значении опорного напряжения, поднятому в предыдущем разделе. Зачем уменьшать допустимый диапазон измерений, уменьшая опорное напряжение? Смотрите, сейчас все разберем в деталях.

Итак, пусть опорное напряжение по-прежнему равно 5 В. Величина, полученная в ходе измерений, может принимать 1024 разных значения (0, 1, 2 ... 1023). А это значит, что точность измерения составит:

\frac {5 \medspace В}{1024} = 0.0049 \medspace В

Действительно, если мы получили значение 120, то оно соответствует напряжению:

U = \frac{ 120 \cdot 5 \medspace В}{1024} = 0.5859 \medspace В

Соседние же значения дают:

  • значение 119 - напряжение 0.5810 В
  • значение 121 - напряжение 0.5908 В

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

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

\frac {1.1 \medspace В}{1024} = 0.0011 \medspace В

Те же самые 1024 возможных значения теперь соответствуют диапазону от 0 до 1.1 В, что автоматически приводит к повышению точности. Вот в этом то и кроется смысл использования разных источников опорного напряжения. Если мы знаем, что нам нужно измерять сигналы из интервала (0 В; 1 В), то есть смысл использовать меньшее значение опорного, во имя повышения точности результата. Все снова логично до безобразия, так что перемещаемся к следующему разделу.

Делитель напряжения.

Здесь мы разберем потенциальную и вполне себе реальную ситуацию - пусть нам требуется измерить напряжение, которое заведомо может превышать опорное. Физически на аналоговый вход не рекомендуется, более того, воспрещается, подавать сигнал более 5.5 В (для Arduino Uno). Это просто-напросто может вывести микроконтроллер из строя.

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

Делитель напряжения.

Про делитель напряжения в целом написано около миллиарда статей, поэтому дублировать не буду, а сейчас рассмотрим конкретный пример расчета. Приведу финальную формулу для напряжения в точке 1:

U_1 = \frac{U_2 \cdot R_1}{R_1 + R_2}

По условию нашей выдуманной задачи измеряемый сигнал (U_2 \medspace) может принимать максимальное значение равное 12 В. В качестве опорного напряжения - 5 В, то есть максимальное напряжение на аналоговом входе (U_1 \medspace) составляет столько же, 5 В. Кстати, технически мы можем подать сигнал от 5 до 5.5 В, что допустимо для данного контроллера. Но практической ценности в этом минимум - любое значение, превышающее опорное напряжение, даст результат равный 1023.

Возвращаемся к примеру: из всего вышесказанного следует простой факт, что 12 Вольтам в точке 2 должны соответствовать 5 Вольт в точке 1. Исходя из этих простых сведений производим расчет делителя напряжения, то есть номиналов резисторов. Ток, потребляемый аналоговым входом Ардуино очень мал, поэтому его значением пренебрегаем. В итоге получаем, что по цепи точка 2 - точка 1 - GND течет один и тот же ток:

Расчет делителя напряжения для Arduino.

И рассчитать его можно следующим образом (в точке GND напряжение равно 0 В):

I = \frac{U_1 - 0}{R_1} = \frac{U_2 - U_1}{R_2}

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

U_2 = 12 \medspace В \\
U_1 = 5 \medspace В

Подставив значения в предыдущую формулу получим соотношение:

\frac{R_2}{R_1} = \frac{U_2 - U1}{U_1} = \frac{7}{5} = 1.4

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

I = \frac{U}{R}

В нашем же случае ограничим себя "средними" величинами от 0 до 10-20 КОм. То есть сумма R_1 + R_2 пусть будет в районе этих самых 10-20 КОм. Остается подобрать величины исходя из ряда номиналов, чтобы их отношение было максимально близко к 1.4. Выбираем:

R_2 = 5.1 \medspace КОм \\
R_1 = 3.6 \medspace КОм

Тогда при напряжении в точке 2, равном 12 В, в точке 1 получим:

U_1 = \frac{U_2 \cdot R_1}{R_1 + R_2} = \frac{12 \cdot 3.6}{3.6 + 5.1} = 4.96 \medspace В

То есть мы заведомо не превысим ограничение в 5 В на аналоговом входе Ардуино, что нас полностью устраивает. Получаем итоговую принципиальную схему:

Измерение напряжения на Ардуино.

И вот теперь уже самое время продвинуться к практической части!

Практическая часть.

Функции для работы с аналоговыми входами Arduino.

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

analogReference(refType);

У функции один аргумент, его значения для Arduino Uno могут быть такими:

  • DEFAULT
  • INTERNAL
  • EXTERNAL

По умолчанию активен вариант DEFAULT, пример кода для внутреннего источника на 1.1 В:

analogReference(INTERNAL);

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

analogRead(pin);

Аргументом является просто номер интересующего нас пина, причем тут есть несколько вариантов, возьмем для примера аналоговых вход A1. Тогда мы можем передать в функцию:

  • непосредственно A1: analogRead(A1);
  • порядковый номер аналогового пина, в данном случае это 1: analogRead(1);
  • порядковый номер пина, A0 - 14, A1 - 15 и так далее по возрастанию: analogRead(15);

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

Пример 1. Подключение потенциометра к Arduino.

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

Потенциометр Ардуино.

Как работает потенциометр в целом уже разбирали, так что имеем схему следующего вида:

Подключение потенциометра к Ардуино.

По сути имеем делитель напряжения с возможностью менять соотношение сопротивлений. Реализация на макетной плате также присутствует:

Макетная плата.

То есть для подключения потенциометра необходимо использовать 3 вывода:

  • 5V
  • A1 (либо другой аналоговый вход)
  • GND

Задачу себе поставим такую - измерить напряжение с потенциометра (которое будет от 0 до 5 В ввиду его подключения к GND и 5V) и вывести это значение в Serial Monitor, он же "Монитор порта". Получаем скетч:

// Аналоговый вход, напряжение на котором будем анализировать
int analogPin = A1;

// Сюда будем сохранять результат с АЦП
int adcResult = 0;



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



void loop() 
{
  // Собственно, считываем требуемое значение
  adcResult = analogRead(analogPin);

  // И выводим результат
  Serial.println(adcResult);

  // Задержка для повышения наглядности
  delay(100);
}

Я снабдил его комментариями, тем не менее в случае возникновения вопросов, смело задавайте их любым из доступных способов:

Вопросы категорически приветствуются 👍

Компилируем скетч и прошиваем, в Serial Monitor'е наблюдаем бегущие значения, которые меняются в соответствии с положением ручки потенциометра от 0 до 1023 в крайних положениях. Что в точности совпадает с той теорией, которую мы обсудили:

Результат работы скетча.

Здесь я добавил задержку delay(100) для того, чтобы значения не молотили с бешеной скоростью, а давали возможность спокойно за собой понаблюдать.

Пример 2. Расчет напряжения с потенциометра на аналоговом входе Ардуино.

Модернизируем пример для того, чтобы увидеть значения в Вольтах, для этого произведем пересчет:

U = \frac{ ADC_{res} \cdot 5 \medspace В}{1024}
// Аналоговый вход, напряжение на котором будем анализировать
int analogPin = A1;

// Сюда будем сохранять результат с АЦП
int adcResult = 0;

// Напряжение в Вольтах
float voltage = 0;



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



void loop() 
{
  // Собственно, считываем требуемое значение
  adcResult = analogRead(analogPin);

  // Пересчитываем в Вольты
  voltage = (float)adcResult * 5 / 1024;

  // И выводим результат
  Serial.println("Voltage: " + String(voltage));

  // Задержка для повышения наглядности
  delay(100);
}

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

Напряжение с потенциометра, Ардуино.

Аналогично можно использовать еще один инструмент Arduino IDE под названием "Serial Plotter": Tools > Serial Plotter. Открываем, крутим ручку потенциометра и получаем закономерные изменения сигнала:

График напряжения.

Отлично! На очереди следующий пример.

Пример 3. Напряжение источника питания.

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

Источник питания.

Подключим ее "+" ко входу A1, а минус посадим на землю (подключим к GND). Запускаем пример с измерением напряжения и получаем результат:

Что снова соответствует ожидаемому и не может не радовать )

Пример 4. Управление периодом мигания светодиода при помощи потенциометра.

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

Управление светодиодом на Ардуино с помощью потенциометра.

На breadboard:

Ардуино потенциометр на breadboard.
// Светодиод подключен к D2
int ledPin = 2;

// Аналоговый вход, напряжение на котором будем анализировать
int analogPin = A1;

// Сюда будем сохранять результат с АЦП
int adcResult = 0;

// Текущий период (строго говоря полупериод)
int currentPeriod = 0;

// Максимальное значение периода
constexpr int PERIOD_MAX = 1000;

// Минимальное значение периода
constexpr int PERIOD_MIN = 100;

// Делитель для перерасчета из результата АЦП
constexpr int ADC_MAX = 1023;



void setup() 
{
  Serial.begin(115200);

  // D2 работает в качестве выхода
  pinMode(ledPin, OUTPUT);
}



void loop() 
{
  // Собственно, считываем требуемое значение
  adcResult = analogRead(analogPin);

  // Расчет длительности мигания
  currentPeriod = (float)adcResult / ADC_MAX * (PERIOD_MAX - PERIOD_MIN) + PERIOD_MIN;

  // Зажигаем светодиод
  digitalWrite(ledPin, HIGH);
  delay(currentPeriod);

  // Гасим светодиод
  digitalWrite(ledPin, LOW);
  delay(currentPeriod);
}

Используем примитивные задержки с delay(), чтобы не перегружать ничем пример. Вращая ручку потенциометра, теперь можем менять период мигания светодиода от значения PERIOD_MIN (100) до значения PERIOD_MAX (1000), что и требовалось в данном примере. Математика для расчета периода проста, не буду отдельно расписывать, если что - спрашивайте. По итогу крайние значения такие:

Измеренное значение currentPeriod
0 PERIOD_MIN (100)
1023 PERIOD_MAX (1000)

И вот на этом на сегодня и завершаем, пункт "потенциометр Ардуино" можно отметить как выполненный, переходим к следующим разделам курса, следите за обновлениями и до новых встреч 🤝

Подписаться
Уведомить о
guest

3 комментариев
Старые
Новые
Межтекстовые Отзывы
Посмотреть все комментарии
Dimonsn17
1 год назад

Но как перевести этот сигнал с потенциометра на адресный светодиод, а именно ленту из 8 и что бы они зажигалиль помере вращения потенциометра?

Dimonsn17
Ответ на комментарий  Aveal
1 год назад

Спасибо. Буду ждать.

3
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x