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


В прошлом уроке мы разобрали измерение и вывод цифрового сигнала с микроконтроллера, а в этом разберём аналоговый сигнал. Как мы уже не раз говорили ранее, у микроконтроллера есть аналоговые входы, т.е. входы, подключенные к АЦП – аналогово-цифровому преобразователю (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.

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


Опорное напряжение играет главную роль в измерении аналогового сигнала, потому что именно от него зависит максимальное измеряемое напряжение и вообще возможность и точность перевода полученного значения 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  ~ 8 мВ) – 8 милливольт. Поставив INTERNAL мы можем измерять напряжение от 0V до 1.1V с точностью (1.1 / 1024 ~ 1.2 мВ) – 1.2 милливольта. Весьма неплохо, особенно если баловаться с делителем напряжения.

Что касается внешнего источника опорного напряжения. Нельзя использовать напряжение меньше 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() {}

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

  • Сумма R1 + R2 не рекомендуется больше 10 кОм для достижения наибольшей точности измерения (согласно даташиту на ATmega). Чем меньше общее сопротивление, тем больший ток будет течь впустую через делитель, что критично для автономных устройств. Для уменьшения шума измерений нужно подключить керамический конденсатор ~0.1 мкФ между аналоговым пином и GND (подробнее читай здесь).
    • Например при измерении 12 Вольт через делитель с общим сопротивлением 10 кОм пойдёт ток 1.2 мА, что много для автономного устройства (микроконтроллер в активном режиме потребляет ~15 мА, в режиме сна около 1 мкА). При при 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 мВ.

Видео


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