AC PWM Timing and Duty Cycle Mismatch

I have build an AC Lamp dimmer and I am trying to control it via HM-10 BLE, I am using this library called ACPWM. The link to the library :
![ Link

The code that i have used is as follows:

#include <ACPWM.h>
 #define ZERO_PIN 2 //Input pin from zero cross detector
 #define PWM_PIN 9 //Output pin to TRIAC / SSR
 int dim = 0; // the dutyCycle 
 String readString;
 void setup()
    pinMode(ZERO_PIN, INPUT);
    pinMode(PWM_PIN, OUTPUT);
    //Initialize PWM operation.
    //Mains frequency: 50Hz.
    //Zero crossing point reached whenever pulse to PIN2 changes
    //Duty cycle = 0..10. 0:always off. 10: always on. 5: 50% on.
 void loop() {
  while (Serial.available()) {  
    char c =;
    readString += c;  
  if (readString.length() >0) {
    if (readString.substring(0,8) == "Z0000001"){
     if (readString.substring(8) == "5"){
     else if (readString.substring(8) == "4"){
     else if (readString.substring(8) == "3"){
     else if (readString.substring(8) == "2"){
     else if (readString.substring(8) == "0"){

In the code you can find that after a few comparisons on the serially fetched string the value of the variable dim is set which is the duty cycle for the pwm process set each time the data is fetched.

As soon as I input the string from my phone as Z0000011 (0%) ,Z0000012(30%),Z0000013(50%),Z0000014(70%),Z0000015(100%) it works fine.

When I send the strings in the opposite order, it works fine until Z0000001 is sent.
That is it reduces from 100 to 30 but instead of going 0% or switching off its duty cycle increases to 100% although the serial monitor shows 00
At this step no serial communication could occur between arduino until it is reset.

The Z00000010 works fine when sent in increasing order or sent in any arbitrary order of duty cycles but when its sent in decreasing as the last statement it increases the duty cycle to 100% rather than making it 0.

The issue is with I suppose, If anybody thinks that I should use character in place of string I am telling in advance this is the best way to input strings from serial, way faster than serial.readString(). Above all i have to use string in any case.

The Changes that i made for the program to work as expected but it didn’t

  1. Reducing number of brightness steps,
  2. Using RISING and FALLING in place of CHANGE
  3. calling noInterrupts() and interrupts()

It is very urgent and i await valuable suggestions. Please suggest alternates if that is a better way to do it. If this can be done by timer1 or any other way please let me know. As i have tried but they didnt work as per expectation.
Thanks in advance

](Arduino ACPWM Library)

How can a light dimmer be urgent?
What’s with all the delay(18) ?

AWOL: How can a light dimmer be urgent? What's with all the delay(18) ?

Well its part of a project and I am stuck here. Saw it in the timer1 example some kind of propogation delay. Although the code runs the same way with or without it.

If you want to read the 8th character of a string, you should wait for the string having (at least) that size.

That's quite a complex circuit for zero-cross detection. I believe this is a significant source of the 30% PWM problem ... at how many degrees in the rectified 12VAC sine waveform do you expect the optocoupler to fully turn on? This could be significantly improved by using an appropriate 230VAC opto-coupler zero-cross circuit.

If using delay(18) was to provide correction for the late zero-cross pulses, as you can see, that's not the correct approach.

What is the part number of the zero crossing detector opto-coupler.
OPs Circuit;

Thanks Tom

Hi, This is how its done in the arduino playground; |500x262 Notice it uses the mains voltage as the detecting waveform source, this means the threshold to get the zero crossing opto to conduct will occur closer to the zero crossing point than if you use the secondary, hence lower waveform, as the source.

Tom... :)

You can perfectly do it on the secondary side but just drop the opto... Just connect R1 to the Arduino and up it's value to 100k.