****This is the old Christmas Countdown that was retired in 2014 and replaced by the new pixel based matrix version.****
Back in January of 2005, in an attempt to find something to do with a PIC microcontroller (uC) and a little extra free time, I decided to make a Christmas countdown for my desk. That quickly got blown out of proportion and I set my sights on a giant yard display instead. V1.0 made it to the yard 3 days before Christmas 2005 and lasted for at most, 16 hours before I blew a bridge rectifier while at work. I decided to go back to the drawing board and tweak how I was controlling the lights. Below is the breakdown of my V2.0 display.
The main idea of the project was to make a big countdown that displays the days, hours, minutes, and seconds until Christmas. I wanted the digits to be large enough to be seen from the street, and I want the countdown to update once a second on its own. I planned to use a PIC uC as the brains, and Christmas lights for the segments in the digits. I wanted the display to breakdown as small as possible for storage, and be easy to set back up. While working through the code, I decided I also wanted it to countdown to any date, from any date (as long as it is within a 100 days). I wanted to be able to input the two dates (current date, and date to countdown to), and have the system determine how much time is left between them.
I started out with a uC from PIC Microchip called the PIC 16F877A. I decided on it because of my familiarity with PIC from college and the cheap compiler/simulators from people like Oshonsoft (and the ability to make programmers for it from scratch). I figured that this particular uC would have more than enough horsepower and had the necessary I/O lines I needed to control the display.
I began by writing some simple mini apps to: 1) verify that the TIMER1 (pdf) interrupt was working, 2) that I could take inputs from my push-buttons (making sure to de-bounce them), and 3) that I would handle functions correctly (including the interrupt service routine). I then started putting these individual pieces together using little 7-segment displays on a breadboard to verify that I could countdown from 9sec to 0sec , then 59sec down to 0sec, then adding in minutes, hours, days, until I was confident that it was counting down correctly. I let this run for days at a time to make sure I was keeping accurate time.
Once I felt that I could keep track of time correctly, I moved to verifying the algorithms for determining the proper time remaining between the start and end dates. This is easy when counting down to Christmas (the countdown date is 12/25 00:00), but is harder when counting to an arbitrary day/time from another arbitrary day/time. I tested, tested, tested, and kept writing down new scenarios so I could retest after any changes. It is a simple enough task, but due to the BASIC programming language I was using, large functions were difficult to do (this code could be much shorter if I would pony up the cash for a C compiler). I now had a completely working countdown on my desk using 8 small 7-segment displays and 3 breadboards.
I had inconsistent timing using a 32.768kHz crystal in V1.0 during the colder days (I had huge drifts) and I decided to revamp that for V2.0. What I ended up doing was using the TIMER1 interrupt like I initially planned with the crystal, but fed it a signal from a zero-cross detect IC (an H11A1) instead. With an H11A1, you run the “line” (hot) and neutral of 120Vac into it, and it sends a 5Vdc pulse out every time it detects a a zero-cross (0VAC). Essentially, you will see 120 pulses a second in the United States on our 60Hz lines. I preload the TIMER1 value with a value 120 less than the overflow and I decrement my countdown every time that an overflow condition occurs. If I keep track of the time with my watch, I see that I can be as far off as +/-6s on any given day, but it averages out to be perfect over a long period of time (it does not continuously increase every day), and I don’t see the severe changes due to the cold. For me, it is good enough; unless you are tracking it with a stopwatch, you will have no idea that is is 6s fast one day, and 4s slow the next, and 2s slow the third (making it 100% accurate over the course of 3 days).
The Digits Themselves
For digits, I planned to mimic the 7-segment displays of my mockup, but use mini Christmas lights instead. Christmas lights in the US are generally in 50 or 100 count segments (yes I know there are other odd sizes, but they are slightly different), and that is because each of the bulbs are rated for 2.4V (2.4Vac*50 lights = 120Vac). The 50 count lights are one string of lights in series (if you pull one bulb out, you will break the connection and all the lights will go out*); and the 100 count lights are two of the 50 count strings in parallel (if you pull out one of the lights, that particular string of 50 will go out, but the other string of 50 will remain on). What I did was cut my strings of 100 into smaller strings of 10, doing that meant I could power the mini strings with 24Vac.
*I know what you are thinking, “when one light goes out on my string on my tree, the rest stay lit!” That is because the bulb burned out and a little shunt in the bulb heats up and bends over completing the circuit in that bulb (essentially creating a short). So in that case, the rest of the lights can stay light, but if you pull the bulb completely, you are left with an open and all the lights go out.
For the framing of the digits, I used 1/2″ CDX plywood (pretty much the cheapest exterior plywood you can get), and drew a pair of digits on each section. I then drilled 10 holes per segment, 7 segments per digit, 8 digits total (4 pairs of digits). I made the holes larger than the size of a bulb so I could paint everything. I coated the wood with outdoor wood primer (painstakingly getting into all 560 holes) and then spray painted the wood with a flat black paint (so the light for the digits would stand out and not glare on shiny wood). I then poked the lights from each mini string of 10 lights into the segments and added a dab of hot glue on the back of each to hold them into place.
Controlling the Digits
When I was using the 7-segment LEDs, I could use the 5Vdc output from my uC to light each individual segment, but my large Christmas light digits required 24VAC per segment. I was able to get my 24Vac by purchasing two surplus transformers online from MPJA (120VAC-to-24VAC transformers seem to very common), but I needed some way to switch the digits with that higher voltage. One method I could use was a relay for each segment, but then I would need 56 of them (7-segments * 8 digits), and that was going to get expensive (and take up lots of physical space), so I decided to go with some homemade Solid State Relays (SSR) to do the trick. An SSR is nothing more than a triac and an optocoupler working together to switch an AC voltage using a small DC voltage. Now with my 56 SSRs built, I could switch any of the segments using the same approach as the LEDs, but with some extra parts bought online (opto: MOC3063; triac: SC-129D). SSRs are a great thing and I have some info here on them (TODO: add link with some description and links to P.C., etc.), just make sure that you keep your current down (or add some heat sinks) and watch that you don’t shock yourself (been there, done that)!
Speaking of current, I figured I should write down some back of the napkin math in case anyone is interested. A string of 100 mini Christmas lights use 120V, and it draws roughly 333mA (0.333A). This means that using the power equation (power = current * voltage), the string of 100 lights draws 40Watts. This also means that we draw 0.4Watts per bulb (40W/100 bulbs=0.4W/bulb). I am running 10-light segments, but the bulbs still have the same properties of drawing 0.4W/bulb; so my segments will need 4W each (10 bulbs * 0.4W/bulb). 4Watts at 24Vac means I am drawing 167mA in each segment. A worst case scenario is that every segment is on at the same time for some flaky reason (88days, 88 hours, 88mins, 88seconds), and that would draw 9.3A at 24Vac. Planning for the unknown, I figure I want to be able to supply at least twice that (roughly 20A at 24Vac), so I picked up two transformers that can source 10A apiece.
The Hardware and Wiring
If you look at my schematic in pdf, you can see that the uC drives eight 74HCT373, these are latches to hold the current configuration for that particular digit. I did that so I would only have to update a particular digit when that digit needs to be changed (the enable pins are controlled by separate I/O lines from the PIC). The output from the latch goes into a darlington transistor array (ULN2803). The darlington’s give us the ability to supply more current on its output than the whatever is on its input can supply (in this case the latch’s output). When a positive voltage is applied to the input of the array, the output becomes a sink; when a ground is applied to the input, the output becomes high impedance which will turn off our SSRs. The other nice thing about the darlingtons is that they add another level of separation between our low voltage DC board (with the uC) and the 120Vac running through the SSR boards.
Purely for the sake of my sanity, I wired everything up in a color coded order. I had scrap Cat5 cables lying around, and it has 8 different colors of wire in it (orange, orange/white, brown, brown/white, blue, blue/white, green, and green/white). Since there was a lot of repetitiveness to my circuit, I needed the color coding for ease of debugging and testing. I assigned the digits (from right to left) colors increasing in the alphabet (blue, blue/white, brown….etc) for my enable pins, and then did the same thing for the segments (top segment = blue, top right = blue/white, bottom right = brown). This proved IMMENSELY helpful while debugging everything.
Wiring Up the Digits and the Weatherproof Project Box
Taking advantage again of my spare Cat5, I used it to run power out to my digits from my “weatherproof” project box. I used standard RJ45 Ethernet keystone jacks like you would use at home for a wired Ethernet network and wired them to my custom SSRs. Then I wired another keystone jack inside a vertical piece of PVC sealed at the top and open on the bottom and ran the Cat5 from my board out to the digits. In doing it this way, everything stays dry during the winter months.
My project box is nothing more than a large Rubbermaid bin. I built a small wooden shelf to sit in the box and hold my power strip, my PCB, and my 12VDC converter to run two small fans. I cut 4 small holes (one for each pair of digits) in the front of the box near the bottom and ran my pairs of Cat5 out the holes. I then used the foam pipe insulation you wrap around PVC piping in your house to seal up the holes like a grommet. On the backside of the box I ran out the cord from the power strip that powers the whole display and again filled the hole with the insulation. I made these holes near the bottom of the box so if water does get in, it will be below all the circuitry and wires (because of the shelf). I had the two fans to blow air around the box in case the transformers get warm (in doing this, I have never had any heat problems in the box).
After a couple of years of sitting in the dark cold nights resetting the time after minor power glitches or if I needed to turn it off for some sort of maintenance, I decided to add GPS to the display to set the time. I now have: a switch for whether or not to use the GPS, and another one for whether or not we are counting down to Christmas. If the GPS is enabled and the display is set to countdown to Christmas (via a second switch), the display will automatically turn on the GPS, wait for a valid fix, and then pull the time from the fix, calculate the time until Christmas, and start counting down. The beauty of this is that all this can happen autonomously while I am at work if there is a slight brownout.
I bought my GPS from Futurlec and am fairly happy with it. I currently have the GPS connected to an SSR and only turn it on when needed. Once it turns on I sift through the serial outputted NMEA sentences until I find a $GPRMS sentence. Once I find the sentence I want, I look at the fix status; if invalid I dump it and start over, if valid I pull in the time sequence. Once I have the time, I then run the rest of my application like I would if I had entered the time by hand. Once I get the time, I turn off the GPS module (via the SSR) until it is needed again at next boot up.
The code can be found here (the .bas file can be opened in notepad). Some of it is commented well, some of it not at all, but it is there as a reference for you. Because of some of the limitations with the compiler I was using, the code ends up being uglier than it should be (the way nested ifs work, etc.).