Ардуїно як профі. Частина 1: Битва розрядностей та перші кроки в аналоговому світі

◆ Чому не Blink?

Майже кожен навчальний курс з мікроконтролерів починається з блимання світлодіодом. Це приємна вправа для перших п’яти хвилин, але вона майже нічого не пояснює про те, як мікроконтролер насправді працює з реальним світом.

Температура, світло, звук, тиск, струм, напруга — усе це аналогові сигнали. Світлодіод про них мовчить. А ось аналого-цифровий перетворювач (ADC, англ. Analog-to-Digital Converter) — це перше місце, де мікроконтролер починає “чути” фізичний світ. До речі, в українському законодавстві цей термін не абстракція з підручника — “аналого-цифровий перетворювач (АЦП)” прямо фігурує в ДСТУ 2869-94 “Обладнання периферійне. Терміни та визначення”.

Тому ця серія починається саме тут.

Куди веде цей курс:

Наприкінці серії ви власноруч зберете простий бездротовий цифровий осцилограф. Перший крок до нього — зрозуміти, що взагалі відбувається всередині analogRead().

◆ Аналоговий сигнал і чому цифровий пін його “не бачить”

Аналоговий сигнал може приймати нескінченну кількість значень — плавно, без стрибків. Приклади: температура, освітленість, сигнал з мікрофона, положення потенціометра.

Цифровий вхід мікроконтролера бачить лише два стани: є напруга (HIGH/1) або немає (LOW/0). Подати на цифровий пін 2.5V і очікувати осмисленої відповіді — марно: він або зчитає це як HIGH, або як LOW, залежно від порогу перемикання, і ніякої “середини” не існує.

Щоб цифрова плата зрозуміла плавний сигнал, потрібен перекладач між двома світами — ADC.

◆ Як працює ADC — не магія, а бінарний пошук

Всередині ADC на класичному AVR (Uno, Nano, Mega) — це SAR-перетворювач (successive approximation register, послідовне наближення). Він не “вимірює” напругу одним махом — він її вгадує методом бінарного пошуку: генерує пробну напругу внутрішнім ЦАП, порівнює з реальним сигналом, і уточнює результат біт за бітом, від старшого до молодшого.

Цікаво, що ця архітектура — не якийсь новий винахід епохи Arduino. Перший комерційний SAR ADC — це DATRAC, представлений Бернардом Гордоном у компанії Epsco ще 1954 року: 11-бітний, повністю на електронних лампах, розміром із шафу і ціною $8500-10000. Той самий принцип бінарного зважування, до речі, простежується аж до математичної головоломки XVI століття авторства Тартальї. SAR прижився в hobby-мікроконтролерах не випадково — на відміну від інших архітектур ADC, він не має конвеєрної затримки: одне вимірювання — один результат, ідеально підходить для по черзі опитуваних сенсорів.

Розрядність (Resolution) визначає, наскільки “дрібно” ADC ділить діапазон напруги на кроки:

  • 10 біт → 2¹⁰ = 1024 рівні
  • 12 біт → 2¹² = 4096 рівнів

Формула переведення сирого значення в напругу:

де ADC — результат вимірювання, Vref — опорна напруга, N — кількість біт.

Опорна напруга (Vref) — це довжина вашої “вимірювальної лінійки”. Якщо Vref = 5V, ADC вимірює лише в діапазоні 0-5V. Подасте 6V — ADC вперто покаже свій максимум і не помітить різниці.

Ніколи не подавайте на аналоговий вхід напругу, вищу за напругу живлення мікроконтролера. Для Uno межа — 5V, для ESP32 — 3.3V. Перевищення може незворотно пошкодити вхід.

◆ Битва розрядностей

Плата ADC Діапазон
Arduino Uno 10 біт 0…1023
Arduino Mega 10 біт 0…1023
ESP32 12 біт 0…4095

Більше біт → менший крок вимірювання → в теорії точніше. При Vref=5V крок 10-біт ADC становить 5/1024 ≈ 4.88 мВ; при 12-біт і Vref=3.3V (ESP32) — 3.3/4096 ≈ 0.8 мВ. Різниця відчутна: 12-бітна “лінійка” помічає значно дрібніші коливання сигналу.

Але “більше біт” не означає автоматично “точніше” — і тут криється пастка, в яку регулярно потрапляють навіть досвідчені розробники.

ADC ESP32 має відому нелінійність, задокументовану самими користувачами на форумі: “заявлені 12 біт — практично 9 біт корисного сигналу + 3 біти шуму. Перші ~0.21V вхідного сигналу просто ігноруються при типовій атенюації”. У професійних проєктах це калібрують окремою бібліотекою (esp_adc_cal) чи таблицею поправок під конкретний екземпляр чипа.

Ще одна відома пастка ESP32, яку варто знати з першого дня: ADC2 конфліктує з Wi-Fi. Офіційна документація ESP-IDF прямо каже — “ADC2 використовується Wi-Fi-драйвером, тому застосунок може використовувати ADC2 тільки коли Wi-Fi ще не запущено”. На практиці це виглядає так: код працював на столі, а щойно ви додали WiFi.begin()analogRead() на певних пінах починає повертати сміття чи завжди максимум. Рішення просте — використовуйте піни ADC1 (GPIO32-39), якщо паралельно потрібен Wi-Fi.

◆ Вправа 1.1 — Uno проти ESP32

Потрібно: Arduino Uno, ESP32, потенціометр 10 кОм.

Підключення:

GND обох плат обов’язково з’єднати між собою — без спільної землі порівнювати виміри між платами безглуздо, сигнали не мають спільної точки відліку.

Живимо схему саме 3.3V (не 5V) — це безпечно і для Uno (5V-логіка спокійно читає нижчу напругу), і критично важливо для ESP32, чий аналоговий вхід максимум на 3.3V.

Код для Arduino Uno:

Код для ESP32:

Завдання: запустіть однаковий рух ручки потенціометра на обох платах одночасно. Відкрийте Serial Plotter (Ctrl+Shift+L в Arduino IDE) і порівняйте:

  • плавність графіка;
  • максимальні значення (графік ESP32 буде вчетверо “вищим” — це очікувано, 4095 проти 1023);
  • реакцію на дрібні зміни — злегка постукайте пальцем по столу біля плати. Графік ESP32 підхопить мікроскопічні коливання напруги від вібрації; лінія Uno, найімовірніше, залишиться майже рівною — вона просто “не бачить” настільки дрібних змін.

◆ Як це роблять професіонали

Схема “напруга → ADC → обробка → відображення” — не навчальна спрощена модель, а буквально те, як влаштований будь-який цифровий мультиметр:

Осцилограф теж починається рівно з цього самого блоку. Різниця між “домашнім” ADC і промисловим — не в принципі роботи, а в швидкості дискретизації, розрядності й якості калібрування.

◆ Вправа 1.2 — мікроскопічний режим Arduino Mega

Що робити, якщо потрібно виміряти дуже слабкий сигнал — наприклад, з термопари чи мікрофона, — який змінюється на соті долі вольта? Стандартна опорна напруга 5V для такого завдання занадто “груба” — крок 4.88 мВ просто не помітить дрібні коливання.

Arduino Mega 2560 має вбудовані внутрішні джерела опорної напруги — 1.1V і 2.56V. Перемкнувши “лінійку” на 1.1V, ви змушуєте ті самі 1024 рівні ADC ділити набагато менший діапазон — точність кроку зростає до ~1.07 мВ.

⚠ Напруга на піні не повинна перевищувати обраний внутрішній референс (тут — 1.1V), інакше ADC просто видасть максимум (1023) і “не помітить” перевищення. Джерело сигналу — щось справді слабке: майже сіла батарейка, вихід аналогового сенсора з малою амплітудою.

Практична порада, яку не знайдеш у мануалі: одразу після зміни analogReference() рекомендується зробити один “холостий” виклик analogRead(A0); і відкинути результат — перше вимірювання після перемикання референсу часто ще “пам’ятає” стару опорну напругу через перехідний процес у внутрішньому конденсаторі.

◆ Бонус: секретний вольтметр — вимір напруги без жодного зовнішнього компонента

Ось факт, який зазвичай ламає шаблон у розробників з software-бекграундом: analogRead() насправді не вимірює проти фіксованих 5V. Він вимірює проти того, чим Vcc є прямо зараз. З цього випливає елегантний трюк спільноти — виміряти власну напругу живлення плати, не підключаючи взагалі нічого зовнішнього.

Принцип: перемикаємо референс ADC на Vcc, а на вхід подаємо внутрішнє джерело 1.1V (той самий bandgap-референс, що й в INTERNAL1V1 вище, тільки тепер у ролі вимірюваного сигналу, а не опорного). Раз виміряне = Vcc × ADC/1023 = 1.1V, то:

⚠ Точність цього трюку обмежена самим bandgap-референсом — за специфікацією він десь між 1.0V і 1.2V, тобто похибка “з коробки” може сягати 10%. Реальні виміри кількох чипів ATmega328P показали значення від 0.994V до 1.089V — усі нижче “типових” 1.1V. Для практичного застосування (наприклад, моніторинг заряду батареї в польовому пристрої) референс варто відкалібрувати індивідуально під конкретний чип мультиметром — тоді результат стає стабільним і повторюваним, хоч і трохи дрейфує з температурою.

Це вже вихід за межі базової вправи цієї статті — залишаю як тему для самостійного дослідження, чи для однієї з наступних статей серії.

◆ Типові помилки

  • Подати 5V на аналоговий вхід ESP32 (межа 3.3V — не рекомендація, а жорсткий ліміт).
  • Забути з’єднати GND двох плат при порівняльних вимірах.
  • Вважати, що більше біт = завжди точніше (ADC ESP32 — живий контрприклад).
  • Використовувати шумний USB-порт ноутбука як “еталонне” живлення для точних вимірів.
  • Плутати піни ADC2 на ESP32 з активним Wi-Fi — код працює на столі, ламається після додавання мережі.

◆ Домашнє завдання

  1. Порівняйте Uno та ESP32 за вправою 1.1, побудуйте графік у Serial Plotter.
  2. Спробуйте торкнутись потенціометра пальцем під час виміру — запишіть, що змінилось і чому (натяк: ваше тіло — антена для наведень 50 Гц).
  3. Спробуйте вправу 1.2 на Mega, якщо плата є в наборі.
  4. Занотуйте власні спостереження — вони знадобляться, коли дійдемо до фільтрації сигналу.

◆ Запитання для самоперевірки

  1. Що таке ADC і навіщо він потрібен, якщо є цифрові піни?
  2. Що таке Vref і як він впливає на точність виміру?
  3. Чому цифровий пін не може коректно виміряти 2.5V?
  4. Чому ESP32 показує до 4095, а Uno — тільки до 1023?
  5. Чому “більше біт” не гарантує “точніше вимірювання”?

◆ Далі в серії

У наступній статті:

  • повністю відмовляємось від delay();
  • вчимось будувати неблокуючий код через millis();
  • реалізуємо цифровий фільтр Moving Average — і побачимо, як “заспокоїти” той самий шумний сигнал з потенціометра, з яким щойно грались;
  • перетворюємо Arduino на швидкий реєстратор даних.

Ласкаво просимо у світ інженерії мікроконтролерів.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *