User Tools

Site Tools


Luminous Advent Calendar

Lovely LEDs in most of the colours of the rainbow.


Who doesn't like advent calendars? Even if one doesn't celebrate Christmas or tries to shield oneself from the festive season as much as possible, there is something special about advent calendars. I think it's the counting down towards an arbitrary goal, a new surprise (maybe chocolate!) every day and of course the objectification of anticipation. A bit like obsessively following the tracking information on a package, when you think about it.

At some point in late November 2015 a retina-searing LED arms race (sparked by some harmless albeit woefully underpowered Christmas decorations) was well under way in the office. This almost naturally led on to building an LED advent calendar, so that the combined joys of advent calendars and LEDs could be shared with my colleagues.

Unfortunately, as mentioned above, December was already looming on the horizon, so a decision on exactly what kind of LED advent calendar should be constructed and procurement of components had to proceed with the greatest haste. The following is a day-by-day account on the development of the luminous advent calendar:

  • Thursday, November 26: At some point during the day I figured that having one LED for each day, and a different colour for each LED - all nicely arranged in a rainbow strip - would probably look nice. The evening was spent trawling electronic component distributors' web sites to ensure the feasibility of obtaining LEDs with sufficiently different colours on short lead times.
  • Friday, November 27: The evening was once again spent online, studying LED datasheets, cursing at the aforementioned distributors' web sites for seemingly randomly picking values from the datasheets for their parametric search (Peak wavelength? Dominant wavelength? Minimum? Maximum? Typical? Clear? Diffused?). However, I finally succeeded in ordering just under 30 LEDs in the same package with hopefully visibly different wavelengths. The orders were placed a few minutes before the next-day delivery cut-off time, as usual.
  • Saturday, November 28: A comparatively serene day, which saw the development of the software that would ultimately control the advent calendar. In order to keep development times as short as possible, I opted for my favourite “I need a microcontroller in there right now, but don't care too much about it” solution - the trusty mbed LPC1768.
  • Sunday, November 29: A day of rest to gather the strength needed for what would lie ahead.
  • Monday, November 30: In order to motivate myself to follow through with the project, I made sure to let my colleagues know that there would be a surprise tomorrow. Despite the ominous language used, my accent that had me likened to Bond villains more than once, and my well-known interest in thermonuclear devices, I was neither called in by HR nor detained by the police. The evening saw an assembly and soldering marathon, which started off by carefully adjusting LED currents to equalise perceived brightness, but as midnight drew closer, the priorities shifted to fixing dodgy solder joints and re-doing half of the wiring where I had gotten the pinouts wrong. However, I did succeed and within the last 15 minutes of November the advent calendar was finished by carefully applying a Dymo label.
  • Tuesday, December 1: How surprised my colleagues were, and how much joy the advent calendar brought us for the next four weeks. All the guessing of what it would actually do, the betting on which LED would come on next, the inevitable pranksters attempting to tamper with it, and people asking if they could push the button the next day - definitely a huge success that shows how much one can do with even a simple project.

No hacky project would be complete without the application of a Dymo label.


After carefully thinking about what it is that makes advent calendars exciting for me (doing something, getting a surprise, building up towards something), I came up with the following concept that consists of:

  • 24 LEDs of different wavelengths, arranged by colour
  • One big button, to be pushed once a day

The calendar starts off with all LEDs turned off. When the button is pressed, a random LED turns on (and remains on). Each additional push of the button turns on an additional LED, until all 24 are lit after 24 days.

As always, there are a few complications:

  • In order to prevent a “ripping the advent calendar open and eating all the chocolate at once” incident (i.e. turning on LEDs early), the calendar keeps track of the time elapsed sine the button has last been pushed. A new LED will only come on if the last successful push of the button was more than 10 hours ago. That time interval was chosen to account for the possibility of the button being pushed at any point during the working day (e.g. 17:00 on one day, and 07:00 on the next).
  • However, after weekends or days off it should be possible to catch up on the missed days without the 10-hour interval. For example, it should be possible to push the button thrice in a row for three LEDs to come on on a Monday morning - once for Saturday, once for Sunday, and once for Monday. In order to make this possible, several LEDs can be lit in succession if the previous push of the button is more than 24 hours in the past. In effect, every 24 hours since the time the button was last pushed allow an LED to come on without the 10-hour lockout time.
  • The current state of the advent calendar is stored in the mbed's flash memory, and is accessible through the file system. This is great for debugging and makes the firmware quite a bit simpler, but it does have the unfortunate side effect that pranksters can tamper with the files. Luckily, a “feature” of the mbed's file system implementation means that it won't show up as a USB mass storage device if there are any open file handles. In the case of tamper-proofing the advent calendar this can be used as an advantage - simply open a dummy file and keep it open, and it won't show up on the computer. This appeared to be enough of a hurdle to put an end to the mischievous deeds of the chief office prankster.


The circuit used is embarrassingly simple: Each LED is powered from the USB supply, driven by a ULN2003, and has its current limited by a trimmpot. There is one GPIO pin for each LED, so no fancy multiplexing or anything clever.

LED driver schematic. There are 24 of these.

There are a few reasons why this rather inelegant and simple driving method was chosen:

  • Despite the large number of components, it was actually fairly quick to build
  • Having one trimmer per LED allows to set the current reasonably accurately to balance brightness
  • Without multiplexing, the LEDs can be easily driven with a PWM waveform.

The resistor values for the trimmers were calculated beforehand to get a rough idea of the values required to equalise the perceived brightness of all LEDs. However, as one would imagine, there was quite a bit of tweaking involved in the end to get everything looking just right - and unfortunately I ran out of trimmers of the same style and had to resort to a few even crustier ones from my box.

Apart from that, literally the only other components on the board are a pushbutton switch with a pull-up resistor and a CR2032 for the battery-backed RTC of the mbed.


Doesn't look as good with bright light coming from above.


Like the hardware, the firmware is really quite simple - It primarily consists of a state machine that deals with the switch input and turns on LEDs accordingly. The current number of LEDs that are on, and the sequence in which the LEDs turn on are kept in files on the mbed's embedded flash (accessible through the mass storage device).

One of the very few aspects of note about the firmware is the bit-bang PWM: When an LED turns on, it fades in slowly over a second or so. Since the mbed doesn't have 24 PWM channels and the LEDs aren't multiplexed, I had to implement a software PWM generator. This will works on any one pin at a time and is reasonably accurate and stable because the state machine is clocked and the time taken to execute it is fairly constant. The fade-in of the LEDs follows a quadratic duty cycle in order to get a perceived linear (well, close enough) fading effect. Again, thanks to the computing power provided by the mbed this task did not even pose a remote challenge.

Github repo coming soon.

projects/advent.txt · Last modified: 2016-02-10 21:14 by robert