Занимаюсь проектом, на модуле ESP32 не хватило выводов! Не особо хотелось применять расширители портов на PCF8574 и ей подобные, в связи с чем пришлось городить «костыль».

DevKit v1 на базе ESP-WROOM-32, на своих выводах (pins) имеет GPIO сконфигурированные только под цифровой вход (т. е. Input), но ни как Input/Output. Это порты: GPIO34, GPIO35, GPIO36 и GPIO39.

Совсем не много ушло времени на понимание проблемы, и поиска пути решения задачи. Но перед этим стоит отметить, что мне в проекте, не хватило всего одного General Purpose Output. И благо эти pins можно конфигурировать на ADC (далее - АЦП)! Это важно!

Кратко, эти pins по своей конфигурации физически не имеют транзисторов структуры Push-Pull (которые «тянут» линию к 3V3 или к GND), а также не имеют встроенных резисторов подтяжки (Pull-up / Pull-down). Это высокоимпедансные входы High-Z, Hi-Z или по другому Off-State. Однако, управляя режимом работы входного каскада, мы можем менять его входное сопротивление и входную емкость. Физически этот «костыль» превращает входной пин в управляемый ключ, который может переключаться между двумя состояниями: очень высокое сопротивление (Hi-Z) и низкое сопротивление (режим аналогового чтения АЦП).

Схема с внешним транзистором «костыль», используем входной пин ESP32 для управления затвором чувствительного полевого транзистора (MOSFET), который, в свою очередь, коммутирует нагрузку (например, светодиод, реле или логический вход другого устройства).

Принципиальная схема

Затвор транзистора должен быть подтянут к 3V3 через достаточно большое сопротивление порядка 100k, чтобы ток уходящий в пин ESP32 в режиме АЦП, был минимальным (микроамперы) и не открыл затвор транзистора, большим напряжением, а сам транзистор должен быть с низким порогом открытия (Logic-Level MOSFET, например 2N7002 или BSS138), — это тоже ВАЖНО!

Принцип работы

Состояние ВЫСОКОГО уровня (Логическая 1):

В коде мы настраиваем GPIO34 как обычный цифровой вход (INPUT). Пин находится в состоянии высокого сопротивления. Он никак не влияет на внешнюю цепь. Через внешний резистор R97 напряжение беспрепятственно поступает на затвор транзистора. Транзистор открывается. Нагрузка на стоке включается.

Состояние НИЗКОГО уровня (Логический 0):

В коде мы переводим пин в режим аналогового ввода analogRead() или подключаем его к внутреннему блоку емкостей АЦП (с помощью низкоуровневых регистров, если требуется максимальная просадка). При включении АЦП входное сопротивление пина резко падает (цепи коммутации АЦП соединяются с землей). Ток от 3V3 через резистор R97 (100 кОм) уходит внутрь пина ESP32, подтягивая за собой затвор транзистора к pull-down. Напряжение на затворе падает ниже порогового (обычно ниже 1В, для указанных выше транзисторов). Транзистор закрывается, нагрузка выключается.

Код программы, который реализует это поведение:

const int pseudoOutputPin = 34;

void setup() {
  // Изначально переводим в INPUT (транзистор открыт, выдается "1")
  pinMode(pseudoOutputPin, INPUT); 
}

void setPseudoOutput(bool level) {
  if (level == HIGH) {
    // Режим Hi-Z: внешняя подтяжка R97 вытягивает линию вверх
    pinMode(pseudoOutputPin, INPUT);
  } else {
    // Режим АЦП: активируем внутренние цепи, сажающие линию на землю
    // Вызываем чтение, чтобы запустить коммутацию емкостей АЦП
    analogRead(pseudoOutputPin);
    
    // Для удержания низкого уровня в некоторых ревизиях ESP32 
    // может потребоваться вызывать analogRead() в цикле loop
  }
}

void loop() {
  setPseudoOutput(HIGH); // Включаем нагрузку
  delay(2000);
  
  setPseudoOutput(LOW);  // Выключаем нагрузку
  delay(2000);
}

p.s.. Собственно на этом всё! Не рекомендую использовать повсеместно, но пригодно как один из вариантов решения проблемы где не хватает Output Pins.

Комментарии (24)


  1. zhogar Автор
    09.06.2026 20:08

    Про пины, тут… https://habr.com/ru/posts/1045164/


  1. HoHIYC
    09.06.2026 20:08

    Интересное решение! Может пригодиться