# Arduino 230v Light bulb dimming

Hey guys i have done a lot of research and testing on different circuits for 230v(50hz) or 220v light dimming, but i cant get my arduino to dim my light. This is the last thing i tried.

Code which i tried:

int AC_LOAD = 3;    // Output to Opto Triac pin
int dimming = 128;  // Dimming level (0-128)  0 = ON, 128 = OFF

void setup()
{
attachInterrupt(0, zero_crosss_int, RISING);  // Choose the zero cross interrupt # from the table above
}

void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
{
// Firing angle calculation :: 50Hz-> 10ms (1/2 Cycle)
// (10000us - 10us) / 128 = 75 (Approx)
int dimtime = (75*dimming);
delayMicroseconds(dimtime);    // Off cycle
delayMicroseconds(10);         // triac On propogation delay
}

void loop()
{
dimming = 128;
delay(100);
dimming = 75;
delay(100);
dimming = 25;
delay(100);

}

• Forget about the interrupt routine for a few moments. Did you check if you actually see the zero crossings on your input pin? You might want to write a sketch that toggles the pin13 LED every 50 or 60 or zerocrossings. You should see a visible 1Hz blink. – jippie Mar 3 '13 at 11:41
• Which input pin did you use for attaching the zero crossing detector? Notice that interrupt number may not be the same as input pin number and may interrupt pin numbers may vary across Arduino board type. So which Arduino are you using? – jippie Mar 3 '13 at 11:44
• @jippie I am using Arduino uno and my interrupt pin is 2 – Daniel Euchar Mar 3 '13 at 11:46
• @jippie i am new to this can you help me with it "Did you check if you actually see the zero crossings on your input pin? You might want to write a sketch that toggles the pin13 LED every 50 or 60 or zerocrossings." – Daniel Euchar Mar 3 '13 at 11:49

I'd start to debug by attempting to switch the load on and off a few times in the setup to ensure the TRIAC is firing, for example:

void setup()
{
for (int i=0; i < 10; i++)
{
delay(1000);
delay(1000);
}
}


The MOC3021SM Datasheet shows that 15mA may be required to drive the LED. At 3.3V as shown in the schematic R5 the 470R resistor would limit the current to 7mA and at 5V it would still only be 10mA and that's ignoring the forward voltage drop.

You can use a normal LED resistor calculation to determine the resistance, it looks like about 1.15V forward voltage drop for that part at room temperature so 120 ohms at 3.3V would be more appropriate to give a bit above 15mA. The following are the recommendations regarding LED current from the datasheet:

All devices are guaranteed to trigger at an IF value less than or equal to max IFT. Therefore, recommended operating IF lies between max IFT (30mA for MOC3020M, 15mA for MOC3010M and MOC3021M, 10mA for MOC3011M andMOC3022M, 5mA for MOC3012M and MOC3023M) and absolute max IF(60mA)

If that works OK next step may be to test the zero-crossing detection works at least once, maybe using the following and seeing if it turns on after 10 seconds:

void setup()
{
delay(10000);
attachInterrupt(0, zero_crosss_int, RISING);  // Choose the zero cross interrupt # from the table above
}

void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
{
}


If that doesn't work maybe remove U1 the optocoupler (if in a socket?) and see if the above works if you short the output between the emitter and collector (carefully!) on U1 together to pull the input down to ground. It may be you have a general interrupt configuration problem depending on which pin it's connected to, which you should add to the question, but that will help isolate a software versus hardware problem.

• THanks for the reply. The MOC3021SM is working perfectly i tired the code you gave and its perfect switching. – Daniel Euchar Mar 3 '13 at 11:35
• i think i am messing up with the zero crossing detection can you guide me further. – Daniel Euchar Mar 3 '13 at 11:42
• now it dosen't glow i will change my components and then tell you the results. – Daniel Euchar Mar 3 '13 at 13:59
• hey peter i am able to get the interrupt but only when the switch is turned on or turned off. not during other times any suggestions ? – Daniel Euchar Mar 5 '13 at 11:08
• @DanielEuchar, the ZCD detect part of that circuit looks dodgy as well only allowing a few milliamps to flow even at peak voltages. You might be better to ask a new question showing that part of the circuit and seek advice how to make a reliable one. As highlighted by my answer and Russell's there are a lot of design problems with the circuit just in the TRIAC driver (although it may work sometimes) and the ZCD doesn't seem a lot better. – PeterJ Mar 5 '13 at 11:31

Forget about the interrupt routine for a few moments. Did you check if you actually see the zero crossings on your input pin? You might want to write a sketch that toggles the pin13 LED every 50 or 60 or zerocrossings. You should see a visible 1Hz blink.

I can't test the sketch (but it compiles without errors), but I think it should look a bit like this:

const uint8_t ledPin = 13;                          // Digital output pin that has the on board LED
const uint8_t zeroPin = 2;                          // Digital input pin to which the zero crossing detector is connected

uint8_t zeroCounter = 0;
bool zeroState = 0;
bool ledState = 0;

void setup() {
pinMode( ledPin , OUTPUT );                       // Enable output driver for LED pin
}

void loop() {
while ( digitalRead( zeroPin ) == zeroState ) {}; // Wait for the state of the zero crossing detector to change
zeroState != zeroState;
zeroCounter++;
if ( zeroCounter == 50 ) {                        // Every 50 zero crossings change the LED state
ledState != ledState;
digitalWrite( ledPin , ledState );
zeroCounter = 0;
}
}

• i tried the code above and nop the led didnt blink at all :( even tried the serial print to check the value it was all filled with '1' – Daniel Euchar Mar 3 '13 at 12:15
• Start by attaching R1 (10k) to +5VDC instead of +3V3, that can't hurt. – jippie Mar 3 '13 at 12:34
• No luck :( i guess i have to replace the components. will give it a try – Daniel Euchar Mar 3 '13 at 13:24

If you do not SHOW the exact circuit and connections that YOU are using then ALL questions of this sort are pointless.

This is the circuit diagram accessed via the page you referenced. Please add YOUR connections to it and post as part of your question.

Arduino ground MUST be connected to MOC3021 ground.

NB!!! - The following highlights a defect in the design of the circuit. This may or may not be what is wrong with your circuit. eg they may have found that the MOC3021SM did not work reliably and substituted a MOC3023 or MOC 022. Your problem MAY be unrelated.

1. Using a wire connect 3.3V+ to Dimmer input pin.
Triac should operate and drive load.

2. If 1. works, connect 3.3V+ at Arduino drive output pin connection. Ideally you should remove Arduino pin connection as this MAY damage the Arduino. In almost all cases it should be OK but back feeding 3.3V into a low driven in is "naughty" at best. TRIAC should operate.

If 1. & 2. do not work the problem could be circuit as below or still your fault. Change R5 as below and retry 1 & 2.

When Arduino high OR +3.3V is connected to Dimmer in there should be a voltage drop across R5 (very roughly 1.5V+ ) and U@ input pin should be at 1.2 - 1.5V above grpund.

The circuit has been badly "designed" and with 3.3V drive will not work with optocouplers meeting typical data sheet spec and is (of course) even worse with worst case data sheet spec. Even with 5V drive it will not meet typical spec.
The designer, if there was one, had severe brain fade the day this was designed.

MOC3021 data sheet - brand MAY matter, alas.

Opto input voltage at 20 mA = 1/15V / 1.5V typical / max .
Current to latch TRIAC = 8 / 15 mA typical/ max.

Working with TYPICAL opto vin and typical drive current (ie most optimistic case).
Iopto = (Vin - Vopto)/R5 = (3.3-1.15)/470 = 4.6 mA.
Typical optto current = 8 mA.
Worst case opto current = 15 mA !!!

Arduino drive current min = ??? mA.

For worst case R5 = (Vin-Vopto_max)/Imax = (3.3-1.5)/15 mA = 120 Ohm.

Vopto_max is at 20 mA but you MAY need most of 20 mA worst case.
What is the Arduino drive current capability max and what does Vhi drop to at this current.

Change R5 to 100 Ohms. Or place 120 Ohms or 150 Ohms in parallel with R5.

8-15 mA 1.15-1.5V (3.3-1.5)/470 =

Use this search to see all Digikey zero crossing optocouplers, sorted by ascending trogger current. Ignoring thos for which Ift is not shown, the (Vishay IL411x family has the lowest Ift at 1.3 mA worst case. They say actual current used should be several times that, and show that trigger current varies with load voltage and temperature and more., Read data sheet for more information.

The Fairchild **FOD4xx and xxx family are similar.

The MOC3063 from Liteon and others has Ift = 5 mA. See data sheet for details.

• AVR based Arduino can source/sink 40mA per pin with a max. of 200mA per package. AVR based Arduino usually runs at 5VDC. Arduino Due (not Duemilanove) is an ARM based controller, which has a 3V3 chip, unsure about output sink/source max. current. – jippie Mar 3 '13 at 11:04
• I tried the code give by @PerterJ and the triac seems to work fine can you guide me. as i am a pretty much lost – Daniel Euchar Mar 3 '13 at 11:43
• @DanielEuchar - PeterJ seems to be on the right track re code. Do not just do what he says BUT ALSO understand why thongs do or don't work when you change things. Does the original code from the website that you bought the board from work? What do they say? IF the TRIAC drive is OK AND the zero crossing is OK (which you must prove using examples provided) then the code you are running differes in what it does from what the examples do. How? Why? – Russell McMahon Mar 3 '13 at 22:25
• Hi! I'm trying to implement this scheme on Arduino Due using MOC3043 (zero-crossing, for heater). I have similar problems with max source current on Due (15mA). Can anybody recommend low current replacement for MOC* optocouples? – kelin Jan 10 '16 at 13:05

The above code froim jippie didn't work for me, but this, which is based on this code did. It also tests the ISR.

const uint8_t ledPin = 13;                          // Digital output pin that has the on board LED
const uint8_t zeroPin = 2;                          // Digital input pin to which the zero crossing detector is connected

uint8_t zeroCounter = 0;
bool zeroState = 0;
bool ledState = LOW;

void setup() {
Serial.begin(9600);
pinMode( ledPin , OUTPUT );                       // Enable output driver for LED pin
attachInterrupt(0, zero_crosss_int, RISING);  // Choose the zero cross interrupt # from the table above
}

void loop() {

}

void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
{
zeroState != zeroState;
zeroCounter++;

if ( zeroCounter == 60 ) {                        // Every 50 zero crossings change the LED state
ledState = (ledState == LOW) ? HIGH : LOW;
digitalWrite( ledPin , ledState );
zeroCounter = 0;
}
}

• Welcome to EE.SE. Note that "the above code" reference is meaningless on a site where answers float up and down with votes and user sort preferences. You have noted jippie's name though so we can work it out. – Transistor Apr 29 '18 at 22:10
• That was why I mentioned that it was jippie's code. – Dan Bemowski May 1 '18 at 1:36