user7916: I have recently bought this light dimmer, and only when I received it I noticed it works with PSM (Pulse Skip Modulation) and not PWD (Pulse Width Modulation).
Does anyone know how to write Arduino code and do the wiring for this dimmer? I can't seems to find a working example.
Thanks



user42015: I assume you use this module.
PSM is often used because of it's higher efficiency with light loads. It's also better for AC loads, since they should get a complete AC voltage and not a DC voltage (when you cut half of the wave).
The module you have, is build to support you with implementing PSM correctly. It has a zero-crossing detection, which gives you a signal on the Z-C pin, every time the AC sine wave crosses zero voltage (which is the best time to switch). You can sense the signal with an interrupt in your Arduino. The website does not explain exactly, what is outputted by the Z-C pin on a zero crossing, but you can check this easily yourself, by monitoring both AC and Z-C voltage in operation. Most likely you will have to use either a FALLING or a CHANGE interrupt.
PSM works with modulating the number of pulses (in this case full sine wave periods) are transmitted to the load. Imagine you want to dim the light in 10 distinct values.

For full power you always set the pin marked with PWM to high, when a full sine wave is starting (this is at every second zero crossing). This means the PWM pin is always high.
For half power you turn the PWM pin high for 5 full periods and then turning it off for further 5 periods.
For 10% (a value of 1) you turn the PWM pin high for 1 full period and then off for 9 periods.

The downside of this method is, that you might see the light flickering when having low values.
When implementing this, you can use the attachInterrupt() function with the Z-C pin. In the callback function you toggle a global (volatile!) boolean variable, to indicate, if a new full period is starting, or if the zero crossing signal is only indicating the start of the negative part of the sine wave. Also use a global (volatile!) counter variable, that counts (increments every full period) to the value, you preset (Here something between 0 and 10). When the counter variable is 0 (and the desired value is greater than 0) you write HIGH to the PWM pin of your module. When the counter reaches the desired value, you write LOW to the PWM pin. When the counter reaches the maximum value, you have reset it to 0.
In code something like this:
volatile byte counter=0;
volatile boolean new_period = true;
volatile byte value=5;
#define MAX_VALUE 10

void setup(){
  // set pinModes for the correct pins

  // active interrupt. Note, that you may have to change FALLING to a value fitting the output of the module (see explanation above)
  attachInterrupt(digitalPinToInterrupt(Z_C_pin), zero_crossing, FALLING);
}

void zero_crossing(){
  if(new_period){
    if(counter==0 && value>0) digitalWrite(PWM_pin,HIGH);
    if(counter==value) digitalWrite(PWM_pin,LOW);
    counter++;
    if(counter > MAX_VALUE) counter=0;
  }
  new_period=!new_period;
}

Note: Especially when having a great range of possible values, some of the values can be exchanged by a better behavior, that would prevent a bit of the flickering. For example, when using 100 distinct dimming stages and wanting to dim to 50%, you can either (as depicted above) turn the light on for 50 periods and then turning it of for another 50 periods. Or you can turn on during every second period. Though this will not help you with really small values. So I left it out for simplicity.

user69751: This module allows you to implement pulse skipping modulation but also phase angle control. The code that reins.ch posted is actually the latter.

user50645: Just adding to chrisl's answer since I bought this module, too.
There is a simple example on the manufacturers website of this module which does not seem to implement PSM the obvious way:

/*
Connect RobotDyn AC Light Dimmer as follows:
Dimmer pin  --  Arduino pin
    VCC     --    5V
    GND     --    GND
    Z-C     --    D2
    PWM     --    D3

Glow sketch for AC Voltage dimmer with Zero cross detection
Based on the sketch by Charith Fernanado 
Adapted by RobotDyn: http://www.robotdyn.com
License: Creative Commons Attribution Share-Alike 3.0 License.
Attach the Zero cross pin of the module to Arduino External Interrupt pin
Select the correct Interrupt # from the below table (the Pin numbers are digital pins, NOT physical pins: digital pin 2 [INT0]=physical pin 4 and digital pin 3 [INT1]= physical pin 5)

Pin    |  Interrrupt # | Arduino Platform
---------------------------------------
2      |  0            |  All
3      |  1            |  All
18     |  5            |  Arduino Mega Only
19     |  4            |  Arduino Mega Only
20     |  3            |  Arduino Mega Only
21     |  2            |  Arduino Mega Only

In the program pin 2 is chosen
*/
int AC_LOAD = 3;    // Output to Opto Triac pin
int dimming = 128;  // Dimming level (0-128)  0 = ON, 128 = OFF

void setup()
{
  pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  attachInterrupt(0, zero_crosss_int, RISING);  // Choose the zero cross interrupt # from the table above
}

// the interrupt function must take no parameters and return nothing
void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
{
  // Firing angle calculation : 1 full 50Hz wave =1/50=20ms 
  // Every zerocrossing thus: (50Hz)-> 10ms (1/2 Cycle) For 60Hz => 8.33ms (10.000/120)
  // 10ms=10000us
  // (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65

  int dimtime = (75*dimming);    // For 60Hz =>65    
  delayMicroseconds(dimtime);    // Off cycle
  digitalWrite(AC_LOAD, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propogation delay (for 60Hz use 8.33)
  digitalWrite(AC_LOAD, LOW);    // triac Off
}

void loop()  {
  for (int i=5; i <= 120; i++){  // We use 120 as the lowest and 5 as the highest brightness setting. May be adjusted depending on the lamp used.
    dimming=i;
    delay(20);
   }
  for (int i=120; i >= 5; i--){  // Same as above
    dimming=i;
    delay(20);
   }
}

They are using an interrupt as suggested by chrisl.
There is no flickering present with low dim values (using an incandescent bulb).
See this video for a similar board with the original version of the above sketch.
Note: If you want to integrate your own code into this example, it will likely not work as intended because the Arduino is busy with delayMicroseconds() most of the time

EDIT: The manufacturer of this module just released a library. Check it out on their github

7916: <p>I have recently bought this light dimmer, and only when I received it I noticed it works with PSM (Pulse Skip Modulation) and not PWD (Pulse Width Modulation).</p>

<p>Does anyone know how to write Arduino code and do the wiring for this dimmer? I can't seems to find a working example.</p>

<p>Thanks</p>

<p><a href="https://i.stack.imgur.com/97mzH.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/97mzH.jpg" alt="RobotDyn PSM Light Dimmer"></a>
<a href="https://i.stack.imgur.com/T7Qfr.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/T7Qfr.jpg" alt="enter image description here"></a></p>
 42015: <p>I assume you use <a href="https://robotdyn.com/ac-light-dimmer-module-1-channel-3-3v-5v-logic-ac-50-60hz-220v-110v.html" rel="nofollow noreferrer">this module</a>.</p>

<p>PSM is often used because of it's higher efficiency with light loads. It's also better for AC loads, since they should get a complete AC voltage and not a DC voltage (when you cut half of the wave).</p>

<p>The module you have, is build to support you with implementing PSM correctly. It has a zero-crossing detection, which gives you a signal on the Z-C pin, every time the AC sine wave crosses zero voltage (which is the best time to switch). You can sense the signal with an interrupt in your Arduino. The website does not explain exactly, what is outputted by the Z-C pin on a zero crossing, but you can check this easily yourself, by monitoring both AC and Z-C voltage in operation. Most likely you will have to use either a <code>FALLING</code> or a <code>CHANGE</code> interrupt.</p>

<p>PSM works with modulating the number of pulses (in this case full sine wave periods) are transmitted to the load. Imagine you want to dim the light in 10 distinct values.</p>

<ul>
<li>For full power you always set the pin marked with PWM to high, when a full sine wave is starting (this is at every second zero crossing). This means the PWM pin is always high.</li>
<li>For half power you turn the PWM pin high for 5 full periods and then turning it off for further 5 periods.</li>
<li>For 10% (a value of 1) you turn the PWM pin high for 1 full period and then off for 9 periods.</li>
</ul>

<p>The downside of this method is, that you might see the light flickering when having low values.</p>

<p>When implementing this, you can use the <code>attachInterrupt()</code> function with the Z-C pin. In the callback function you toggle a global (volatile!) boolean variable, to indicate, if a new full period is starting, or if the zero crossing signal is only indicating the start of the negative part of the sine wave. Also use a global (volatile!) counter variable, that counts (increments every full period) to the value, you preset (Here something between 0 and 10). When the counter variable is 0 (and the desired value is greater than 0) you write HIGH to the PWM pin of your module. When the counter reaches the desired value, you write LOW to the PWM pin. When the counter reaches the maximum value, you have reset it to 0.</p>

<p>In code something like this:</p>

<pre class="lang-c prettyprint-override"><code>volatile byte counter=0;
volatile boolean new_period = true;
volatile byte value=5;
#define MAX_VALUE 10

void setup(){
  // set pinModes for the correct pins

  // active interrupt. Note, that you may have to change FALLING to a value fitting the output of the module (see explanation above)
  attachInterrupt(digitalPinToInterrupt(Z_C_pin), zero_crossing, FALLING);
}

void zero_crossing(){
  if(new_period){
    if(counter==0 &amp;&amp; value&gt;0) digitalWrite(PWM_pin,HIGH);
    if(counter==value) digitalWrite(PWM_pin,LOW);
    counter++;
    if(counter &gt; MAX_VALUE) counter=0;
  }
  new_period=!new_period;
}
</code></pre>

<p>Note: Especially when having a great range of possible values, some of the values can be exchanged by a better behavior, that would prevent a bit of the flickering. For example, when using 100 distinct dimming stages and wanting to dim to 50%, you can either (as depicted above) turn the light on for 50 periods and then turning it of for another 50 periods. Or you can turn on during every second period. Though this will not help you with really small values. So I left it out for simplicity.</p>
 69751: <p>This module allows you to implement pulse skipping modulation but also phase angle control. The code that reins.ch posted is actually the latter.</p>
 50645: <p>Just adding to <a href="https://arduino.stackexchange.com/a/51859/50645">chrisl's answer</a> since I bought this module, too.</p>

<p>There is a simple example on the <a href="https://robotdyn.com/ac-light-dimmer-module-1-channel-3-3v-5v-logic-ac-50-60hz-220v-110v.html" rel="nofollow noreferrer">manufacturers website of this module</a> which does not seem to implement PSM the obvious way:
</p>

<pre><code>/*
Connect RobotDyn AC Light Dimmer as follows:
Dimmer pin  --  Arduino pin
    VCC     --    5V
    GND     --    GND
    Z-C     --    D2
    PWM     --    D3

Glow sketch for AC Voltage dimmer with Zero cross detection
Based on the sketch by Charith Fernanado 
Adapted by RobotDyn: http://www.robotdyn.com
License: Creative Commons Attribution Share-Alike 3.0 License.
Attach the Zero cross pin of the module to Arduino External Interrupt pin
Select the correct Interrupt # from the below table (the Pin numbers are digital pins, NOT physical pins: digital pin 2 [INT0]=physical pin 4 and digital pin 3 [INT1]= physical pin 5)

Pin    |  Interrrupt # | Arduino Platform
---------------------------------------
2      |  0            |  All
3      |  1            |  All
18     |  5            |  Arduino Mega Only
19     |  4            |  Arduino Mega Only
20     |  3            |  Arduino Mega Only
21     |  2            |  Arduino Mega Only

In the program pin 2 is chosen
*/
int AC_LOAD = 3;    // Output to Opto Triac pin
int dimming = 128;  // Dimming level (0-128)  0 = ON, 128 = OFF

void setup()
{
  pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
  attachInterrupt(0, zero_crosss_int, RISING);  // Choose the zero cross interrupt # from the table above
}

// the interrupt function must take no parameters and return nothing
void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
{
  // Firing angle calculation : 1 full 50Hz wave =1/50=20ms 
  // Every zerocrossing thus: (50Hz)-&gt; 10ms (1/2 Cycle) For 60Hz =&gt; 8.33ms (10.000/120)
  // 10ms=10000us
  // (10000us - 10us) / 128 = 75 (Approx) For 60Hz =&gt;65

  int dimtime = (75*dimming);    // For 60Hz =&gt;65    
  delayMicroseconds(dimtime);    // Off cycle
  digitalWrite(AC_LOAD, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propogation delay (for 60Hz use 8.33)
  digitalWrite(AC_LOAD, LOW);    // triac Off
}

void loop()  {
  for (int i=5; i &lt;= 120; i++){  // We use 120 as the lowest and 5 as the highest brightness setting. May be adjusted depending on the lamp used.
    dimming=i;
    delay(20);
   }
  for (int i=120; i &gt;= 5; i--){  // Same as above
    dimming=i;
    delay(20);
   }
}
</code></pre>

<p>They are using an interrupt as suggested by chrisl.
There is no flickering present with low dim values (using an incandescent bulb).
See <a href="https://www.youtube.com/watch?v=Oq6Cnqwbbbg" rel="nofollow noreferrer">this video</a> for a similar board with the original version of the above sketch.</p>

<p><strong>Note:</strong> If you want to integrate your own code into this example, it will likely not work as intended because the Arduino is busy with <code>delayMicroseconds()</code> most of the time</p>

<hr>

<p>EDIT: The manufacturer of this module just released a library. Check it out on <a href="https://github.com/RobotDynOfficial/Lib-RBD-Dimmer-for-Mega-UNO-Leonardo" rel="nofollow noreferrer">their github</a></p>
