Точний вольтметр на ADS1115: 16 біт замість «кривого» АЦП ESP32
Вбудований АЦП ESP32 має мертву зону біля нуля, стелю 3.1 В і нелінійність. Зовнішній 16-бітний ADS1115 по I2C міряє з кроком 0.125 мВ. Порівнюємо обидва на одному потенціометрі й міряємо напругу акумулятора 12 В через дільник.
Про проєкт
analogRead() на ESP32 зручний, але неточний: до ~0.1 В він показує нуль, вище ~3.1 В — максимум, а посередині помиляється на десятки мілівольт. Для індикатора заряду чи потенціометра цього досить, для вимірювального приладу — ні. ADS1115 — 16-бітний АЦП із програмованим підсилювачем і власним джерелом опорної напруги: 4 входи, I2C і похибка в частки відсотка. Порівнюємо його з вбудованим АЦП і робимо вольтметр для 12-вольтового акумулятора.
Що знадобиться
- ESP32 DevKit
- Модуль ADS1115 (фіолетова плата)
- Потенціометр 10 кОм
- Резистори 100 кОм і 22 кОм для дільника
- Бібліотека Adafruit ADS1X15
Схема
| ADS1115 | Підключення |
|---|---|
| VDD / GND | 3V3 / GND |
| SDA / SCL | GPIO21 / GPIO22 |
| ADDR | GND → адреса 0x48 |
| A0 | повзунок потенціометра (він же на GPIO34 для порівняння) |
| A1 | середня точка дільника 100 кОм / 22 кОм від «+12 В» |
Потенціометр: крайні виводи на 3V3 і GND. Дільник: «+12 В» → 100 кОм → A1 → 22 кОм → GND, земля акумулятора з'єднана з GND ESP32.
Налаштування підсилювача (GAIN)
Діапазон вимірювань задає setGain():
| GAIN | Діапазон | Крок (16 біт) |
|---|---|---|
GAIN_TWOTHIRDS |
±6.144 В | 0.1875 мВ |
GAIN_ONE |
±4.096 В | 0.125 мВ |
GAIN_TWO (за замовч.) |
±2.048 В | 0.0625 мВ |
GAIN_FOUR … GAIN_SIXTEEN |
±1.024 … ±0.256 В | до 0.0078 мВ |
Важливо: діапазон ±6.144 В не означає, що на вхід можна подати 6 В. Напруга на будь-якому вході не може виходити за межі GND − 0.3 В … VDD + 0.3 В. При живленні 3.3 В це максимум 3.6 В. Усе більше — тільки через дільник. Симулятор попередить про перевищення.
Розрахунок дільника
U(вх) = U(бат) × R2 / (R1 + R2) = 14.4 × 22 / 122 ≈ 2.6 В навіть для акумулятора на зарядці (14.4 В) — із запасом у діапазоні ±4.096 В. У коді множимо назад на (100 + 22) / 22. Дільник на 122 кОм бере з акумулятора лише ~0.1 мА.
Код
// Вольтметр: ADS1115 (16 біт) проти вбудованого АЦП ESP32 + напруга акумулятора
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1115 ads;
const float DIVIDER = (100.0 + 22.0) / 22.0; // дільник 100 кОм / 22 кОм на A1
void setup() {
Serial.begin(115200);
ads.setGain(GAIN_ONE); // ±4.096 В, крок 0.125 мВ
if (!ads.begin(0x48)) {
Serial.println("ADS1115 не знайдено");
while (true) delay(1000);
}
}
void loop() {
float pot = ads.computeVolts(ads.readADC_SingleEnded(0));
float naive = analogRead(34) * 3.3 / 4095.0; // «наївний» перерахунок
float mv = analogReadMilliVolts(34) / 1000.0; // з заводською калібровкою
float battery = ads.computeVolts(ads.readADC_SingleEnded(1)) * DIVIDER;
Serial.printf("A0: ADS1115 %.4f В | analogRead %.3f В | analogReadMilliVolts %.3f В\n", pot, naive, mv);
Serial.printf("Акумулятор: %.3f В\n", battery);
delay(1000);
}
Що побачите
Покрутіть потенціометр до краю. Біля нуля ESP32 показує 0 В, коли ADS1115 ще бачить 0.05 В, а біля 3.3 В вбудований АЦП «впирається» в 3.1 В. analogReadMilliVolts() помітно краще за наївну формулу, але шум ±10–20 мВ залишається.
Корисно знати
- Швидкість. За замовчуванням 128 вимірювань на секунду (~8 мс на одне).
setDataRate(RATE_ADS1115_860SPS)— швидше, але шумніше. - Диференційний режим
readADC_Differential_0_1()міряє різницю між A0 і A1, наприклад на шунті для вимірювання струму. - ADS1015 — 12-бітний брат із тією ж розпіновкою: у коді клас
Adafruit_ADS1015. Переплутаєте класи — отримаєте результати, зсунуті в 16 разів. - Чотири ADS1115 на одній шині: ADDR до GND, VDD, SDA або SCL дає адреси 0x48–0x4B.