Se rendre au contenu

Le variateur AC TRIAC n'est pas du PWM : comment fonctionne la variation par découpe de phase

analogWrite ou ledc sur la broche DIM de votre variateur AC donne simplement la pleine luminosité — le TRIAC ne répond pas au PWM. La variation par découpe de phase nécessite un signal de passage par zéro et une bibliothèque appropriée. Expliqué avec des schémas ASCII et du code fonctionnel.

En bref : analogWrite() et le PWM ne fonctionnent pas avec un variateur AC TRIAC. Un TRIAC n'est ni une résistance ni un transistor DC. Il régule la puissance par commande de phase : il s'ouvre à un moment précisément calculé de chaque demi-cycle, synchronisé avec le signal de passage par zéro. Sans passage par zéro et la bonne bibliothèque — la charge sera seulement en marche ou à l'arrêt, sans valeurs intermédiaires.



Description du problème

Vous avez connecté un variateur AC, trouvé la broche DIM — et essayé de le contrôler avec analogWrite() comme une sortie PWM classique. Ou utilisé ledc sur ESP32. Résultat : la charge est soit à 100 %, soit complètement éteinte. Aucune luminosité intermédiaire.

Parfois le comportement est encore plus inattendu :

  • À faibles valeurs PWM, la charge ne s'allume pas du tout
  • À valeurs élevées — elle passe directement à pleine puissance
  • Une valeur de 50 % (128 sur 255) ne donne pas 50 % de luminosité

Ce n'est pas un bug dans le code ni un module défectueux. C'est une incompatibilité fondamentale entre la méthode de contrôle et le type de charge.

Situations typiques sur les forums :

  • « J'ai connecté la broche DIM du variateur au PWM, analogWrite(128), mais la lampe est à fond »
  • « PWM essayé sur un variateur TRIAC, mais aucun effet de variation »
  • « ESP32 ledc sur la broche du variateur — la lumière s'allume et s'éteint, c'est tout »
  • « Pourquoi analogWrite ne fonctionne pas avec le variateur AC ? »
  • Broche ZC pas connectée du tout — seulement DIM sur une sortie PWM



Cause profonde


PWM — pour le courant continu (DC)

Le PWM (modulation de largeur d'impulsion) contrôle la puissance par commutation rapide : un transistor s'ouvre et se ferme des milliers de fois par seconde, et la charge reçoit une tension moyenne proportionnelle au rapport cyclique.

text
PWM 50 % rapport cyclique (charge DC — ruban LED, moteur, chauffage DC) :
Tension :
 ┌──┐  ┌──┐  ┌──┐  ┌──┐  ┌──┐
─┘  └──┘  └──┘  └──┘  └──┘  └─
│←ON→│←OFF→│   ← fréquence 1–20 kHz
Puissance moyenne = 50 % ✅

Cela fonctionne parce qu'une charge DC réagit à la tension moyenne. Un chauffage chauffe à puissance moyenne ; une LED clignote assez vite pour que l'œil ne le remarque pas.


TRIAC — pour le courant alternatif (AC) : fonctionne différemment

Un TRIAC est un thyristor bidirectionnel pour l'AC. Il se comporte de manière fondamentalement différente :

  1. Se verrouille — une fois que le courant commence à circuler (et dépasse le courant de maintien), le TRIAC reste ouvert jusqu'à la fin du demi-cycle, même si le signal de gâchette est retiré.
  2. S'éteint automatiquement au passage par zéro de la sinusoïde — quand le courant tombe sous le courant de maintien.
  3. Ne répond pas au PWM rapide : une seule impulsion de gâchette de n'importe quelle durée ouvre le TRIAC jusqu'à la fin du demi-cycle. 10 µs ou 5 ms — le résultat est le même.
text
Sinusoïde AC (50 Hz) :
    ╭──────╮         ╭──────╮
    │      │         │      │
────╯      ╰────────╯      ╰────
    ↑      ↑         ↑      ↑
   ZC    ZC(-)      ZC    ZC(-)
   (100 impulsions par seconde)
text
TRIAC s'ouvre au ZC — la charge reçoit le demi-cycle COMPLET (100 %) :
    ╭──────╮         ╭──────╮
    │//////│         │//////│
────╯      ╰────────╯      ╰────
↑ s'ouvre              ↑ s'ouvre au ZC
text
TRIAC s'ouvre avec 5 ms de délai — la charge reçoit la MOITIÉ du demi-cycle (~50 %) :
    ──────╮         ──────╮
          │               │
    ──────╯────────  ─────╯──────
    ↑     ↑          ↑    ↑
   ZC   s'ouvre     ZC  s'ouvre
        (après 5 ms)     (après 5 ms)


Pourquoi le PWM « ne voit pas » le TRIAC

Lorsque vous appliquez 50 % de PWM (par ex. 500 Hz) sur la broche DIM du TRIAC :

  • Le PWM commute 500 fois par seconde
  • La première impulsion HIGH ouvre le TRIAC
  • Les impulsions LOW suivantes n'ont aucun effet — le TRIAC est déjà verrouillé
  • Il reste ouvert jusqu'à la fin du demi-cycle (10 ms à 50 Hz)
  • La charge se retrouve à pleine puissance

Pas de passage par zéro — pas de timing — pas de variation.



Tableau : PWM vs découpe de phase

Paramètre PWM (DC) Découpe de phase (AC TRIAC)
Type de signal Commutation continue Impulsion de gâchette unique
ZC nécessaire ? Non Oui — obligatoire
Bibliothèque nécessaire ? Non (analogWrite) Oui
Type de charge DC (ruban LED, moteur, chauffage) AC (lampe, halogène, chauffage)
Méthode de contrôle Rapport cyclique Délai de gâchette relatif au ZC
Fréquence de commutation 1–20 kHz 100–120 Hz (une fois par demi-cycle)
Plage de fonctionnement 0–100 % ~10–95 % (limitation du TRIAC)



Solutions



🟢 Pour les débutants : DimmerLink — branchez et utilisez

Vous ne voulez pas vous occuper du passage par zéro, de l'angle de phase et des ISR ? DimmerLink gère toute la logique en interne — il suffit de définir un niveau.

❌ non supporté 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.

Quand choisir :

  • ☐ Vous voulez simplement régler la luminosité sans apprendre la découpe de phase
  • ☐ Raspberry Pi (pas de temps réel pour les ISR)
  • ☐ ESP32-S2/C3/H2 (simple cœur, ISR non supporté)
  • ☐ Besoin d'un contrôle WiFi/MQTT simultané sans plantages
  • Câblage :

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

    Code :

    cpp
    // DimmerLink — régler la luminosité comme une simple valeur 0–100
    // Pas de PWM, passage par zéro ou ISR — tout est géré dans DimmerLink
    // Doc : 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);    // éteint
        delay(2000);
        setLevel(50);   // luminosité 50 %
        delay(2000);
        setLevel(100);  // pleine luminosité
    }
    void loop() {}


    🔵 Pour les utilisateurs avancés : commande de phase correcte

    Vous voulez travailler directement avec le variateur sans DimmerLink ? Vous devez connecter le passage par zéro et utiliser une bibliothèque.

    Ce qu'il faut connecter :

    Broche du variateur Connecter à
    VCC 5V (Arduino) / 3.3V (ESP32)
    GND GND
    ZC Broche compatible interruption (2 ou 3 sur Arduino Uno ; tout GPIO sur ESP32)
    DIM Toute sortie numérique

    Différence clé avec le PWM : la broche DIM reçoit une seule impulsion courte (~100 µs) au bon moment, calculé par rapport au ZC. Pas de signal PWM continu.


    Option A : ESP32 avec rbdimmerESP32 ✅ Recommandé

    cpp
    // Plateforme : ESP32 double cœur
    // Bibliothèque : rbdimmerESP32 — découpe de phase, pas PWM
    // https://github.com/robotdyn-dimmer/rbdimmerESP32
    #include "rbdimmerESP32.h"
    #define ZC_PIN  18  // passage par zéro — OBLIGATOIRE
    #define DIM_PIN 19  // commande TRIAC
    rbdimmer dimmer;
    void setup() {
        dimmer.begin(ZC_PIN, DIM_PIN, 50);  // secteur 50 Hz
        dimmer.setPower(50);                 // 50 % — fonctionne par découpe de phase
    }
    void loop() {
        // Balayage progressif de luminosité
        for (int p = 10; p <= 95; p++) {
            dimmer.setPower(p);
            delay(30);
        }
        for (int p = 95; p >= 10; p--) {
            dimmer.setPower(p);
            delay(30);
        }
    }

    Ce qui se passe dans la bibliothèque :

    text
    1. L'interruption ZC se déclenche (t=0)
       ↓
    2. Calcul du délai de gâchette (front montant, 50 Hz) :
       delay_us = (100 - power%) × 78
       Exemple : 50 % → delay = 50 × 78 = 3 900 µs
       ↓
    3. Timer matériel : se déclenche après 3 900 µs
       ↓
    4. Envoi d'une impulsion courte sur DIM (~100 µs)
       ↓
    5. Le TRIAC s'ouvre et reste ouvert jusqu'au prochain ZC
    ⚠️ Plage de fonctionnement — pas 0–100 %, mais ~10–95 % :
       100 % → delay = 0 µs (s'ouvre au ZC, puissance maximale) ✅
         0 % → delay = 7 800 µs (78 % du demi-cycle) → la charge reçoit 22 %,
               pas 0 %. Pour éteindre — ne pas ouvrir le TRIAC du tout.
       < 10 % — le TRIAC s'ouvre si tard que le courant ne peut pas dépasser
               le courant de maintien → scintillement instable.
       Les bibliothèques limitent donc la plage : setPower(0) = éteint,
       setPower(1–9) ≈ 10 %, setPower(95–100) ≈ 95 %.


    Option B : Arduino Uno/Mega avec RBDdimmer

    cpp
    // Plateforme : Arduino Uno / Mega / Nano (AVR)
    // Bibliothèque : RBDdimmer — https://github.com/robotdyn/dimmer
    // ZC EST OBLIGATOIRE ! Arduino Uno : uniquement broches 2 ou 3
    #include <RBDdimmer.h>
    #define ZC_PIN   2   // passage par zéro — broche 2 (compatible interruption sur Uno)
    #define DIM_PIN  11  // commande TRIAC
    dimmerLamp dimmer(DIM_PIN, ZC_PIN);
    void setup() {
        dimmer.begin(NORMAL_MODE, ON);
        dimmer.setPower(50);  // 50 %
    }
    void loop() {}


    ⚠️ Pièges courants

    • « DIM connecté au PWM, ZC pas connecté du tout » : Sans ZC, la découpe de phase est physiquement impossible. La broche ZC est une partie obligatoire du circuit, pas une option.

    • « analogWrite(DIM_PIN, 128) — la lampe ne scintille pas, reste allumée » : C'est le comportement attendu. analogWrite ouvre le TRIAC dès la toute première impulsion HIGH et il reste verrouillé. Utilisez une bibliothèque avec ZC.

    • « Fréquence PWM réglée à 100 Hz — rien n'a changé » : Faire correspondre la fréquence PWM au taux de ZC n'aide pas. Le TRIAC se verrouille quand même au premier pulse.

    • « Le PWM fonctionnait avec une charge DC — pourquoi pas avec AC ? » : Les charges DC (rubans LED 12V, moteurs DC) utilisent un contrôle par transistor et réagissent à la tension moyenne. Le TRIAC AC est une physique différente. Voir le tableau ci-dessus.

    • « Puis-je laisser DIM en PWM juste pour allumer/éteindre ? » : Techniquement oui — vous pouvez allumer/éteindre la charge avec un simple HIGH/LOW. Mais ce n'est pas de la variation. Et sans ZC, le TRIAC peut se déclencher à un point aléatoire de la sinusoïde, causant des interférences et du stress sur le TRIAC.




    Vérification rapide

  • ☐ Broche ZC connectée à un GPIO compatible interruption ? Sans cela, rien ne fonctionne.
  • ☐ Utilisez-vous une bibliothèque avec passage par zéro (rbdimmerESP32 / RBDdimmer / DimmerLink) ?
  • ☐ Avez-vous supprimé `analogWrite()` / `ledc` de la broche DIM ?
  • ☐ Arduino Uno : ZC sur broche 2 ou 3 (pas 4, 5 ou autres) ?
  • ☐ ESP32 simple cœur (S2/C3/H2) ? → Utilisez DimmerLink.


  • Problèmes connexes

    • Passage par zéro non détectétroubleshooting/zero-cross-detection-errors.md
    • ESP32 + TRIAC : Guru Meditation Errortroubleshooting/esp32-iram-attr.md
    • Scintillement LED avec variateurload-types/led-flicker-triac-dimmer.md



    Encore des questions ?

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

    Partager cet article
    Se connecter pour laisser un commentaire.