Problems with zero cross detect light dimmer

Continuing the discussion from Difficulty using interrupts to recreate the spark socket in a dimmer switch[SOLVED]:

Hi @BDub, I had a thread going with @peekay123 yesterday trying to work out some IntervalTimer Library issues on my project…

Though that part was solved, it didn’t get me working. My project is very similar to what this original thread was based on. I just can’t seem to make the transition from arduino (where the code runs as intended) to Spark.

Aside from the differences you may point out, I will note that the AC Dimmer Circuit board I’m using is a 5v board so I’m using SparkFun’s bi-directional logic level converter.

At this point, I’m setting aside the code that includes the IntervalTimer Library and just trying to get a more simple version working. Thanks for taking the time.

int AC_LOAD = D5;    // 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(D1, zero_cross_int, RISING);  

//the interrupt function must take no parameters and return nothing

void zero_cross_int()  //function to be fired at the zero crossing to dim the light
  // Firing angle calculation : 1 full 60Hz wave =1/60=16.66ms 
  // Every zerocrossing thus: (60Hz)-> 8.33ms (1/2 Cycle) 
  // 8.33ms=8333us
  // (8333us - 8.33us) / 128 = 65 

  int dimtime = (65*dimming);    // For 60Hz =>65    
  delayMicroseconds(dimtime);    // Wait till firing the TRIAC
  digitalWrite(AC_LOAD, HIGH);   // Fire the TRIAC
  delayMicroseconds(8.33);         // triac On propogation delay (for 60Hz use 8.33)
  digitalWrite(AC_LOAD, LOW);    // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC

void loop()  {
  for (int i=5; i <= 128; i++){

What happens if you ignore the 60Hz interrupt and just bang D5 high in setup? Does the light come on?

You might have an electrical problem, not a code problem, so it is good to check.

1 Like

Light comes on and stays on, but I didn’t ignore the interrupt I just put it right in front of it. I did the same on the arduino and it powered through the interrupt.

1 Like

@techbutler I reviewed the link and software on the Zero Crossing circuit you posted.

The zero crossing detector will send a low to high transition to the spark just before the zero crossing and then a high to low just after.

When you get the interrupt you need to delay the HIGH signal to the Triac Optocoupler by some amount of time between 0 and 8.33 milliseconds. This is your 65*dimming amount. So for a dimming setting of 0 you will have no delay and the light will be full brightness. When your dimming value is 128 the delay will be 8.3ms. You need to make sure you turn AC_LOAD LOW before the end of the cycle, otherwise it will stay on during the next cycle.

In the original Arduino code sample they keep the AC_LOAD HIGH until just before the next zero crossing. So they turn it LOW upon entering the zero crossing low - high transition and then use the timer to delay the setting of AC_LOAD to HIGH. You have effectively replaced the timer function with


However you only keep AC_LOAD HIGH for 8 microseconds I’m not sure that is enough time to fire the triac. The data sheet on the MOC302 indicates max turn on time is 20us.

However you indicate that the light stays on, so it may be that you have blown the triac. If I remember correctly they fail closed.

So as @bko suggests you may want to review your wiring. Does the light turn off with dimmer set to ‘0’?


@mtnscott, thank you for kicking in. Those are valid points. The fact remains however that this sketch still runs perfectly on my pro mini as do others that I keep testing against this dimmer board.

I would ask, if you have the time, to check out the link I included in my first post which is a tandem thread (InternalTimer Library) I have been having on this topic and may help to bring you more up to speed on where things started and where I’m at.


I review that thread and the arduino code and studied the schematic file for the zero crossing and AC switch.

A few points -
This board is based on 5V supply on the digital side. Are you using the level converters for both the Arduino OUT and IN connections? The Arduio OUT which is your zero crossing trigger needs to be shifted to 3.3v for the Spark.

You mention that the Arduino IN - which is basically Pin 11 on the Arduino sketch or D5 on your spark sketch, when you connect it to a multimeter you measure a voltage around 2.7v, well since you don’t have a scope you are measuring RMS voltage and what is displayed will be between 0 and 3.3v based on your dimmer setting. If you cycle the dimmer setting via the program

you probably won’t be able to measure it as it will be moving all the time.

Finally, when you removed the timer interrupt code and just used a delay you still have the issue I mentioned before where you only keep the output to the AC switch on for ~8 microseconds. BTW - why do you have a floating point number where an integer is used?


@techbutler ok, I’ve reviewed all of the threads and datasheets… here’s my advice:

  1. ditch the sparkfun logic level converter. It won’t drive your opto isolator properly as it’s designed to output 5V with a 10k ohm pull up resistor. That means it’s really only good for driving high impedance inputs like TTL logic gates and things that have a low input current requirement. The 5V arduino output drives your dimmer circuit LED and OPTO input that are in parallel. The LED has a 470 ohm in series with it, so that’s about 6.3mA of load if it’s a red LED ( (5V - 2V) / 470). The OPTO has a 1k ohm in series with it, and with the 1.15Vf of the opto’s LED, you have about 3.85mA of load ( (5V - 1.15V) / 1000). So approximately 10mA of load. Now drive all of that through a 10k pull up resistor to 5V (the output of your logic level converter) and you get a lot of nothing happening correctly :smile:

  2. make the AC dimmer work with a 3.3V system, aka Spark Core. I will be referencing this schematic:

  • Replace R4 with a 220 ohm (or put a 470 in parallel with the 470 that’s in the board)
  • Replace R3 with a 560 ohm (or put a 1k in parallel with the 1k that’s in the board)
  • The ARDUINO_+5V connection should just be tied to Spark Core pin 3V3
    (digital 3.3V reference)
  • This will make the AC dimmer work the same way it does when it’s hooked up to the 5V output of the Arduino.
  1. I haven’t fully analyzed your code differences between the TimerOne library based arduino code, and the code in the first post above… but delayMicroseconds(8.33); is not going to work. At best you might see an 8us delay, but it needs to be passed an integer, not a float. You can achieve sub-micro second delays on the spark core, but it’s a little more involved. Not hard though.
// DWT->CYCCNT is a free running 32-bit hardware counter, clocked at 72MHz.
uint32_t DWT_START = DWT->CYCCNT; 
while((DWT->CYCCNT - DWT_START) < 600);  
// DWT->CYCCNT has a resolution of 1 second / 72,000,000, so 600 / 72M = 8.333uS

I’ll let you figure out how to make that prettier :wink: Basically those two lines are your delayMicroseconds(8.333); more precisely.

Give all of that a try and then see where you are at.


Great input @BDub, Thanks. I’ll get on your suggestions. Let’s just drop the delay(microseconds) code. The endgame has always been to use is use the @peekay123 TimerInterval Library. I thought I was simplifying things, but ended up doing the opposite. I apologize to all. I will report back on my progress.


ok, so I made the hardware changes as suggested by @BDub to make what I have a 3.3v dimmer board. This had no impact on successfully running my IntervalTimer dimmer code. To verify the board was working properly at 3.3v, I wired it up to a 3.3v pro mini and ran my Timer1 dimmer code and it ran successfully.

Of all the different aspects of this equation, I was troubleshooting, the one I kept coming back to was the pull up on the dimmer board, since that’s tied into the zero cross input. I tried unhooking that pullup and then enabling the D1 input_pullup. I got the light to come on, but it just stayed on. I then tried reattaching the pullup on the board and enabling the D1 input_pulldown.

and voila! The TimerInterval dimmer code is working successfully.

So, now this inquiring mind wants to know why? Is this a pro mini vs Spark thing? Is this a Timer1 vs TimerInterval thing? all of the above?

Thanks as always.

It still sounds like some hardware issues, because having a pull up and pull down to make it work is quite unusual. Are you referring to the 10k ohm R2 as the pull up resistor? What voltage rail have you tied the “+5V” side of that resistor to? Thanks, we’ll figure this out!


Yes, R2. Per your instructions on making the dimmer board 3.3v, it goes right to the 3.3v pin on the Spark.

Ok… well that’s good… but I THINK if you have to add a pull down to make it work, then the OPTO is not pulling the line down itself very well. This could be due to R1 being too high in resistance, not biasing the LED in the OPTO hard enough. I don’t have time currently to check out the datasheet, but perhaps lowering the value of R1 a bit would help. You must be VERY careful here because it’s 120VAC and an OPTO’s LED is typically rated for <=5V in reverse, which simply means they may be playing some tricks here to make that circuit really inexpensive. Perhaps it should have a better voltage conditioning circuit comprised of a zener diode before it goes to the LED. hard to know without digging in a bit. I can look later on…

I know you are thinking, but it works on arduino!! well… pullups on arduino may be slightly different… input current requirements… etc… If you make the output of that OPTO mostly digital in nature, ON or OFF with decent drive, then the electrical characteristics of the microcontroller input matters a lot less.

1 Like

Ok, looking at the datasheet… I see that the OPTO symbol on that above linked schematic doesn’t show the full picture. That H11AA11 OPTO has two LEDs back to back in reverse polarity of each other, so when the input reverses such as it does with AC you get the forward voltage drop of one LED (about 1.15V) acting as a clamping diode so the other reversed LED doesn’t see more than 1.15V across it in reverse.

Checking the bias, it seems to be more than adequate, about 3mA of drive… yielding a full saturated output transistor (i.e. it’s ON - Collector to Emitter voltage drop of 0.1V typical) with more than enough current to pull a 10k ohm resistor fully to ground without the need of the internal pulldown resistor.

It should seem that the hardware is ok, however your experiments tend to suggest otherwise.

This would be a great problem for an oscilloscope to solve :wink: Do you have one? I would look at the D1 input when you have the external pullup only, external pullup AND internal pulldown, and finally internal pullup only on the spark core… but then also whatever works great on the arduino… look at that input as well.


Thanks again for your continued support and diligence @BDub. Per @Peekay123 recommendation, I did just get my Xminilab over the weekend and once spun up on it will start digging in on D1. Cheers.


Ok, looking back at this I think you might have a little trouble discerning things with the xminilab, but it should help you nonetheless.

What I didn’t initially pick up on since this is a continuation of another thread, is that the schematic I’ve been referring to is not the one you are working with! Please correct me if I’m wrong here, but this is the one you are posting as “your” schematic:

If that’s true, you may have damaged your OPTO if it’s a 4N25M

These don’t seem to have dual back-to-back gallium arsenide infrared emitting diodes, but rather just one. Which means it will have a Vr (reverse bias voltage) spec, and this one is 6V. So in one phase of AC, you are ok… but the other phase you are reverse biasing the LED with 170pk volts. Likely to damage the opto. If you simply wire two of these in parallel back-to-back on the inputs and parallel collector-to-collector and emitter-to-emitter on the outputs you’ll have a pretty good substitute for the H11AA1 that has two LEDs.

I’d still like to see what the output on your Xminilab looks like though as well so report back when you can :smile:

1 Like

No, that’s not the schematic. You already referenced the correct schematic 8 days ago when you used it to give me the directions to convert the board to 3.3v. You even cited the correct url yourself:

Now on to the oscilloscope testing…

I’m pretty confident I now know what my zero cross detects (zcd) look like on the xminilab…pretty cool. I first did those measurements right from the wire coming out of the H11AA1 bypassing the Spark and got the results I would have expected… ~3.3v spikes every ~8.8ms.

Next, I put that wire into D1 (without pulldown) and the zcd reading just flat lined. Just for the hell of it, I then put the wire into any digital pin and got the same result.

With the pulldown enabled, as expected, the zcd keeps going. The only difference I saw was that the peak voltage of the zcd at the pin decreased to 2.56v.

Next, I over wrote the sketch on the Spark with just a bare minimum empty setup and loop. I got the same results on all digital pins. The zcd was beating like a heart one second and then gone the next. And yes, I did try the same experiments on my 3.3v pro mini. The zcd remained alive on all pins.

And that’s what I know about that. :slight_smile:

That is really weird. I don’t think I have ever heard of a situation where an internal pull-down was needed to see a high signal on a pin. Are you sure the grounds are connected together when you are using the Spark?

I do think that 10K is too large for the collector resistor for 3.3V. I would shoot for a collector current of 1mA and would pick around a 2700 ohm resistor instead. But I would think that 10k ohm should still work.

Thank you @bko… A data point that I forgot to share was resistance across those digital pins. The native resistance (withouth anything connected) I read on all digital pins was 35 ohms. When I attached the zcd wire to any digital pin, the resistance jumped 100+ ohms to 135-137 ohms. That is when the zcd flatlines.


The latest today may just be another mystery or a V-8 moment for someone… So, I got the dimmer code working without the pulldown. Just for the hell of it, I changed the zero cross detect input from being digital (D1) to analog (A1).

Any issues with letting it run that way?

Glad it is working and there are no issues with A1. Did you try D2 or any other interrupt-able digital-only pin?

I wonder if some of the magic smoke got let out of D1 at some point–like one of the internal protection diodes is blown.

By the way, it is not a good idea (or really useful) to measure the resistance of live circuits or IC inputs. The ohm meter puts some voltage across the leads so it can measure the resistance and lots of meters have “diode” setting that puts out more than 0.7 V so you can check diodes for forward and reverse bias and this can upset your IC input. This is not really measuring anything useful in this case. You can measure voltages and currents and often calculate resistances of course.