Dimmable AC Light Box


I went to the hardware hacker’s Mecca of Central Florida, Skycraft, and bought a hardware box to house my Solid State Relays in.

It was also during this time I learned that the Solid State Relays I were planning to use would not be ideal for dimming. I was learning about Zero-Crossing, and found the opto-22’s I had wouldn’t be fast enough to be fired in as many places as I would like for precise, 8-bit dimming.

I was donated a surface mounted TRIAC, and a MOC3021 opto-isolator to drive them. I built a reference circuit from the opto-isolator’s datasheet that allowed for the drive of inductive loads, but found that the circuit was producing a high pitched hum; it worked though. I connected the isolator’s on pin via resistor to a 5v+ source, and was able to tap a string of christmas lights on and off by touching the drive pin to 5v+.



I decided it was time to start coding a PIC to phase control the TRIAC, and as I knew the ultimate goal was to drive the TRIACs serially, I started to look into PICs that supported UART. It just so happened that the spare PIC16F628s I had supported hardware UART, and were common chips.

I wrote VERY preliminary code that counted from 0-15, over and over at different speeds, and illuminated the count via LEDs. I coded the test routine to count 16 different intensity levels with, and display the count by binary on 4 LEDs. Other than that, it did not do much else besides set up a framework for future code. The video below showcases the hardware I was planning to use at the time.


As is shown, early on I planned on using a Mini-ITX motherboard I had to run a daemon to interpret network packets via programmable scripts, and use them to drive the PIC I was going to code. While I did not end up doing this, this idea ended up being used later on…


The next part of my code was of course a lot more complex. I had to find a way to detect the zero-crossing, and to turn on the Triac at the appropriate time. Of course, this was dependent on having zero crossing detection circuit. I scoured the internet, and came across this design by Michael Pearce:

His design called for a transformer that would step down the 120v AC to 6-8v. While undesirable, I went with an oversized, over-kill transformer I bought from Skycraft. Even with the size, I still had more than enough space for it my project box. I know I could have gone with other ways of detecting zero crossing without a transformer, but as my number one goal was safety, I liked the idea of using the transformer as a natural protection as it would step down voltage efficiently.

In the design, the output of the transformer becomes rectified, and is eventually fed into a Transistor. When the base is driven low, it causes a pull up resistor to drive an input pin high. I would use this to trigger a hardware interrupt on the PIC. The design also used the stepped down voltage coming from the rectifier to drive a 7805 5v Regulator. As I was using a PSU rail at the time, I wasn’t planning on using this, but ultimately ended up using it for power as the ITX computer was taken out of the design.

The circuit also has an adjustable 10k ohm pot used to fine tune the zero crossing detection. I connected the output of the circuit to an oscilloscope, with the AC Sine Wave on a second channel. I found that the Zero Crossing detection pin would rise before the actual crossing. On the scope, I measured these two events happened about 1.2ms apart. I knew I would have to account for this with an offset..


Sometime, around 4AM, last Thursday, I came up with this mess of a pseudo-code..

What I ended up planning was to set up a hardware interrupt to detect the zero-crossing, and then I’d copy whatever value I had for channel brightness (as was set by counter debug code) to a channel work register. After, I would set up a timer to account for the offset. When the offset finished, I started the actual routine.

The routine would then loop for how many levels of brightness I desired -1, at the time 16, and add one to¬† the channel’s work register. I’d turn off that channel if the register did not overrun that pass, and turn it on if it did.

As an overrun would be any value that would exceed 255 (size of a byte) I used values 240-255 at the time to represent the 16 degrees of brightness, one of which being 0 of course. The routine would run for 15 loops, so if the value of 240 was used for a channel, by the end of the loop, the value would have become 255, and would have cut short before it overrun, hence never turn on. Likewise, if the maximum value of 255 was used, it would overrun the first loop, and hence be turned on. As 255 would overrun first loop every cycle, it would never turn off. These loops used a timer interrupt to space each half cycle 6.7% apart to have a linear scale of time for each value.

This would work great for this version of the code, (v0.4) but as I’d come to find I would run into problems once I increased to 256 levels of brightness.

Th early hardware I was testing with:


Youtube clip of early dimming code in action:


Next up, more permanent hardware, ICSP circuit, and optimization….


Pages: 1 2 3 4 5 6

About waterbury

Hi, you may also know me by my IRL name, Ted.