Не работает ШИМ-затухание светодиода ESP32

Не уверен, что это больше подходит для электронного SE, но я попробую. Я пытаюсь использовать ESP32-C3 и NPN-транзистор (2N5551) для ШИМ-управления светодиодом (параметры указаны ниже). Пробую простое плавное свечение, но светодиод не плавно затухает, а лишь плавно меняет цвет.

Я использую analogWrite (приведён ниже), но почти уверен, что код правильный. Вполне возможно, что проблема в моей пайке, но решил спросить здесь, вдруг я упускаю что-то очевидное?

Я измерил ток светодиода 100 мА при падении напряжения 2,7 В, поэтому подключил его последовательно с резистором 22 Ом. Схема ниже:

схема

    #include <Arduino.h>

    unsigned long fadeStartTime;

    void setup() {
        Serial.begin(115200);
        while(!Serial); // Ждать, пока serial станет доступен
        Serial.println("Starting");
        setCpuFrequencyMhz(80);
        LOG_INFO(MODULE_NAME, "Finished setup.");
    }

    void loop() {
        unsigned long progress = millis() - fadeStartTime;
        long brightness;
        if (progress <= 3000) brightness = map(progress, 0, 3000, 0, 255);
        else if (progress <= 6000) brightness = map(6000 - progress, 0, 3000, 0, 255);
        else fadeStartTime = millis(); // перезапустить затухание снова
        analogWrite(STEMS_DATA_PIN, brightness * brightness / 255);
    }

, 👍2

Обсуждение

Пожалуйста, приведите достаточно кода для компиляции. Похоже, затухание может происходить так быстро, что вы его не видите. Схема (эмиттерный повторитель) здесь необычна, поскольку ограничивает выходное напряжение 3,3 В. Лучше использовать резистор сопротивлением 680 Ом/1 кОм между выводом ESP32 и базой транзистора, подключить эмиттер к земле и подключить резистор/светодиод между 5 В и коллектором. В этом случае сопротивление 22 Ом будет слишком низким., @6v6gt

поместите транзистор между светодиодом и землей, @jsotola

Из-за остальной проводки, связанной с другими частями проекта, гораздо проще использовать общий заземляющий кабель с другими компонентами, поэтому транзистор не может быть идеально расположен там. Не могли бы вы вкратце объяснить, почему это лучше? Почему это ограничит выходное напряжение 3 В?, @Lorenzo

Пожалуйста, прочтите [этот ответ](https://electronics.stackexchange.com/a/303184) относительно того, почему следует использовать драйвер BJT верхнего плеча для управления светодиодом., @hcheung

Как вы показали, особенностью конфигурации «транзисторный эмиттерный повторитель» является то, что выходное напряжение ограничено напряжением базы (минус около 0,7 В). ESP32 может выдавать только 3,3 В. Вам нужно протестировать его, поискать в Google или задать вопрос на https://electronics.stackexchange.com/. Не думайте об использовании PNP-транзистора для достижения ваших целей, так как 3,3 В будет недостаточно для его выключения в 5-вольтовой схеме. Как насчёт демонстрации компилируемой версии вашего кода, которая наглядно демонстрирует вашу проблему?, @6v6gt

@6v6gt, хорошо, спасибо большое. После небольшого поиска в Google я убедился, что проблема, скорее всего, именно в этом (но я также обновил код выше)! Вы были первым, кто ответил, так что если вы напишите это как ответ, я буду рад принять его! Вот полезная ссылка, которую я нашёл, если хотите добавить: https://electronics.stackexchange.com/questions/57845/why-would-one-drive-leds-with-a-common-emitter, @Lorenzo

Хорошо, но, проверив ваш код (без тестирования), я всё ещё думаю, что исходная проблема осталась. Попробуйте добавить задержку (50) в цикл, чтобы замедлить эффект затухания., @6v6gt

ОТ: Ваше второе сопоставление можно упростить до map(progress, 3000, 6000, 255, 0), что сделает ваши намерения гораздо более понятными., @the busybee

@6v6gt Честно говоря, я очень сомневался в тебе — извини :) — но после того, как я попробовал другую схему транзисторов, у меня всё равно возникли проблемы! Добавил задержку, и всё заработало. Мне нужно, чтобы код был неблокирующим, поэтому я заменил её на if(value != lastValue), и теперь всё работает отлично! Полагаю, он слишком часто пытался выполнить analogWrite и нарушал рабочий цикл?, @Lorenzo

Хорошо, что теперь всё работает. Поскольку вы разработали рабочий код и смогли его протестировать, теперь вы можете написать свой ответ, включив этот код, и, возможно, получить несколько очков Brownie. Также воспользуйтесь возможностью объяснить это: analogWrite(STEMS_DATA_PIN, bright * bright / 255); вместо просто analogWrite(STEMS_DATA_PIN, bright );. Коэффициент заполнения будет увеличиваться нелинейно, а значения яркости <16 дадут 0 (целочисленное деление)., @6v6gt


1 ответ


Лучший ответ:

2

Полная благодарность @6v6gt и другим комментаторам за освещение этих проблем:

1. Схема транзистора неверна для NPN-транзистора.

Из-за свойств n-p-n-транзисторов, при использовании в конфигурации «эмиттерный повторитель», они выдают напряжение только на базу. В этом случае напряжение на R1+D1 будет равно всего 3,3 В от вывода GPIO ESP. Это приводит к меньшему току через светодиод, чем ожидалось. Ниже представлена правильная схема. Подробнее см. в этом ответе.

2. Код затухания был на самом деле неверным

Функция analogWrite микроконтроллера ESP работает с использованием ШИМ. Это прямоугольный сигнал с чередующимися высокими и низкими импульсами, соотношение которых определяет скважность, определяющую средний ток, протекающий через светодиод. Если эта функция вызывается слишком часто, сигнал может не пройти полный цикл импульсов «высокий-низкий», что приведёт к сплошному высокому сигналу. Это исправляется добавлением небольшой задержки delay(50), которая длиннее нескольких циклов ШИМ (в ESP частота по умолчанию составляет 1 кГц).

В моём случае код не мог блокироваться даже на таком небольшом участке, поскольку ему требовалось объединить несколько серверов, а также записать данные на другие линии GPIO для некоторых светодиодов WS2812. Простейший вариант — проверить, изменилось ли записываемое значение. Оно меняется быстро, но достаточно медленно, чтобы импульсы не мешали друг другу.


Ошибочно названо ШИМ

#include <Arduino.h>

#define DATA_PIN 0

unsigned long fadeStartTime;
unsigned long lastValue;

void setup() {
    Serial.begin(115200);
    while(!Serial); // Ждать, пока serial станет доступен
    Serial.println("Starting");
    setCpuFrequencyMhz(80);
    LOG_INFO(MODULE_NAME, "Finished setup.");
}

void loop() {
    unsigned long progress = millis() - fadeStartTime;
    long brightness;
    if (progress <= 3000) brightness = map(progress, 0, 3000, 0, 255);
    else if (progress <= 6000) brightness = map(progress, 3000, 6000, 255, 0);
    else fadeStartTime = millis(); // перезапустить затухание снова
    if(brightness != lastValue) {
        analogWrite(DATA_PIN, brightness);
        lastValue = brightness;
    };
}

schematic

,

Интересное наблюдение за поведением analogWrite() esp32. В этой конфигурации вам понадобится последовательный резистор в цепи базы транзистора (например, 680 Ом на 1 кОм). В предыдущей конфигурации эмиттерного повторителя базовый резистор был не нужен. Кроме того, если сопротивление 22 Ом для токоограничивающего резистора светодиода было правильным в предыдущей конфигурации, то в текущей конфигурации, где доступно 5 В вместо примерно 2,7 В, оно, безусловно, будет слишком низким. Это зависит от прямого напряжения светодиода и максимального тока., @6v6gt

@6v6gt Честно говоря, это моё единственное разумное предположение, почему это должно работать с задержкой. Что касается резистора, значения для светодиода указаны на схеме, 22 Ом были рассчитаны для исходных 5 В (с падением напряжения на транзисторе 0,3 В). Я также добавил базовый резистор на 150 Ом, немного погорячился, так как не слишком разбираюсь в этом, и все онлайн-калькуляторы, похоже, давали разные результаты. Отредактировал схему, чтобы добавить его., @Lorenzo

Это действительно «интересное» поведение! В AVR можно вызывать analogWrite() сколько угодно раз, и это не нарушит работу ШИМ., @Edgar Bonet

Из любопытства я только что попробовал оригинальный код автора (с минимальными необходимыми изменениями) как на Uno, так и на Espressif ESP32_C3 devkitC-02 (Arduino ESP32 Core 3.0.4), и не смог воспроизвести проблему. Похоже, функция analogWrite() в ESP32 претерпела ряд изменений. Я бегло просмотрел историю проблем с ESP32 analogWrite на GitHub (сейчас там 56 записей), так что могу предположить, что автору неудачно совпали версии платы и ядра. Тем не менее, бить по analogWrite() на скорости цикла не кажется хорошей идеей., @6v6gt

@6v6gt Думаю, это могло быть ещё и какое-то странное сочетание других проблем. Я не упоминал об этом, но мой светодиод был сильноточным (больше, чем маленький светодиод TH) и был подключён тонким проводом AWG30 длиной 30 см. Какая-то ёмкость / индуктивность / какое там ещё слово из электроники могло сыграть свою роль, ахаха., @Lorenzo