“Аналоговые” пины


В прошлом уроке мы разобрали измерение и вывод цифрового сигнала с микроконтроллера, а в этом разберём аналоговый сигнал. Как мы уже не раз говорили ранее, у микроконтроллера есть аналоговые входы, т.е. входы, подключенные к АЦП – аналогово-цифровому преобразователю (ADC). На платах Ардуино это пины, маркированные буквой А. Я не просто так написал название в кавычках, потому что не все пины являются только аналоговыми: например на плате Nano пины A0-A5 являются также обычными цифровыми, и у них есть возможность измерять аналоговый сигнал как доп. функция. Пины A6 и A7 являются чисто аналоговыми.

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

Чтение сигнала


“Аналоговые” пины могут принимать напряжение от 0 (GND) до опорного напряжения и преобразовывать его в цифровое значение, просто в какие-то условные единицы. АЦП у нас имеет разрядность в 10 бит, т.е. мы получаем измеренное напряжение в виде числа от 0 до 1023. Функция, которая оцифровывает напряжение, называется analogRead(pin), данная функция принимает в качестве аргумента номер аналогового пина и возвращает полученное значение. Сам пин должен быть сконфигурирован как INPUT (вход), напомню, что по умолчанию все пины так и настроены. Пин кстати указывается “аналоговый”:

  • Просто номером А-пина (например, 0)
  • Номером с буквой А (например, А0)
  • Порядковым номером GPIO: А0 – 14 пин, A1 – 15 пин… А7 – 21

Вот пример, опрашивающий пин А0.

int value1 = analogRead(0);   // считать напряжение с пина A0
int value2 = analogRead(A0);  // считать напряжение с пина A0
int value3 = analogRead(14);  // считать напряжение с пина A0

Хранить полученное значение разумно в переменной типа int, потому что значение варьируется от 0 до 1023.

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


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

К Arduino потенциометр подключается вот так, средний вывод на любые A-пины, крайние – на GND и питание. От порядка подключения GND и питания зависит направление изменения значения. Что касается сопротивления, то читай заметку по делителям напряжения ниже в этом уроке. Чаще всего для микроконтроллеров ставят потенциометры с сопротивлением 10 кОм, но диапазон в принципе очень широк: от 1 кОм до 100 кОм. Чем больше, тем более шумным будет приходить сигнал, а если брать меньше – пойдут потери тока в нагрев потенциометра, а это никому не нужно.

Опорное напряжение


Опорное напряжение играет главную роль в измерении аналогового сигнала, потому что именно от него зависит максимальное измеряемое напряжение и вообще возможность и точность перевода полученного значения 0-1023 в Вольты. Изучим следующую функцию – analogReference(mode), где mode:

  • DEFAULT: опорное напряжение равно напряжению питания МК. Активно по умолчанию
  • INTERNAL: встроенный источник опорного на 1.1V для ATmega168 или ATmega328P и 2.56V на ATmega8
  • INTERNAL1V1: встроенный источник опорного на 1.1V (только для Arduino Mega)
  • INTERNAL2V56: встроенный источник опорного на 2.56V (только для Arduino Mega)
  • EXTERNAL: опорным будет считаться напряжение, поданное на пин AREF

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

Значение 1023 функции analogRead() будет соответствовать выбранному опорному напряжению или напряжению выше его, но не выше 5.5V, что спалит плату. То есть при режиме DEFAULTмы можем оцифровать напряжение от 0 до напряжения питания. Если напряжение питания 4.5 Вольта, и мы подаём 4.5 Вольт – получим оцифрованное значение 1023. Если подаём 5 Вольт – опять же получим 1023, т.к. выше опорного. Это правило работает и дальше, главное не превышать 5.5 Вольт. Как измерять более высокое напряжение (12 Вольт например) я расскажу в отдельном уроке.

Что касается точности: при питании от 5V и режиме DEFAULT мы получим точность измерения напряжения (5 / 1024) ~4.9 милливольт. Поставив INTERNAL мы можем измерять напряжение от 0V до 1.1V с точностью (1.1 / 1024) ~0.98 милливольт. Весьма неплохо, особенно если баловаться с делителем напряжения.

Что касается внешнего источника опорного напряжения. Нельзя использовать напряжение меньше 0V или выше 5.5V в качестве внешнего опорного в пин AREF. Также при использовании режима EXTERNAL нужно вызвать analogReference(EXTERNAL) до вызова функции analogRead(), иначе можно повредить микроконтроллер. Можно подключить опорное в пин AREF через резистор на ~5 кОм, но так как вход AREF имеет собственное сопротивление в 32 кОм, реальное опорное будет например 2.5 * 32 / (32 + 5) = ~2.2V.

Измерение напряжения

0-5 Вольт


Простой пример, как измерить напряжение на аналоговом пине и перевести его в Вольты. Плата питается от 5V.

float voltage = (float)(analogRead(0) * 5.0) / 1024;

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

Почему мы делим на 1024, а не на 1023 , ведь максимальное значение измерения с АЦП составляет 1023? Ответ можно найти в даташите:

АЦП при преобразовании отнимает один бит, т.е. 5.0 Вольт он в принципе может измерить только как 4.995, что и получится по формуле выше: 1023 * 5 / 1024 == 4.995.. . Таким образом делить нужно на 1024, если кто-то у вас спросит почему – отправьте его читать даташит.

Сильно больше 5 Вольт


Для измерения постоянного напряжения больше 5 Вольт нужно использовать делитель напряжения на резисторах (Википедия). Схема подключения, при которой плата питается от 12V в пин Vin и может измерять напряжение источника (например, аккумулятора):

Код для перевода значения с analogRead в вольты с учётом делителя напряжения:

// GND -- [ R2 ] -- A0 -- [ R1 ] -- VIN
#define VREF 5.1      // точное напряжение на пине 5V (в данном случае зависит от стабилизатора на плате Arduino)
#define DIV_R1 10000  // точное значение 10 кОм резистора
#define DIV_R2 4700   // точное значение 4.7 кОм резистора

void setup() {
  float voltage = (float)analogRead(0) * VREF * ((DIV_R1 + DIV_R2) / DIV_R2) / 1024;
}
void loop() {}

Как выбрать/рассчитать делитель напряжения?

  • Согласно даташиту на ATmega, сумма R1 + R2 не рекомендуется больше 10 кОм для достижения наибольшей точности измерения. В то же время через делитель на 10 кОм будет течь ощутимый ток, что критично для автономных устройств (читай ниже). Если девайс работает от сети или от аккумулятора, но МК не используется в режиме сна – ставим делитель 10 кОм и не задумываемся. Также рекомендуется поставить конденсатор между GND и аналоговым пином для уменьшения помех.
  • Если девайс работает от аккумулятора и микроконтроллер “спит”: пусть аккумулятор 12V, тогда через 10 кОм делитель пойдёт ток 1.2 мА, согласно закону Ома. Сам микроконтроллер в режиме сна потребляет ~1 мкА, что в тысячу раз меньше! На самом деле можно взять делитель с гораздо бОльшим суммарным сопротивлением (но не больше 20 МОм, внутреннего сопротивления самого АЦП), но обязательно поставить конденсатор на ~0.1 мкФ между аналоговым пином и GND (вот здесь проводили эксперимент). Таким образом например при при R1+R2 = 10 МОм (не забыть про конденсатор) ток через делитель будет 1.2 мкА, что уже гораздо лучше!
  • Коэффициент делителя равен (R1 + R2) / R2. Коэффициент должен быть таким, чтобы при делении на него измеряемого напряжения не получилось больше 5 Вольт. У меня в примере (10 + 4.7) / 4.7 ~ 3.13. Я хочу измерять литиевый аккумулятор с максимальным напряжением 12.8 Вольт. 12.8 / 3.13 ~ 4 Вольта – отлично. Например для измерения 36 Вольт я бы взял делитель с плечами 100к и 10к.
  • Можно воспользоваться онлайн-калькулятором.

Сильно меньше 5 Вольт


Для более точных измерений маленького напряжения можно подключить пин AREF к источнику низкого опорного напряжения (об этом было выше), чтобы “сузить” диапазон работы АЦП. Источник может быть как внешний, так и внутренний, например изменив опорное на внутреннее 1.1V ( analogReference(INTERNAL) ) можно измерять напряжение от 0 до 1.1 Вольта с точностью 1.1/1024 ~ 1.01 мВ.

Видео


Важные страницы