Перейти к содержимому

AC TRIAC-диммер — это не PWM: как работает диммирование с фазовой отсечкой

analogWrite или ledc на пин DIM вашего AC-диммера просто даёт полную яркость — TRIAC не реагирует на PWM. Для диммирования с фазовой отсечкой нужен сигнал перехода через ноль и подходящая библиотека. Объяснение с ASCII-диаграммами и рабочим кодом.

Кратко: analogWrite() и PWM не работают с AC TRIAC-диммером. TRIAC — это не резистор и не DC-транзистор. Он регулирует мощность с помощью фазового управления: открывается в точно рассчитанный момент каждого полупериода, синхронизируясь с сигналом перехода через ноль. Без перехода через ноль и правильной библиотеки нагрузка будет только полностью включена или полностью выключена — без промежуточных значений.



Описание проблемы

Вы подключили AC-диммер, нашли пин DIM — и попытались управлять им через analogWrite(), как обычным PWM-выходом. Или использовали ledc на ESP32. Результат: нагрузка либо на 100%, либо полностью выключена. Промежуточной яркости нет.

Иногда поведение ещё более неожиданное:

  • При малых значениях PWM нагрузка вообще не включается
  • При больших значениях — сразу выходит на полную мощность
  • Значение 50% (128 из 255) не даёт яркости 50%

Это не ошибка кода и не неисправность модуля. Это фундаментальное несоответствие между методом управления и типом нагрузки.

Типичные ситуации на форумах:

  • «Подключил DIM-пин диммера к PWM, analogWrite(128), а лампа на полной мощности»
  • «Пробовал PWM на TRIAC-диммере, но нет эффекта диммирования»
  • «ESP32 ledc на пине диммера — свет просто включается и выключается»
  • «Почему analogWrite не работает с AC-диммером?»
  • Пин ZC вообще не подключён — только DIM на PWM-выходе



Причина проблемы


PWM — для постоянного тока (DC)

PWM (широтно-импульсная модуляция) управляет мощностью путём быстрого переключения: транзистор открывается и закрывается тысячи раз в секунду, и нагрузка получает среднее напряжение, пропорциональное скважности.

text
PWM 50% скважность (DC-нагрузка — LED-лента, двигатель, DC-нагреватель):
Напряжение:
 ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐
─┘  └──┘  └──┘  └──┘  └──┘  └─
│←ВКЛ→│←ВЫКЛ→│   ← частота 1–20 кГц
Средняя мощность = 50% ✅

Это работает, потому что DC-нагрузка реагирует на среднее напряжение. Нагреватель греет при средней мощности; светодиод мерцает достаточно быстро, чтобы глаз не замечал.


TRIAC — для переменного тока (AC): работает иначе

TRIAC — это кремниевый управляемый выпрямитель для AC. Он ведёт себя принципиально иначе:

  1. Фиксируется — как только ток начинает протекать (и превышает ток удержания), TRIAC остаётся открытым до конца полупериода, даже если сигнал на затворе снят.
  2. Самовыключается при переходе синусоиды через ноль — когда ток падает ниже тока удержания.
  3. Не реагирует на быстрый PWM: одиночный импульс на затворе любой длительности открывает TRIAC до конца полупериода. 10 мкс или 5 мс — результат одинаков.
text
Синусоида AC (50 Гц):
    ╭──────╮         ╭──────╮
    │      │         │      │
────╯      ╰────────╯      ╰────
    ↑      ↑         ↑      ↑
   ZC    ZC(-)      ZC    ZC(-)
   (100 импульсов в секунду)
text
TRIAC открывается при ZC — нагрузка получает ПОЛНЫЙ полупериод (100%):
    ╭──────╮         ╭──────╮
    │//////│         │//////│
────╯      ╰────────╯      ╰────
↑ открыт              ↑ открыт при ZC
text
TRIAC открывается с задержкой 5 мс — нагрузка получает ПОЛОВИНУ полупериода (~50%):
    ──────╮         ──────╮
          │               │
    ──────╯────────  ─────╯──────
    ↑     ↑          ↑    ↑
   ZC   открыт      ZC  открыт
        (через 5 мс)     (через 5 мс)


Почему PWM «не видит» TRIAC

Когда вы подаёте 50% PWM (например, 500 Гц) на пин DIM TRIAC:

  • PWM переключается 500 раз в секунду
  • Первый импульс HIGH открывает TRIAC
  • Последующие LOW-импульсы ничего не значат — TRIAC уже зафиксирован
  • Он остаётся открытым до конца полупериода (10 мс при 50 Гц)
  • Нагрузка оказывается на полной мощности

Нет перехода через ноль — нет тайминга — нет диммирования.



Таблица: PWM vs фазовая отсечка

Параметр PWM (DC) Фазовая отсечка (AC TRIAC)
Тип сигнала Непрерывное переключение Одиночный импульс на затвор
Нужен ZC? Нет Да — обязательно
Нужна библиотека? Нет (analogWrite) Да
Тип нагрузки DC (LED-лента, мотор, нагреватель) AC (лампа, галогенная, нагреватель)
Метод управления Скважность импульса Задержка затвора относительно ZC
Частота переключения 1–20 кГц 100–120 Гц (раз в полупериод)
Рабочий диапазон 0–100% ~10–95% (ограничение TRIAC)



Решения



🟢 Для начинающих: DimmerLink — подключил и работай

Не хотите разбираться с переходом через ноль, фазовым углом и ISR? DimmerLink берёт всю логику на себя — просто задайте уровень.

Любой ESP32 is a controller with its own zero-cross detector and TRIAC phase control. Your microcontroller only sends a brightness level (0–100%) via I2C or UART. No PWM, no zero-cross on the MCU side.

Когда выбрать:

  • ☐ Хотите просто задать яркость без изучения фазовой отсечки
  • ☐ Raspberry Pi (нет реального времени для ISR)
  • ☐ ESP32-S2/C3/H2 (одноядерный, ISR не поддерживается)
  • ☐ Нужно одновременное управление через WiFi/MQTT без сбоев
  • Подключение:

    text
    DimmerLink → Arduino/ESP32
    VCC → 3.3V (ESP32) / 5V (Arduino)
    GND → GND
    SDA → SDA (GPIO 21 на ESP32, A4 на Uno)
    SCL → SCL (GPIO 22 на ESP32, A5 на Uno)

    Код:

    cpp
    // DimmerLink — установка яркости как простое значение 0–100
    // Без PWM, перехода через ноль или ISR — всё обрабатывается внутри DimmerLink
    // Документация: https://www.rbdimmer.com/docs/dimmerlink-I2CCommunication
    #include <Wire.h>
    #define DIMMER_ADDR 0x50
    #define REG_LEVEL   0x10
    void setLevel(uint8_t level) {  // level: 0–100%
        Wire.beginTransmission(DIMMER_ADDR);
        Wire.write(REG_LEVEL);
        Wire.write(level);
        Wire.endTransmission();
    }
    void setup() {
        Wire.begin();
        setLevel(0);    // выключено
        delay(2000);
        setLevel(50);   // яркость 50%
        delay(2000);
        setLevel(100);  // полная яркость
    }
    void loop() {}


    🔵 Для продвинутых пользователей: правильное фазовое управление

    Хотите работать с диммером напрямую без DimmerLink? Нужно подключить переход через ноль и использовать библиотеку.

    Что нужно подключить:

    Пин диммера Куда подключать
    VCC 5V (Arduino) / 3.3V (ESP32)
    GND GND
    ZC Пин с поддержкой прерываний (2 или 3 на Arduino Uno; любой GPIO на ESP32)
    DIM Любой цифровой выход

    Ключевое отличие от PWM: пин DIM получает одиночный короткий импульс (~100 мкс) в нужный момент, рассчитанный относительно ZC. Никакого непрерывного PWM-сигнала.


    Вариант A: ESP32 с rbdimmerESP32 ✅ Рекомендуется

    cpp
    // Платформа: двухъядерный ESP32
    // Библиотека: rbdimmerESP32 — фазовая отсечка, не PWM
    // https://github.com/robotdyn-dimmer/rbdimmerESP32
    #include "rbdimmerESP32.h"
    #define ZC_PIN  18  // переход через ноль — ОБЯЗАТЕЛЬНО
    #define DIM_PIN 19  // управление TRIAC
    rbdimmer dimmer;
    void setup() {
        dimmer.begin(ZC_PIN, DIM_PIN, 50);  // сеть 50 Гц
        dimmer.setPower(50);                 // 50% — работает через фазовую отсечку
    }
    void loop() {
        // Плавное изменение яркости
        for (int p = 10; p <= 95; p++) {
            dimmer.setPower(p);
            delay(30);
        }
        for (int p = 95; p >= 10; p--) {
            dimmer.setPower(p);
            delay(30);
        }
    }

    Что происходит внутри библиотеки:

    text
    1. Срабатывает прерывание ZC (t=0)
       ↓
    2. Расчёт задержки затвора (передний фронт, 50 Гц):
       delay_us = (100 - power%) × 78
       Пример: 50% → delay = 50 × 78 = 3 900 мкс
       ↓
    3. Аппаратный таймер: срабатывает через 3 900 мкс
       ↓
    4. Отправка короткого импульса на DIM (~100 мкс)
       ↓
    5. TRIAC открывается и остаётся открытым до следующего ZC
    ⚠️ Рабочий диапазон — не 0–100%, а ~10–95%:
       100% → delay = 0 мкс (открытие при ZC, максимальная мощность) ✅
         0% → delay = 7 800 мкс (78% полупериода) → нагрузка получает 22%,
               а не 0%. Для выключения — не открывать TRIAC вообще.
       < 10% — TRIAC открывается так поздно, что ток не может превысить
               ток удержания → нестабильное мерцание.
       Поэтому библиотеки ограничивают диапазон: setPower(0) = выкл,
       setPower(1–9) ≈ 10%, setPower(95–100) ≈ 95%.


    Вариант B: Arduino Uno/Mega с RBDdimmer

    cpp
    // Платформа: Arduino Uno / Mega / Nano (AVR)
    // Библиотека: RBDdimmer — https://github.com/robotdyn/dimmer
    // ZC ОБЯЗАТЕЛЕН! Arduino Uno: только пины 2 или 3
    #include <RBDdimmer.h>
    #define ZC_PIN   2   // переход через ноль — пин 2 (с поддержкой прерываний на Uno)
    #define DIM_PIN  11  // управление TRIAC
    dimmerLamp dimmer(DIM_PIN, ZC_PIN);
    void setup() {
        dimmer.begin(NORMAL_MODE, ON);
        dimmer.setPower(50);  // 50%
    }
    void loop() {}


    ⚠️ Частые ошибки

    • «Подключил DIM к PWM, ZC вообще не подключил»: Без ZC фазовая отсечка физически невозможна. Пин ZC — обязательная часть схемы, а не опция.

    • «analogWrite(DIM_PIN, 128) — лампа не мерцает, просто горит»: Это ожидаемое поведение. analogWrite открывает TRIAC первым же HIGH-импульсом, и он остаётся зафиксированным. Используйте библиотеку с ZC.

    • «Установил частоту PWM на 100 Гц — ничего не изменилось»: Совпадение частоты PWM с частотой ZC не помогает. TRIAC всё равно фиксируется при первом импульсе.

    • «PWM работал с DC-нагрузкой — почему не работает с AC?»: DC-нагрузки (12V LED-ленты, DC-моторы) используют транзисторное управление и реагируют на среднее напряжение. AC TRIAC — это другая физика. См. таблицу выше.

    • «Можно ли оставить DIM на PWM только для включения/выключения?»: Технически да — можно включать/выключать нагрузку одним HIGH/LOW. Но это не диммирование. И без ZC TRIAC может сработать в произвольной точке синусоиды, вызывая помехи и нагрузку на TRIAC.




    Экспресс-проверка

  • ☐ Пин ZC подключён к GPIO с поддержкой прерываний? Без этого ничего не работает.
  • ☐ Используете библиотеку с переходом через ноль (rbdimmerESP32 / RBDdimmer / DimmerLink)?
  • ☐ Убрали `analogWrite()` / `ledc` с пина DIM?
  • ☐ Arduino Uno: ZC на пине 2 или 3 (не 4, 5 или другие)?
  • ☐ Одноядерный ESP32 (S2/C3/H2)? → Используйте DimmerLink.


  • Связанные проблемы

    • Переход через ноль не определяетсяtroubleshooting/zero-cross-detection-errors.md
    • ESP32 + TRIAC: Guru Meditation Errortroubleshooting/esp32-iram-attr.md
    • Trailing vs Leading Edgeload-types/trailing-vs-leading-edge.md



    Остались вопросы?

    Ask on forum.rbdimmer.com or open a GitHub Issue.

    Поделиться этой записью
    Войти оставить комментарий