4 channel dimmer board

Hi! I got a 4 channel dimmer board like this one:

[https://robotdyn.com/ac-light-dimmer-module-4-channel-3-3v-5v-logic-ac-50-60hz-220v-110v.html]HERE----->](https://robotdyn.com/ac-light-dimmer-module-4-channel-3-3v-5v-logic-ac-50-60hz-220v-110v.html)

I finally done my code in "MY" simpliest way possible. The reason is when I got only one channel program it seem to be execute faster and give less flicker in my Led Gu10 light. When active the 3 other channel thing get just a little bit anoying.

Not a huge problem but here is the question...with the documentation here:

GitHub librairy

Do you think you can do better then me for the execution of the loop ??? You'll see I send only a number to the arduino to tell wich % of light I want. I give the 1000 for the 1st channel, 2000 for the second and...

Suggestion?

#include <RBDdimmer.h>

int buftemp; 

dimmerLamp dimmer1(3); 
dimmerLamp dimmer2(4); 
dimmerLamp dimmer3(5); 
dimmerLamp dimmer4(6); 

void setup() {
  Serial.begin(9600); 
  dimmer1.begin(NORMAL_MODE, ON);  
  dimmer2.begin(NORMAL_MODE, ON);
  dimmer3.begin(NORMAL_MODE, ON);  
  dimmer4.begin(NORMAL_MODE, ON);  
  }


void loop() {
 
  if (Serial.available())  {
    buftemp = Serial.parseInt();   
   }
    
  if ((buftemp>=1005) && (buftemp<= 1095)) {
     buftemp=buftemp - 1000;
     dimmer1.setPower(buftemp); 
   }

   if ((buftemp>=2005) && (buftemp<= 2095)) {
     buftemp=buftemp - 2000;
     dimmer2.setPower(buftemp); // setPower(0-100%);
   }

   if ((buftemp>=3005) && (buftemp<= 3095)) {
     buftemp=buftemp - 3000;
     dimmer3.setPower(buftemp); // setPower(0-100%);
   }


   if ((buftemp>=4005) && (buftemp<= 4095)) {
     buftemp=buftemp - 4000;
     dimmer4.setPower(buftemp); // setPower(0-100%);
   }
       
}

don't set the value again and again. put everything in if (Serial.available()) {

I'm a bit surprised by how you are working with temps of 5-95 over a range of 1000. What happens when buftemp is 2345?

Regardless:

dimmerLamp dimmer[] = {
  dimmerLamp (3),
  dimmerLamp (4),
  dimmerLamp (5),
  dimmerLamp (6)
};

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 4; i++) {
    dimmer[i].begin(NORMAL_MODE, ON);
  }
}

void loop() {
  if (Serial.available())  {
    buftemp = Serial.parseInt();
  }

  int lamp = buftemp / 1000;
  int temp = buftemp % 1000;

  if((lamp>=1) && (lamp <= 4) && (temp >= 5) && (temp <= 95)) {
    // -1 because array indexes start at zero
    dimmer[lamp-1].setPower(temp);
  }
}

the module has a Triac and zero-crossing detector
some background to the Robotdyn dimmer library.
the library makes phase cutting . it uses two interrupts,

first interrupt is an external interrupt for the zero crossing, which only resets counters for output channels.

the second interrupt is timer interrupt fired every 12 microseconds. it handles the phase cutting intervals for the individual channels, based on count of elapsed timer interrupts since reset in zero crossing interrupt.

(I don't like it)

Juraj:
don't set the value again and again. put everything in if (Serial.available()) {

Good shot, I did it and maybe I got a litlle difference, but it's not perfect...I don't knowwhat I can do more to get it faster....will see the librairy is the cause

PaulMurrayCbr:
I'm a bit surprised by how you are working with temps of 5-95 over a range of 1000. What happens when buftemp is 2345?

The answer at your question is simply nothing

Actualy the only one input is a slider frome Node-red then the risk is null to get bad value and for 2345, it can happen happen with no "if" to take valide it

Juraj:
(I don't like it)

OK, not really sure to get it, but do you have a sugest way to do something else?

EdI_VeDeR:
OK, not really sure to get it, but do you have a sugest way to do something else?

sorry, I don't like the Robotdyn library. The interrupts take too much of the CPU time and most of the occurrences do nothing usefull.
For two channels on ATmega the TriacDimmer library is better. (It uses capture interrupt for zero crossing.) But it doesn't have a solution for more channels.
I use one channel of Robotdyn AC dimmer to regulate a 2kW electric heater. I setup a 100 Hz Fast PWM with Timer1 and reset it in zero crossing interrupt to stay in sync with AC. The period is then set with OCRA. OCRB could be used for second channel. This technique could be enhanced with other timer for additional channels.

I'll alredy take a look on the example...

Will see if I can do something to merge it on my 4 channel board and ultimately on my 2 board of 4 channels each setup

Juraj:
sorry, I don't like the Robotdyn library. The interrupts take too much of the CPU time and most of the occurrences do nothing usefull.
For two channels on ATmega the TriacDimmer library is better. (It uses capture interrupt for zero crossing.) But it doesn't have a solution for more channels.
I use one channel of Robotdyn AC dimmer to regulate a 2kW electric heater. I setup a 100 Hz Fast PWM with Timer1 and reset it in zero crossing interrupt to stay in sync with AC. The period is then set with OCRA. OCRB could be used for second channel. This technique could be enhanced with other timer for additional channels.

Can you put your code here for more comprhension?

EdI_VeDeR:
Can you put your code here for more comprhension?

here relay - Fan regulator control from Arduino - Arduino Stack Exchange

or here

It is an 'in-project' library and has #ifdefs for SAMD too

Thank you

After many hours I clearly don't get everything in your code but at this point I got a perfect light without flicker on every channel. The dimmer is smoother and linear. My GU10 give me 1500 to 7500 dimming value range.

The last thing that I can't go through is I can't get two, three or four channel open in the same time. Just one at a time.

#include <TimerOne.h>

const byte INTERRUPT_PIN = 2;
const byte TRIAC1_PIN = 3;
const byte TRIAC2_PIN = 4;
const byte TRIAC3_PIN = 5;
const byte TRIAC4_PIN = 6;
const byte TRIAC_PULSE_MICROS = 30;

volatile bool triacOn;
volatile int period ; // microseconds cut out from AC pulse
volatile long periodSerial; //Need a long to get bigger size then 32000
volatile int TRIACtochange_PIN; 


void zeroCrossing() {
  triacOn = false; // triac tuns off self at zero crossing
  Timer1.setPeriod(period); // to call triacPulse() after off period
}

void triacPulse() {
  if (triacOn) { // stop pulse
    digitalWrite(TRIACtochange_PIN, LOW);
    Timer1.stop();
   } else { // start pulse
    digitalWrite(TRIACtochange_PIN, HIGH);
    triacOn = true;
    Timer1.setPeriod(TRIAC_PULSE_MICROS);
   }
}

void setup(){
  Serial.begin(9600);
  Serial.setTimeout(10); 
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), zeroCrossing/*  Fonction*/, RISING);   
  Timer1.initialize();
  Timer1.attachInterrupt(triacPulse);
    
 }

void loop() {
  
  while (!Serial) {}  
  periodSerial = Serial.parseInt();
  
 if (periodSerial!=0){
      
     if (periodSerial>11499 && periodSerial<17501){ 
       TRIACtochange_PIN = TRIAC1_PIN;
       period = periodSerial  - 10000;}                 
             
     if (periodSerial>21499 && periodSerial<27501){ 
      TRIACtochange_PIN = TRIAC2_PIN;
      period = periodSerial  - 20000;}                         
  
     if (periodSerial>31499 && periodSerial<37501){ 
      TRIACtochange_PIN = TRIAC3_PIN;
      period = periodSerial  - 30000;}                
  
     if (periodSerial>41499 && periodSerial<47501){ 
       TRIACtochange_PIN = TRIAC4_PIN;
       period = periodSerial  - 40000;}          
  }
}

This code is nearly the opposite

When I send an Int in the 4th channel range all the light light on

#include <TimerOne.h>

const byte INTERRUPT_PIN = 2;
const byte TRIAC1_PIN = 3;
const byte TRIAC2_PIN = 4;
const byte TRIAC3_PIN = 5;
const byte TRIAC4_PIN = 6;
const byte TRIAC_PULSE_MICROS = 30;

volatile bool triacOn1;
volatile bool triacOn2;
volatile bool triacOn3;
volatile bool triacOn4;
volatile int period1 ; // microseconds cut out from AC pulse
volatile int period2 ; // microseconds cut out from AC pulse
volatile int period3 ; // microseconds cut out from AC pulse
volatile int period4 ; // microseconds cut out from AC pulse
volatile long periodSerial; //Need a long to get bigger size then 32000

void zeroCrossing1() {
  triacOn1 = false; // triac tuns off self at zero crossing
  Timer1.setPeriod(period1); // to call triacPulse() after off period
  triacOn2 = false; // triac tuns off self at zero crossing
  Timer1.setPeriod(period2); // to call triacPulse() after off period
  triacOn3 = false; // triac tuns off self at zero crossing
  Timer1.setPeriod(period3); // to call triacPulse() after off period
  triacOn4 = false; // triac tuns off self at zero crossing
  Timer1.setPeriod(period4); // to call triacPulse() after off period
}

void triacPulse1() {
  if (triacOn1) { // stop pulse
    digitalWrite(TRIAC1_PIN, LOW);
    Timer1.stop();
   } else { // start pulse
    digitalWrite(TRIAC1_PIN, HIGH);
    triacOn1 = true;
    Timer1.setPeriod(TRIAC_PULSE_MICROS);
   }
   if (triacOn2) { // stop pulse
    digitalWrite(TRIAC2_PIN, LOW);
    Timer1.stop();
   } else { // start pulse
    digitalWrite(TRIAC2_PIN, HIGH);
    triacOn2 = true;
    Timer1.setPeriod(TRIAC_PULSE_MICROS);
    }
   if (triacOn3) { // stop pulse
    digitalWrite(TRIAC3_PIN, LOW);
    Timer1.stop();
   } else { // start pulse
    digitalWrite(TRIAC3_PIN, HIGH);
    triacOn3 = true;
    Timer1.setPeriod(TRIAC_PULSE_MICROS);
   }
   if (triacOn4) { // stop pulse
    digitalWrite(TRIAC4_PIN, LOW);
    Timer1.stop();
   } else { // start pulse
    digitalWrite(TRIAC4_PIN, HIGH);
    triacOn4 = true;
    Timer1.setPeriod(TRIAC_PULSE_MICROS);
   }
}


void setup(){
  Serial.begin(9600);
  Serial.setTimeout(10); 
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), zeroCrossing1/*  Fonction*/, RISING);  
  Timer1.initialize();
  Timer1.attachInterrupt(triacPulse1);
  
    
 }

void loop() {
  
  while (!Serial) {}  
  periodSerial = Serial.parseInt();
  
 if (periodSerial!=0){
      
     if (periodSerial>11499 && periodSerial<17501){ 
          period1 = periodSerial  - 10000;}                 
             
     if (periodSerial>21499 && periodSerial<27501){ 
          period2 = periodSerial  - 20000;}                         
  
     if (periodSerial>31499 && periodSerial<37501){ 
          period3 = periodSerial  - 30000;}                
  
     if (periodSerial>41499 && periodSerial<47501){ 
          period4 = periodSerial  - 40000;}          
  }
}

you have only one period setting and 4 pins. you can't expect the one period be set for any pin individually

I have already figure it out, but I don't know how to get multiple timer1????

EdI_VeDeR:
I have already figure it out, but I don't know how to get multiple timer1????

you don't. you can code it that the timer fires the interrupt always when you need it ( by calculating the intervals between individual periods).

Hi all.

Sorry to hijack, but just a quick couple questions on these Triac modules as the documentation is almost non-existent (typical for cheap electronics from China).

@Juraj:

  • From your code it appears that both the Zero Crossing detect output and the triac turn-on control are Active High logic. Correct?

  • Is the High level for both of these signals set by the applied VCC (3.3 or 5V)?

  • Is the Zero Crossing detect output driven high or is it Open Drain?

Thanks

gfvalvo:
Hi all.

Sorry to hijack, but just a quick couple questions on these Triac modules as the documentation is almost non-existent (typical for cheap electronics from China).

Robotdyn has some tutorial and schematics here

and they have some library too GitHub - RobotDynOfficial/RBDDimmer: The following library is used for work with dimmer, it gives ability to control large ammoun of dimmer. This lib uses with Leonardo, Mega, UNO, ESP8266, ESP32, Arduino M0, Arduino Zero, Arduino Due, STM32.

gfvalvo:

  • From your code it appears that both the Zero Crossing detect output and the triac turn-on control are Active High logic. Correct?
  • Is the Zero Crossing detect output driven high or is it Open Drain?

Triac switches AC on with HIGH on gate and turns AC off only at zero crossing (if gate is LOW at the time). So the Triac needs only a 20 microseconds pulse. For AVR I use the WO of Timer so the gate is HIGH until counter reaches top, which is now in my code short before zero crossing. (It could be set to a short pulse by setting the top in setPeriod to period + 20 us.)

Right now I am not sure if the zero crossing detector is active LOW or HIGH and if i is open drain. I already have a point in my TODO list to check this to make sure I detect the zero crossing at the beginning.

gfvalvo:

  • Is the High level for both of these signals set by the applied VCC (3.3 or 5V)?

I powered it from 5V with SAMD too. The Triac switched with 3.3 V level.

They have on shop page "The logical level is tolerant to 5V and 3.3V, therefore it can be connected to the microcontroller with 5V and 3.3V level logic"

OK, thanks. I’ll wait until my order arrives and also do some checking. Here is at least a notional schematic: esp8266 - RobotDyn dimmer controlled by ESP 07 only results in flickers - Electrical Engineering Stack Exchange

If this is accurate, the Z-C output is indeed a high-going pulse from an open-collector transistor (with pullup resistor that could be removed is necessary).

What’s not clear from this is whether opto-isolator D1 has two back-to-back LEDs (giving two Z-C pulses per AC cycle) or a LED and regular diode (giving one Z-C pulse per AC cycle).

Like I said, I’ll check it out when it arrives.

the shop page has schematics
https://robotdyn.com/pub/media/0G-00005677==Mod-Dimmer-5A-1L/DOCS/Schematic==0G-00005677==Mod-Dimmer-5A-1L.pdf

the ZC interrupt fires every 10 milliseconds on 50 Hz AC

Juraj:
the shop page has schematics
https://robotdyn.com/pub/media/0G-00005677==Mod-Dimmer-5A-1L/DOCS/Schematic==0G-00005677==Mod-Dimmer-5A-1L.pdf

Yup, that's the same "Schematic" as on the page I linked. Of course, without component values or part numbers, the schematic is only notional.

the ZC interrupt fires every 10 milliseconds on 50 Hz AC

OK then, 2 pulses per AC cycle.

Thanks.