Issues with I2C when 50-Hz AC-Dimmer is connected

Hi all,

I am sending integer values from an Arduino Nano to another Arduino Nano to control a light-dimmer and a relais. When the light dimmer unit is connected, the sending does not work properly: There is just no value received or you need to wait ca. 1-3s until you can send another int value.

Code of the Master (simplified for demonstration)

#include <Wire.h>

int value = 0;

void setup() {
  
  Wire.begin();
  
void loop()
{

  value = value + 20
  
  byte buffer[2];
  buffer[0] = value >> 8;
  buffer[1] = value & 255;

  Wire.beginTransmission(4);
  Wire.write(buffer, 2);
  Wire.endTransmission();

  delay(500); //delay() only for demonstration
    
  }
}

Code of the Slave (controlling the dimmer and relais)

#include <PushButton.h>
#include <Wire.h>
#include <TimerOne.h>
#include <Button.h>
#include <ButtonEventCallback.h>
#include <Bounce2.h>

int x = 0;

int RelaisDigitalPort =  12;      

int RelaisState = LOW;         

int volatile i = 0;             
volatile boolean zero_cross = 0; 
int AC_pin = 11;                
int DimmLevelAry[] = //360 steps to adjust light intensity
    {33, 47, 58, 67, 75, 82, 89, 95, 101, 106, 111, 116, 121, 126, 130, 135,
    139, 143, 147, 151, 155, 159, 162, 166, 169, 173, 176, 179, 183, 186, 189,
    192, 195, 198, 201, 204, 207, 210, 213, 216, 219, 221, 224, 227, 230, 232,
    235, 237, 240, 243, 245, 248, 250, 253, 255, 258, 260, 262, 265, 267, 270,
    272, 274, 277, 279, 281, 283, 286, 288, 290, 292, 295, 297, 299, 301, 303,
    306, 308, 310, 312, 314, 316, 318, 320, 323, 325, 327, 329, 331, 333, 335,
    337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 363, 365,
    367, 369, 370, 372, 374, 376, 378, 380, 382, 384, 386, 388, 389, 391, 393,
    395, 397, 399, 401, 403, 404, 406, 408, 410, 412, 414, 415, 417, 419, 421,
    423, 425, 426, 428, 430, 432, 434, 435, 437, 439, 441, 443, 444, 446, 448,
    450, 452, 453, 455, 457, 459, 460, 462, 464, 466, 468, 469, 471, 473, 475,
    476, 478, 480, 482, 484, 485, 487, 489, 491, 492, 494, 496, 498, 499, 501,
    503, 505, 507, 508, 510, 512, 514, 515, 517, 519, 521, 523, 524, 526, 528,
    530, 531, 533, 535, 537, 539, 540, 542, 544, 546, 547, 549, 551, 553, 555,
    556, 558, 560, 562, 564, 565, 567, 569, 571, 573, 574, 576, 578, 580, 582,
    584, 585, 587, 589, 591, 593, 595, 596, 598, 600, 602, 604, 606, 608, 610,
    611, 613, 615, 617, 619, 621, 623, 625, 627, 629, 630, 632, 634, 636, 638,
    640, 642, 644, 646, 648, 650, 652, 654, 656, 658, 660, 662, 664, 666, 668,
    670, 672, 674, 676, 679, 681, 683, 685, 687, 689, 691, 693, 696, 698, 700,
    702, 704, 707, 709, 711, 713, 716, 718, 720, 722, 725, 727, 729, 732, 734,
    737, 739, 741, 744, 746, 749, 751, 754, 756, 759, 762, 764, 767, 769, 772,
    775, 778, 780, 783, 786, 789, 792, 795, 798, 801, 804, 807, 810, 813, 816,
    820, 823, 826, 830, 833, 837, 840, 844, 848, 852, 856, 860, 864, 869, 873,
    878, 883, 888, 893, 898, 904, 910, 917, 924, 932, 941, 952, 966, 999, 1000};
int DimmLevel = 0;                  
int inc = 1;                    
int freqStep = 10;              

void setup() {
  Serial.setTimeout(50);

  Wire.begin(4);                
  Wire.onReceive(receiveEvent); 
  
  pinMode(RelaisDigitalPort, OUTPUT);

  pinMode(AC_pin, OUTPUT);                          
  attachInterrupt(1, zero_cross_detect, RISING);    

  Timer1.initialize(freqStep);                     
  Timer1.attachInterrupt(DimmLevel_check, freqStep);
}

void zero_cross_detect() {
  zero_cross = true;               
  i = 0;
  digitalWrite(AC_pin, LOW);       
}

void DimmLevel_check() {                
  if (zero_cross == true) {
    if (i >= DimmLevel) {
      digitalWrite(AC_pin, HIGH);   
      i = 0;                       
      zero_cross = false;           
    }
    else {
      i++;                          
    }
  }
}

void loop()
{

}

void receiveEvent()
{
  while(Wire.available()) 
  {
    x = 0;
    x = Wire.read() << 8 | Wire.read(); 
  }

  if (x == 10000) {
    LichtSwitch();
  }
  else if (x > 33 && x < 1001) {
    DimmLevel = DimmLevelAry[x];
  }

}

void LichtSwitch(){

  if (RelaisState == 0) {
    digitalWrite(RelaisDigitalPort, HIGH);
    RelaisState = 1;   
  }
  else {
    digitalWrite(RelaisDigitalPort, LOW);
    RelaisState = 0;
  }
}

What I tried:

  • Disconnect the dimmer module: Everything works perfectly, but of couse I would like to use it with the dimmer module!
  • Use serial communication instead if I2C: Basically the same problem
  • **Change baudrate:**No improvement

I checked the forum for comparable issues, but I cannot e.g. detach the interrupt as the light needs to stay on all the time obviously :).

I would appreciate your help!

Do you have a schematic, datasheet for the dimmer module? Please provide a link.

How did you connect everything together? Simple hand drawing picture taken by phone is OK.

Dimming is an ugly business from a noise point of view. Do you have an oscilloscope to look at the signals?

Unfortunately, I do not have an oscilloscope.

Here is more information on my setup:

Dimmer Module
LINK
I got the source of this method/code originally from HERE.

Setup of the Arduino + Modules
LINK

I also tried to power the Nanos independently, but this also didn't work.

Could you check the following?

  • Do you have pull-up resistors on both your I2C lines? 4.7K or 10K are typical

  • Do you have an LED on board that you can trigger when you receive a value? This would allow you to test whether your wire communication works, but something else is not working.

  • The following does not seem right. Your array is only 384 values but you look up values up to 1000.

else if (x > 33 && x < 1001) {
DimmLevel = DimmLevelAry[x];

  • Can you add some code to confirm whether the zero cross detection works as expected or whether you get extra pulses from some the switch on noise? e.g. count the number of interrupts per second and measure the max, and min time between interrupts. This should be twice your power frequency 50/60Hz -> 100/120 and the time should be 1s/100 or 1s/120 -> 10ms/~8ms

If you like I recommend you start cleaning the code a bit as well. For instance

  • Give all pins a common naming scheme. I use ALL_CAPITAL_WITH_UNDERSCORE for constants e.g.

const in ZERO_CROSS_DETECT_PIN = 1;

  • Make x a local variable of receiveEvent. You do not use it anywhere else. If you want to use the code in some other project you can copy the function and do not need to worry about variables because they are declared inside the function source code. Also it saves memory by using the stack or even processor registers and allows better optimization.

  • use the Arduino naming scheme variables and functions all start with lower letter and then Camel case no underscore e.g. zeroCrossDetect, dimmLevelCheck

  • You could mark functions attached to interrupts by adding something to the name and clearly use void in the parameter void zeroCrossDetectHandler(void) or void zeroCrossDetectIsr(void). This makes the code easier to read.

  • Do not use another language in your source code. e.g. LichtSwitch, RelaisState Makes it easier for others to help you.

  • Use nice variables names. Not i & x as global variables. Reserve the short ones for loops and so on.