Аналоговые входы ESP32: особенности, подводные камни и калибровка

ADC (Analog-to-Digital Converter) в ESP32 позволяет считывать аналоговые сигналы (напряжение) и переводить их в цифровые значения. Это основа для работы с потенциометрами, фоторезисторами, датчиками напряжения аккумулятора и др.

Особенности АЦП ESP32

  • Количество каналов: до 18 входов (ADC1 и ADC2). Часть входов (ADC2) недоступна при активном Wi-Fi/BT, т.к. блок разделяется с радиомодулем.
  • Разрядность: 12 бит (диапазон отсчётов 0…4095).
  • Диапазон напряжений: обычно 0…3,3 В (зависит от выбранной аттенюации). Типовая аттенюация ADC_11db позволяет измерять до ≈3,6 В (рекомендуется придерживаться 3,3 В).

Таблица пинов ADC (ESP32)

Примечание: пины ADC2 недоступны при включённом Wi-Fi/BT. Пины GPIO34…GPIO39 — только вход, без внутренних подтяжек.

Блок Канал GPIO Доступен при Wi-Fi/BT Особенности
ADC1 CH0 GPIO36 (VP) Да Только вход
ADC1 CH1 GPIO37 Да Только вход
ADC1 CH2 GPIO38 Да Только вход
ADC1 CH3 GPIO39 (VN) Да Только вход
ADC1 CH4 GPIO32 Да  
ADC1 CH5 GPIO33 Да  
ADC1 CH6 GPIO34 Да Только вход
ADC1 CH7 GPIO35 Да Только вход
ADC2 CH0 GPIO4 Нет Страп/переферия на некоторых платах
ADC2 CH1 GPIO0 Нет Стартовый пин (boot)
ADC2 CH2 GPIO2 Нет Стартовый пин (boot)
ADC2 CH3 GPIO15 Нет Стартовый пин (boot)
ADC2 CH4 GPIO13 Нет  
ADC2 CH5 GPIO12 Нет Страп VDD_SDIO (осторожно!)
ADC2 CH6 GPIO14 Нет  
ADC2 CH7 GPIO27 Нет  
ADC2 CH8 GPIO25 Нет  
ADC2 CH9 GPIO26 Нет  

Итог: для стабильных измерений при активном Wi-Fi/BT используйте каналы ADC1 (GPIO32…GPIO39).

Пример программы (базовое чтение)


// Пример: чтение с ADC1 GPIO34 (только вход)
#include <Arduino.h>

const int adcPin = 34; // ADC1_CH6

void setup() {
  Serial.begin(115200);
  // Настройка ширины и аттенюации (опционально для Arduino-ESP32 core)
  analogReadResolution(12);                 // 0..4095
  analogSetPinAttenuation(adcPin, ADC_11db); // до ≈3.6 В (реалистично 3.3 В)
}

void loop() {
  int raw = analogRead(adcPin);
  // Грубая оценка напряжения (без калибровки):
  float v = (float)raw / 4095.0f * 3.30f; // если питание 3.3 В
  Serial.printf("RAW=%d  V=%.3f V\n", raw, v);
  delay(250);
}
  

Настройка ADC: analogReadResolution и analogSetPinAttenuation

Для более гибкой работы с АЦП в ESP32 можно использовать дополнительные функции настройки:

analogReadResolution()

Эта функция позволяет задать разрядность результата преобразования. По умолчанию ESP32 работает с 12 бит (значения от 0 до 4095). В некоторых случаях можно уменьшить точность для ускорения обработки или упрощения вычислений.

  • analogReadResolution(9) → диапазон 0–511.
  • analogReadResolution(10) → диапазон 0–1023.
  • analogReadResolution(11) → диапазон 0–2047.
  • analogReadResolution(12) → диапазон 0–4095 (рекомендуется).

analogSetPinAttenuation()

Эта функция позволяет изменять аттенюацию (ослабление сигнала), чтобы адаптировать входной диапазон напряжений для конкретного пина. По умолчанию ESP32 измеряет напряжение примерно в пределах 0–1.1 В, но диапазон можно расширить.

  • ADC_0db → диапазон 0–1.1 В (по умолчанию, наибольшая точность).
  • ADC_2_5db → диапазон 0–1.5 В.
  • ADC_6db → диапазон 0–2.2 В.
  • ADC_11db → диапазон 0–3.3 В (для работы с полным диапазоном питания).

Пример кода


#include <Arduino.h>

void setup() {
  Serial.begin(115200);

  // Устанавливаем разрядность 12 бит (0–4095)
  analogReadResolution(12);

  // Расширяем диапазон измерения пина 34 до 3.3 В
  analogSetPinAttenuation(34, ADC_11db);
}

void loop() {
  int val = analogRead(34);
  Serial.println(val);
  delay(500);
}

Таким образом можно настроить точность и диапазон измерения для каждого аналогового входа ESP32 отдельно.

Пример программы с программным фильтром сигнала

Для подавления шума применим скользящее среднее и медианный фильтр.


#include <Arduino.h>

const int adcPin = 34;         // ADC1_CH6
const int N = 15;              // размер окна усреднения
int buf[N];
int idx = 0;
bool filled = false;

int median3(int a, int b, int c) { // медиана из 3
  if ((a <= b && b <= c) || (c <= b && b <= a)) return b;
  if ((b <= a && a <= c) || (c <= a && a <= b)) return a;
  return c;
}

void setup() {
  Serial.begin(115200);
  analogReadResolution(12);
  analogSetPinAttenuation(adcPin, ADC_11db);
}

void loop() {
  // Медиана по 3 мгновенным отсчётам
  int r1 = analogRead(adcPin);
  int r2 = analogRead(adcPin);
  int r3 = analogRead(adcPin);
  int med = median3(r1, r2, r3);

  // Скользящее среднее
  buf[idx] = med;
  idx = (idx + 1) % N;
  if (idx == 0) filled = true;

  long sum = 0;
  int count = filled ? N : idx;
  for (int i = 0; i < count; i++) sum += buf[i];
  int avg = (int)(sum / max(1, count));

  float v = (float)avg / 4095.0f * 3.30f;
  Serial.printf("RAW_med=%d   AVG=%d   V=%.3f V\n", med, avg, v);
  delay(50);
}
  

Подводные камни ESP32 ADC

  • Нелинейность: реальное напряжение часто не совпадает с идеальной прямой преобразования, особенно на краях диапазона или при разных аттенюациях.
  • Влияние Wi-Fi: активный Wi-Fi/BT делает ADC2 недоступным и добавляет помехи. Для стабильных измерений используйте ADC1.
  • Разные характеристики ADC1/ADC2: шум, чувствительность и доступность отличаются. Рекомендация: для ответственных измерений — только ADC1.

Калибровка и улучшение точности

Калибровка через esp_adc_cal

Для учёта нелинейности и реального опорного напряжения используйте API esp_adc_cal (работает и из Arduino-ядра).


// Калиброванное измерение в мВ с esp_adc_cal
#include <Arduino.h>
#include "esp_adc_cal.h"
#include "driver/adc.h"

#define ADC_CHANNEL   ADC1_CHANNEL_6   // GPIO34
#define ADC_UNIT      ADC_UNIT_1
#define ADC_ATTEN     ADC_ATTEN_DB_11  // до ~3.6 В
#define ADC_WIDTH     ADC_WIDTH_BIT_12

esp_adc_cal_characteristics_t adc_chars;

void setup() {
  Serial.begin(115200);

  // Настройка ширины/аттенюации низкоуровневым API
  adc1_config_width(ADC_WIDTH);
  adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN);

  // Характеризация (калибровка): eFuse -> Two Point/ Vref / Default
  esp_adc_cal_value_t cal = esp_adc_cal_characterize(
      ADC_UNIT, ADC_ATTEN, ADC_WIDTH, 1100, &adc_chars); // 1100 мВ дефолтный Vref

  Serial.printf("Calibration source: %d (0:TwoPoint 1:eFuseVref 2:Default)\n", cal);
}

void loop() {
  uint32_t raw = adc1_get_raw(ADC_CHANNEL);
  uint32_t mv  = esp_adc_cal_raw_to_voltage(raw, &adc_chars); // в мВ
  Serial.printf("RAW=%lu  V=%lu mV\n", raw, mv);
  delay(200);
}
  

Как отключать/включать ADC для экономичности

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


#include "driver/adc.h"

void adcPowerSaveExample() {
  // Выключить блок АЦП
  adc_power_off();      // отключает питание ADC (оба блока)
  // ... выполнить другие действия/сон ...
  adc_power_on();       // включить обратно перед чтением
}
  

Советы: отключайте Wi-Fi/BT на время критических измерений; делайте серию быстрых чтений (burst) и усредняйте; подбирайте аттенюацию ADC_0db/2_5db/6db/11db под ваш диапазон.

Выводы

  • Для бытовых задач (потенциометр, LDR, мониторинг батареи с делителем) — ADC1 с фильтрацией и калибровкой даёт достаточную точность.
  • При активном Wi-Fi/BT используйте только ADC1 и уменьшайте помехи (экранирование, фильтры, усреднение).
  • Для задач, где важны высокая точность, повторяемость и линейность (прецизионные датчики), целесообразно применить внешний АЦП с опорным источником (MCP3201/ADS1115/ADS1015 и т.п.).
<< Проекты << Все товары >> Статьи, уроки >>

Написать отзыв

Примечание: HTML разметка не поддерживается! Используйте обычный текст.
    Плохо           Хорошо
Оптопара EL817 SMD

Оптопара EL817 SMD

Оптопара с транзистором на выходеПрименяется для гальванической развязки дискретного сигнала, а так ..

4.28грн.

Разработка систем мониторинга: температура, вес, расход воды, влажность

Разработка систем мониторинга: температура, вес, расход воды, влажность

Современный бизнес, сельское хозяйство и промышленность всё чаще нуждаются не просто в электронике..

Какие виды датчиков можно подключить к Arduino для измерения параметров окружающей среды

Какие виды датчиков можно подключить к Arduino для измерения параметров окружающей среды

Какие виды датчиков можно подключить к Arduino для измерения параметров окружающей среды Ar..

STM32F103CBT6 микроконтроллер QFP-48

STM32F103CBT6 микроконтроллер QFP-48

Микроконтроллер STM32F103CBT6 в корпусе QFP-48..

259.68грн.

Arduino закачивание детской кроватки по крику

Arduino закачивание детской кроватки по крику

Привет друзья!  Представляю интересный проект для новоиспеченных папочек. Это - автоматическ..