Кратко:
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 (широтно-импульсная модуляция) управляет мощностью путём быстрого переключения: транзистор открывается и закрывается тысячи раз в секунду, и нагрузка получает среднее напряжение, пропорциональное скважности.
PWM 50% скважность (DC-нагрузка — LED-лента, двигатель, DC-нагреватель):
Напряжение:
┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐
─┘ └──┘ └──┘ └──┘ └──┘ └─
│←ВКЛ→│←ВЫКЛ→│ ← частота 1–20 кГц
Средняя мощность = 50% ✅Это работает, потому что DC-нагрузка реагирует на среднее напряжение. Нагреватель греет при средней мощности; светодиод мерцает достаточно быстро, чтобы глаз не замечал.
TRIAC — для переменного тока (AC): работает иначе
TRIAC — это кремниевый управляемый выпрямитель для AC. Он ведёт себя принципиально иначе:
- Фиксируется — как только ток начинает протекать (и превышает ток удержания), TRIAC остаётся открытым до конца полупериода, даже если сигнал на затворе снят.
- Самовыключается при переходе синусоиды через ноль — когда ток падает ниже тока удержания.
- Не реагирует на быстрый PWM: одиночный импульс на затворе любой длительности открывает TRIAC до конца полупериода. 10 мкс или 5 мс — результат одинаков.
Синусоида AC (50 Гц):
╭──────╮ ╭──────╮
│ │ │ │
────╯ ╰────────╯ ╰────
↑ ↑ ↑ ↑
ZC ZC(-) ZC ZC(-)
(100 импульсов в секунду)TRIAC открывается при ZC — нагрузка получает ПОЛНЫЙ полупериод (100%):
╭──────╮ ╭──────╮
│//////│ │//////│
────╯ ╰────────╯ ╰────
↑ открыт ↑ открыт при ZCTRIAC открывается с задержкой 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.
Когда выбрать:
Подключение:
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)Код:
// 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 ✅ Рекомендуется
// Платформа: двухъядерный 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);
}
}Что происходит внутри библиотеки:
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
// Платформа: 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.
Экспресс-проверка
Связанные проблемы
- Переход через ноль не определяется →
troubleshooting/zero-cross-detection-errors.md - ESP32 + TRIAC: Guru Meditation Error →
troubleshooting/esp32-iram-attr.md - Trailing vs Leading Edge →
load-types/trailing-vs-leading-edge.md
Остались вопросы?
Ask on forum.rbdimmer.com or open a GitHub Issue.