Основы ESP32: Аналого-цифровой преобразователь (АЦП)
Эта статья из нашей серии «Основы ESP32» демонстрирует, как считывать аналоговые значения с помощью ESP32 в Arduino IDE.
Это полезно для считывания данных с самых разных датчиков и переменных компонентов, включая, помимо прочего, подстроечные резисторы, джойстики, ползунки и датчики силы нажатия (FSR).
Выводы АЦП ESP32
ESP32 включает два 12-битных АЦП типа SAR — ADC1 и ADC2 — и поддерживает измерения на 18 каналах (выводы с поддержкой аналогового входа). ADC1 доступен на восьми GPIO (32–39), а ADC2 — на десяти GPIO (0, 2, 4, 12–15 и 25–27).
Однако плата DEVKIT V1 DOIT (версия с 30 GPIO) имеет только 15 каналов АЦП, как показано на рисунке ниже.
АЦП в вашем ESP32 имеет разрешение 12 бит, что означает, что он может определять 4096 (2^12) дискретных аналоговых уровней. Другими словами, он преобразует входные напряжения в диапазоне от 0 до 3,3 В (рабочее напряжение) в целые числа в диапазоне от 0 до 4095. Это даёт разрешение 3,3 вольта / 4096 единиц, или 0,0008 вольт (0,8 мВ) на единицу.
Кроме того, разрешение АЦП и диапазон канала могут быть настроены программно.
Ограничения АЦП ESP32
Если быть честным, АЦП — не самая сильная сторона ESP32. Существует несколько ограничений, о которых следует знать.
Невозможность использования при включённом WiFi
Выводы ADC2 нельзя использовать, когда включён Wi-Fi. Поскольку велика вероятность использования WiFi на микроконтроллере, предназначенном для этого, фактически можно использовать только ADC1.
Диапазон входного напряжения АЦП
АЦП ESP32 может измерять напряжения только в диапазоне от 0 до 3,3 В. Вы не можете напрямую измерять аналоговое напряжение в диапазоне от 0 до 5 В.
Точность АЦП
В идеале вы ожидаете линейное поведение при использовании АЦП, но это не так. Преобразователи АЦП на ESP32 имеют нелинейную природу. Более подробную информацию об этом можно найти в обсуждении на GitHub.
На графике ниже отчётливо видны нелинейности на нижнем и верхнем концах диапазона входного напряжения.
По сути, это означает, что ESP32 не может отличить 3,2 В от 3,3 В; измеренное значение будет одинаковым (4095). Точно так же он не может различить сигналы 0 В и 0,13 В; измеренное значение будет одинаковым (0).
Электрический шум
Электрический шум АЦП подразумевает небольшие колебания измерений.
Однако это можно скорректировать, добавив конденсатор на выходе и применив передискретизацию (oversampling).
Функция analogRead()
Считывание аналоговых значений с вывода GPIO выполняется просто. В Arduino IDE для этого используется функция analogRead(), которая принимает в качестве аргумента номер GPIO-вывода, который вы хотите прочитать.
analogRead(GPIO);
Считывание потенциометра
Чтобы продемонстрировать использование АЦП на ESP32, мы воспользуемся простым примером — считыванием аналогового значения с потенциометра.
Подключение оборудования
Давайте соберём простую схему с потенциометром для этого примера.
Начните с установки потенциометра на макетную плату. Подключите средний вывод к GPIO 34 на вашем ESP32. Наконец, подключите один из крайних выводов потенциометра — неважно какой — к выводу 3V3 ESP32, а другой — к земле (GND).
Пример кода
Загрузите следующий скетч на ваш ESP32. Этот скетч просто считывает значение потенциометра и выводит результаты в монитор последовательного порта.
// Potentiometer is connected to GPIO 34 (Analog ADC1_CH6)
const int potPin = 34;
// variable for storing the potentiometer value
int potValue = 0;
void setup() {
Serial.begin(115200);
delay(1000);
}
void loop() {
// Reading potentiometer value
potValue = analogRead(potPin);
Serial.print("Analog value: ");
Serial.println(potValue);
delay(500);
}
После загрузки скетча откройте монитор последовательного порта со скоростью 115200 бод и нажмите кнопку EN на ESP32.
Вы должны увидеть значение от 0 до 4095, зависящее от текущего положения ручки потенциометра, выводимое в монитор последовательного порта. Попробуйте повернуть ручку потенциометра, чтобы увидеть, как меняются значения.
Объяснение кода
Скетч начинается с определения GPIO-вывода, к которому подключён потенциометр, — в данном случае это GPIO 34.
const int potPin = 34;
Также определяется переменная для хранения значений потенциометра.
int potValue = 0;
В функции setup() мы инициализируем последовательную связь с ПК.
Serial.begin(115200);
В цикле loop() функция analogRead() используется для считывания напряжения на выводе potPin. Возвращённое значение сохраняется в переменной potValue.
potValue = analogRead(potPin);
Наконец, значения, считанные с потенциометра, выводятся в монитор последовательного порта.
Serial.print("Analog value: ");
Serial.println(potValue);
Примечание
potPin не нужно устанавливать как вход. Это делается автоматически каждый раз, когда вы вызываете analogRead().
Другие функции АЦП
Существуют и другие функции АЦП, которые могут быть полезны в других проектах:
analogReadMilliVolts(pin): получает значение АЦП для заданного вывода/канала АЦП в милливольтах.analogReadResolution(bits): устанавливает разрядность и разрешение считывания. По умолчанию — 12 бит. Диапазон: от 9 (0–511) до 12 бит (0–4095).analogSetWidth(bits): устанавливает аппаратную разрядность и разрешение считывания. По умолчанию — 12 бит. Диапазон: от 9 до 12 бит. 9 бит = 0–511, 10 бит = 0–1023, 11 бит = 0–2047 и 12 бит = 0–4095.analogSetCycles(cycles): устанавливает количество циклов на выборку. По умолчанию — 8. Диапазон: от 1 до 255.analogSetSamples(samples): устанавливает количество выборок в диапазоне. По умолчанию — 1 выборка. Увеличение количества повышает чувствительность.analogSetClockDiv(clockDiv): устанавливает делитель тактовой частоты АЦП. По умолчанию — 1. Диапазон: от 1 до 255.analogSetAttenuation(attenuation): устанавливает входное ослабление для всех выводов АЦП. По умолчанию —ADC_11db. Допустимые значения:ADC_0db: без ослабления (диапазон измеряемого входного напряжения = 100 мВ ~ 950 мВ).ADC_2_5db: ослабление 1,34 (диапазон измеряемого входного напряжения = 100 мВ ~ 1250 мВ).ADC_6db: ослабление 1,5 (диапазон измеряемого входного напряжения = 150 мВ ~ 1750 мВ).ADC_11db: ослабление 3,6 (диапазон измеряемого входного напряжения = 150 мВ ~ 2450 мВ).
analogSetPinAttenuation(pin, attenuation): эта функция аналогична предыдущей, за исключением того, что устанавливает входное ослабление для указанного вывода.adcAttachPin(pin): подключает вывод к АЦП (а также очищает любой другой аналоговый режим, который может быть активен) и возвращает true в случае успешной настройки, иначе возвращает false.adcStart(pin): запускает преобразование АЦП на шине подключённого вывода.adcBusy(pin): проверяет, выполняется ли в данный момент преобразование на шине АЦП вывода (возвращает TRUE или FALSE).resultadcEnd(pin): получает результат преобразования (ожидает, если АЦП ещё не завершил работу), возвращает 16-битное целое число.
Более подробную информацию можно найти на readthedocs.