Кнопочный ввод с помощью ацп

Содержание

АЦП микроконтроллера AVR

//программирование микроконтроллеров AVR на Си – осваиваем АЦП
#include
#include

#define StartConvAdc() ADCSRA |= (1 #define KEY_NULL 0
#define KEY_S1 1
#define KEY_S2 2
#define KEY_S3 3
#define KEY_S4 4

//кнопочный буфер
volatile unsigned char KeyBuf = 0;

int main( void )
<
unsigned char tmp;

//настраиваем порты
DDRC = 0xff;
PORTC = 0xff;

//инициализируем АЦП
//ион – напряжение питания, выравнивание влево, нулевой канал
ADMUX = (0 //вкл. ацп, режим одиночного преобр., разрешение прер., частота преобр. = FCPU/128
ADCSRA = (1 //разрешаем прерывания и запускаем преобразование
__enable_interrupt ();
StartConvAdc();

//основной цикл программы – опрос кнопочного буфера
while (1)
<
tmp = KeyBuf;
if (tmp)
<
tmp–;
PORTC =

(1 else
PORTC = 0xff;
>
return 0;
>

#pragma vector=ADC_vect
__interrupt void adc_my( void )
<
//считываем старший регистр АЦП
unsigned char AdcBuf = ADCH;

//опеределяем в какой диапазон попадает его значение
if (AdcBuf > 240)
KeyBuf = KEY_S4;
else if (AdcBuf > 180)
KeyBuf = KEY_S3;
else if (AdcBuf > 120)
KeyBuf = KEY_S2;
else if (AdcBuf > 35)
KeyBuf = KEY_S1;
else
KeyBuf = KEY_NULL;

//запускаем преобразование и выходим
StartConvAdc();
>

Пояснения к коду

Номера кнопок

#define KEY_NULL 0
#define KEY_S1 1
#define KEY_S2 2
#define KEY_S3 3
#define KEY_S4 4

Переменная – кнопочный буфер

//кнопочный буфер
volatile unsigned char KeyBuf = 0;

Опрос буфера в основном коде программы

while (1)
<
tmp = KeyBuf;
if (tmp)
<
tmp–;
PORTC =

Обработчик прерывания

if (AdcBuf > 240)
KeyBuf = KEY_S4;
else
if (AdcBuf > 180)
KeyBuf = KEY_S3;
else
if (AdcBuf > 120)
KeyBuf = KEY_S2;
else
if (AdcBuf > 50)
KeyBuf = KEY_S1;
else
KeyBuf = KEY_NULL;

но согласитесь, что такая запись менее наглядна.

Устраняем ложные срабатывания

unsigned char comp = 0;
#pragma vector=ADC_vect
__interrupt void adc_my( void )
<
unsigned char AdcBuf;
unsigned char Key;
static unsigned char LastState;

//считываем старший регистр АЦП
AdcBuf = ADCH;

//проверяем в какой диапазон попадает его значение
if (AdcBuf > 240)
Key = KEY_S4;
else if (AdcBuf > 180)
Key = KEY_S3;
else if (AdcBuf > 120)
Key = KEY_S2;
else if (AdcBuf > 50)
Key = KEY_S1;
else
Key = KEY_NULL;

//если какая-нибудь из кнопка нажата
//сравниваем предыдущее и текущее состояние
//если совпадают – проверяем счетчик comp,
//если нет – обнуляем его
//кнопка считается нажатой, если она удерживается в течении 100
//преобразований АЦП
if (Key)
<
if (Key == LastState)
<
if (comp > 100)
KeyBuf = Key;
else
comp++;
>
else
<
LastState = Key;
comp = 0;
>
>
else
<
comp = 0;
KeyBuf = KEY_NULL;
LastState = KEY_NULL;
>

//запускаем преобразование и выходим
StartConvAdc();
>

Мы ввели три дополнительные переменные: comp, LastState и Key.

Итак, из этих двух статей вы узнали

– Основные характеристики АЦП
– Как инициализировать и запустить АЦП
– Как перевести значение напряжения на входе АЦП в цифровой код
– Конструкция if (…) else if(…)
– Зачем нужен квалификатор volatile
– Как объявить статическую переменную и в чем ее особенность
– Алгоритм для борьбы с дребезгом кнопок

Arduino. Обработка кнопок при помощи АЦП

Есть много способов экономии выводов при подключении кнопок к микроконтроллеру. В этой статье мы рассмотрим способ при котором кнопки подключаются через резистивные делитель и их состояние считывается при помощи АЦП.

Подготовка к работе

На нашем TutorShield есть две кнопки, которые могут быть подключены как к цифровым выводам Arduino, так и к аналоговым входам. Если вы установите перемычку так, как показано на рисунке, кнопки будут подключены к аналоговому входу А3.

Схема подключения кнопок при этом будет выглядеть следующим образом:

Схема подключения кнопок

На TutorShield кнопки подписаны “2” и “3”. При разных комбинациях их нажатий образуется делитель напряжения с разным коэффициентом передачи. Все возможные комбинации эквивалентных схем и напряжений на выводе А3 приведены ниже:

Напряжение на резистивном делителе определяется по формуле
Uвых=(Uвх*Rн)/(Rв+Rн)
, где Uвх — напряжение приложенное к верхнему плечу делителя (5В), Rв — сопротивление в верхнем плече делителя, Rн — сопротивление в нижнем плече делителя.
Считывать состояние данные с кнопок будем как в предыдущей статье. Мы будем использовать также только 8 разрядов, поэтому измерять напряжение будем с шагом 19.6мВ.
Итак, есть четыре возможные ситуации:

  1. Ни одна кнопка не нажата, на выводе А3 напряжение 5В, АЦП вернет значение “255”
  2. Если нажата кнопка “2”,на А3 — 2,5В, АЦП пришлет значение 2,5/0.0196=128
  3. Нажата кнопка “3”, на А3 — 3,3В, АЦП — 3,3/0.0196=169
  4. Обе кнопки, на А3 — 2В, АЦП — 2/0,0196=102

Обратите внимание, что АЦП всегда округляет полученное значение в большую сторону! Также расхождение возможно из-за того, что сопротивление резисторов отличается от номинального, меняется от напряжение питания и т.д.

Первый пример

Для начала повторим пример из предыдущей статьи. Попробуем просто читать состояние вывода A3 и будем передавать его в COM-порт с периодичностью раз в секунду:

Нажимая кнопки и наблюдая за данными в мониторе COM-порта (Ctrl+Shift+M), проверьте, какие значения соответствуют нажатиям кнопок.
Плата, на которой мы запускали этот код, присылала значения 255, 128, 170 и 102. Небольшое расхождение возможно из-за не одинаковых питающий напряжений, различия сопротивлений резисторов и т.д. Это означает, что нужно задать определенный разброс значений для определения состояния кнопок.

Второй пример

Теперь в программе нужно принимать решения о состоянии кнопок. Нам нужно разработать код, который будет проверять состояние вывода и выставлять флаги о состоянии кнопок.
Флагом в программировании называют переменную, которая характеризует состояние какого-либо объекта. Мы заведем два флага — button2 и button3. Если в этой переменной единица, то кнопка нажата. Если ноль, то отжата.
Перейдем к определению состояния кнопок. Можно, конечно, просто сравнивать полученное значение с измеренным заранее числом, но гораздо лучше задать определенный разброс параметров. Сделать это проще всего по середине диапазона. Зададим условие следующим образом:

  1. Если полученное значение больше 212, значит ни одна кнопка не нажата
  2. Если оно лежит в диапазоне от 212 до 149, то нажата кнопка “3”
  3. От 149 до 115, то нажата кнопка “2”
  4. Менее 115 — нажаты обе кнопки

Чтобы визуально контролировать состояние кнопок, подключите два светодиода к выводам D0 и D1 (вспомнить как это сделать можно здесь)

Кнопке номер два соответствует крайний правый светодиод, а кнопке “3” второй справа.

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

Использование АЦП микроконтроллера в качестве интерфейса клавиатуры

Atmel ATMega168

ATMega168 – это прекрасный универсальный 8-битный AVR микроконтроллер фирмы Atmel. Он имеет 23 вывода общего назначения (GPIO), но иногда, по мере роста вашего проекта, контактов ввода/вывода начинает не хватать. Такое недавно случилось и со мной, когда из 23 доступных GPIO два я занял внешним керамическим резонатором, один вывод под линию сброса, 3 для последовательного порта, 14 для ЖК индикатора и 3 для управления RGB светодиодом. Таким образом, все 23 вывода были использованы, и для управления четырьмя кнопками ничего не оставалось. Что же делать? Решение предлагается в этой статье.

Читайте также:  Эффект эхо (echo) на микроконтроллере atmega32

Внимательно посмотрев в техническую документацию на ATMega168, можно заметить, что количество доступных выводов для вариантов в 28-выводном корпусе DIP и 32-выводном корпусе TQFP не одно и то же. Версия в корпусе TQFP, помимо рекламируемых 23 GPIO, имеет пару дополнительных выводов VCC и GND, а также два входа АЦП. Таким образом, если я смогу с помощью двух дополнительных входов АЦП считывать данные четырех кнопок, все будет OK, и моя конструкция будет спасена.

Кроме того, интерфейс пользователя был довольно сильно перегружен функциями, поэтому для вызова на ЖКИ различных пунктов меню приходилось использовать комбинации кнопок. К тому же, разработка софта еще не была закончена, и не было уверенности, что не понадобятся новые комбинации кнопок. Мне хотелось иметь возможность определения нажатия, как каждой отдельной кнопки, так и любых их сочетаний, поэтому всего я должен был распознавать 2 4 или 16 возможных состояний кнопок.

Ну что же, сначала мне показалось, что это будет несложно. Я просто должен был включить цепочку резисторов между моими четырьмя кнопками и одним из входов АЦП, чтобы каждая кнопка подтягивалась к земле различным количеством резисторов, равномерно распределенных между VCC и GND (Рисунок 1). Однако, когда я попытался это сделать, оказалось, что все не так просто, как представлялось вначале.

Рисунок 1.Резистивная цепь для четырех кнопок.

Я рассматривал вариант использования лестничной цепочки резисторов R-2R, но для этого потребовались бы переключатели на два направления, чтобы выходы соединялись с VCC или GND и не оставались висящими в воздухе. Поразмышляв об этом некоторое время, я понял, что пошел по слишком трудному пути, и решение должно быть более простым. Есть два доступных входа АЦП, поэтому, если к каждому из них я подключу только по две кнопки, мне потребуется декодировать лишь 2 2 , или 4 возможных состояния кнопок вместо 16 (Рисунок 2). Если состояния не распределятся равномерно между VCC и GND, особого значения это иметь не будет.

Рисунок 2.Более простая схема с двумя кнопками.

Это привело к созданию схемы, изображенной на Рисунке 3, которая подтвердила правильность выбранного решения довольно долгой работой в серийной продукции одного из моих клиентов. Поскольку сопротивления всех резисторов одинаковы, заменив их одной матрицей из четырех резисторов, например, чем-нибудь типа Bourns 1206, можно уменьшить размеры схемы.

Рисунок 3.Часть схемы с двумя парами кнопок.

В конце статьи можно загрузить проектные файлы, помогающие понять работу схемы, среди которых есть электронные таблицы в формате OpenOffice. Желтым цветом в них выделены ячейки, в которые вы вводите значения сопротивлений используемых резисторов, напряжение питания и разрешение АЦП. В зеленых ячейках находятся расчетные значения, показывающие работу схемы. Первые три колонки содержат таблицу истинности входов кнопок, а колонка R Buttons показывает результирующее подтягивающее сопротивление, образующееся при различных комбинациях нажатых кнопок. В колонках Vout и Counts представлены входное напряжение АЦП и его выходной код. Колонка Count Mid Points содержит коды АЦП, средние относительно ожидаемых значений; именно они используются для дифференциации различных входов и декодирования нажатых кнопок. Это дает гарантию, что все возможные комбинации входных значений будут декодированы, а запас, учитывающий разброс номинальных значений сопротивлений, шумы и прочее, будет максимальным.

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

Как обнаружилось, распределение кодов получилось не вполне линейным. Тем не менее, даже ближайшие значения разделены интервалами, достаточными для практического использования. Результаты, представленные в графическом виде на Рисунке 4, демонстрируют эту нелинейность, и, кроме того, наглядно показывают, что почти половина входного диапазона АЦП в такой схеме остается неиспользованной.

Рисунок 4.Зависимость входного напряжения АЦП от номера комбинации
нажатых кнопок для схемы на Рисунке 3.

Это приемлемая плата за простоту, которая, однако, заставила меня задаться вопросом, можно ли придумать более хорошее решение задачи, и побудила пересмотреть первоначальные представления о схеме на Рисунке 1. Кажется логичным увеличить количество кнопок с двух до четырех, продлив прогрессию сопротивлений резисторов от 10K, 20K до 10K, 20K, 40K, 80K. Однако это не решает проблем нелинейности или потери части рабочего диапазона АЦП.

Более хорошим решением была бы замена подтягивающего резистора (R1 на Рисунке 3) источником постоянного тока. Цепочка подключенных к кнопкам резисторов преобразовывала бы постоянный ток в хорошие, равномерно распределенные значения выходных напряжений. Вероятно, подобное можно сделать с помощью источника опорного напряжения (например, TL431) и транзистора. Но это увеличит число активных компонентов и потребует тщательной проработки конструкции, уводя меня от первоначального видения простой резистивной цепочки.

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

Рисунок 5.Схема с четырьмя кнопками.

В этой схеме для четырех кнопок используется всего один вход АЦП, оставляя другой для наращивания количества кнопок, или для иных целей. Четыре кнопки и включенные последовательно с ними резисторы образуют одно плечо моста, а R9 и R10 – другое. Втрое плечо используется в качестве источника опорного напряжения АЦП, равного максимальному входному напряжению. Сопротивления резисторов выбраны так, чтобы R10 = R15, а R9 равнялось эквивалентному сопротивлению включенных параллельно резисторов R11 … R14, что обеспечивает полное использование входного диапазона АЦП. Небольшие величины сопротивлений R15 и R10 улучшают линейность за счет снижения фактического размаха напряжения.

Надо заметить, что на практике найти такие значения сопротивлений непросто, однако их можно сделать с использованием резисторов из стандартного ряда номиналов. Нужные сопротивления R13 и R14 можно набрать путем последовательного соединения резисторов 20 кОм, а R9 может состоять из пары параллельно соединенных резисторов 10 кОм, к которым последовательно подключены три параллельных резистора 1 кОм. При использовании этих трех номиналов для всей схемы будет достаточно четырех резисторных матриц и одного отдельного резистора.

Работа схемы иллюстрируется графиком на Рисунке 6, показывающим значительное улучшение линейности по сравнению с предыдущим вариантом. Продолжая геометрическую прогрессию резисторов, эту схему можно расширить до пяти и, возможно, до шести кнопок. Однако для надежной работы схемы потребуется тщательный подбор сопротивлений резисторов, после чего придется провести ряд экспериментов для определения минимальных и максимальных значений сопротивлений.

Рисунок 6.Зависимость входного напряжения АЦП от номера комбинации
нажатых кнопок для схемы на Рисунке 5.

Опыт, приобретенный в процессе создания и исследования схемы, выявил незначительную проблему, связанную с выводом AREF микроконтроллера, потребляющим небольшой ток и вносящим ошибку в опорное напряжение. Ток вывода AREF приводится в справочных данных на микроконтроллер, и может быть учтен. Для компенсации вносимой этим выводом ошибки последовательно с R10 необходимо включить резистор 33 Ом. После такой коррекции экспериментальные результаты, полученные при использовании 8-битного АЦП, отличались от расчетных значений из электронной таблицы не более чем на один отсчет. Разработка программного кода для этой версии схемы оставлена в качестве упражнения для читателей.

Рисунок 7.Макет схемы с четырьмя кнопками.

Есть возможность обойтись вообще без R9 и R10, воспользовавшись напряжением 1.1 В внутреннего источника опорного микроконтроллера. В этом случае сопротивление R15 потребуется изменить с 1 кОм на 1.5 кОм. Однако тогда на результаты измерений будет влиять точность напряжения VCC.

Теперь, после большой проведенной работы, кажется, что цель, которую мы ставили перед собой, глядя на Рисунок 1, была не такой уж труднореализуемой.

Загрузки

Перевод: AlexAAN по заказу РадиоЛоцман

Прикладное программирование с нуля.

AVR, STM, Android, IoT. Встраиваемые системы.

Шаг №32. Настраиваем АЦП для кнопок на AVR. Делитель напряжения

Всем привет. В прошлой статье мы с Вами подвели итог проделанной работы по контроллеру сбору данных и спланировали работу дальше. Первым пунктом мы прописали подключение кнопок для коррекции времени. Для этого используем вывод АЦП и делитель напряжения. Один раз АЦП мы уже использовали на примере Реле напряжения (барьер) на микроконтроллере AVR . Перед подключением познакомимся с АЦП поближе.

Читайте также:  Как проложить электропроводку в квартире

АЦП обладает следующими характеристиками:

— разрешающая способность. Обычно у ATmega это 2 в 10 степени, т.е. 1024 кодовые комбинации. Но не забываем что мы делаем проект на ATmega 8, у которого ADC4 и ADC5 – 8-битные. Эти ножки мы уже использовали для передачи информации по интерфейсу TWI . Я подключил к ADC0.

Следующая характеристика –это абсолютная погрешность , которая допускается ±2МЗР, где МЗР- это младшие значащие разряды, т.е. минимальный размер напряжения, который может преобразовать АЦП. Ниже в программе мы непременно вернемся к этим характеристикам.

И две последние – интегральная нелинейность ±0.5МЗР и быстродействие до 15 тыс. выборок в секунду.

АЦП может работать в двух режимах:
— одиночное преобразование, запускается пользователем;
— непрерывное преобразование, использовали в статье № 9, при построении барьера.

Мы будем использовать 1-й вариант. Для управления модулем АЦП используется 3 регистра, для atmega 8 (для других моделей смотрим даташит):

– ADCSR – регистр состояния и управления;
— ADMUX – регистр управления мультиплексором;
— SFIOR – регистр специальных функций.

Рассмотрим каждый. Начнем с 1-го. Изображен на рисунке ниже.

В программе настройка регистра управления будет выглядеть следующим образом: включаем АЦП, режим одиночного преобразования, разрешаем прерывание, частота преобразования Fcpu/128.
ADCSR = (1 Последние два разряда регистра – это выбор коэффициента пред делителя, рис. ниже

Запуск каждого преобразования мы будем осуществлять установкой разряда ADSC, как говорится вручную ( ADCSRA |= (1 В программе, настройка регистра управления, будет выглядеть следующим образом: ИОН – напряжение питания AVcc, выравниваем результат преобразования влево, к АЦП подключаем нулевой канал ADC0.

ADMUX = (0 И последний регистр SFIOR – регистр специальных назначений. Рис. ниже.

Как видите в данной модели контроллера, всего один разряд ADCHM. Который отвечает за увеличение частоты выборки. Т.е. когда нужна частота более 200 кГц и точность преобразования менее 10 разрядов. Но при этом увеличивается потребление микроконтроллера. Мы данным регистром пользоваться не будем.

Итак разберем как преобразовываются значения. Для этого существует формула для несимметричных выходов

В нашем случае мы обойдемся 8-разрядной точностью:

Vin –значение входного напряжения
Vref – величина опорного напряжения.

Идем дальше. Нам необходимо что бы при нажатии определенной кнопки ей соответствовало свое напряжение. Для этого кнопки подключим к делителю напряжения (Рис. ниже)

Где R6, R5 –делитель. R3 – подтягиваем ногу к земле, через большое сопротивление , для предотвращения появления на нем наводок, помех и др. Как говорится что б ножка не “болталась в воздухе”. R4 – токоограничивающий резистор. R3, C1 – низкочастотный фильтр для защиты от дребезга кнопок и помех, что является рекомендацией в документации .

В делителе для простоты расчета берем сопротивление одного номинала – 2 кОм. Рассчитаем значение входного напряжения в зависимости от нажатой кнопки по формуле для верхней кнопки:

S1 = 5В * (4/(2+2))= 5 В.

S2 = 5В *(2 /(2+2))=2,5 В;

Далее наши значения входного напряжения подставляем в формулу для расчета ADC:

ADCs1= 255 * 5 В/5 В = 255.
ADCs2= 255 * 2,5 В/5 В = 127,5.

И последнее, рассмотрим подключение опорного напряжения. В своих настройках ИОН я выбрал внешнее питание. В контроллере за питание АЦП отвечают выводы AGND и AVCC . На рисунке ниже приведена схема включения, опять же рекомендуемая.

Т.к. АЦП это точный измеритель напряжения, то для точности ставят фильтры от помех в питающей цепи. Ставят дроссель примерно 10 мкГн между AVcc и Vcc , конденсатор дополнительно успокоит питание на АЦП . Также не лишне будет ставить керамический конденсатор, примерно 100 нФ между Vcc и GND , которій сгладит импульсные помехи в шине питания вызванные работой цифровых схем.

Также для более точных измерений проводят разделение земли на цифровую и аналоговую, и соединяют их в одной точке. На AVсс подается напряжение через фильтрующий дроссель. Дополнительно для повышения точности вход AREF , т.к. мы его не используем (для подключения источника внутреннего напряжения, относительно чего будет считать АЦП ), рекомендуется вешать конденсатор, что немного улучшит качество опорного напряжения АЦП . Ну и напоследок можно повесить конденсатор на 47мКФ в цепи питания, который сгладит более глубокие броски напряжения.

Для двух кнопок нам не надо точные измерения, поэтому напрямую подключаем AVcc к внешнему питанию, а AGND садим на цифровую землю.

Хочется отметить что в микроконтроллере ATmega 8 есть аппаратный баг. Vcc и AVcc связаны между собой внутри кристалла. Сопротивление между ними составляет примерно 5 Ом . Но это не значит, что нет необходимости подключать AVcc .

В этой статье мы кратко рассмотрели настройки АЦП . Как его применить под кнопки. Подключение питания и настройка источника опорного напряжения для АЦП.

В следующей статье подключим кнопки, напишем код, протестируем в Proteus и в железе. Одновременно порт АЦП , будет в качестве интерфейса TWI и обработчик кнопок. На этом все. Всем пока.

Кнопочный ввод с помощью ацп

  • Уроки
  • Базовые уроки Arduino
  • Аналоговые входы

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

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

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

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

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

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

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

Хранить полученное значение разумно в переменной типа 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) =

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

0-5 Вольт

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

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

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

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

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

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

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

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

    Сумма 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

    Видео