This add-on to a Soleil Sun alarm lets the clock control the brightness of a bank of LEDs. A microcontroller adjusts the power of the LEDs so they appear to dim at the same rate as any incandescent lights you may have attached to the alarm.

Step 1: Background

We run a tight ship here at Squid Labs. Partners are expected at their desks, pencils ready, at 7:00 AM sharp. Given the 4-hour each way commutes typical of the Bay Area and 12-hour works-days, there's not alot of time left for sleeping! So, anything to simulate a natural existence, like a sunrise, is greatly appreciated.

I use a Soleil Sun alarm with its incandescent light controller to simulate sunrises in the morning. It works fairly well and often I wake while the lights are about half brightness, before the radio comes on. Recently, a few close friends, some with seasonal affective disorder, have started using a blue light box -- the Golite -- and swear by it's effectiveness.

Despite having timers on the Golite, it doesn't have an alarm setting and won't turn the LEDs on automatically. Worse, in darkness, the lowest light setting of 10% isn't that different than 100%, and compared to a "sunrise" driven by incandescents, the difference between 0% and 10% is quite jarring. I wanted to try blue light and so decided to build my own LED light source integrated with my alarm clock.

Step 2: Parts and Materials

Here's what I used and where I got it.

Blue LED light box - click for Instructable

Atmel ATMEGA8-16PI (buy a few in case you burn one out) - Jameco.com
Optoisolator 4N35 - Jameco.com
5 volt regulator, LM341T-5.0 for example - RadioShack

lying around the shop but available at RadioShack or Jameco:
1 kOhm resistor
470 Ohm resistor

Step 3: About the Soleil Alarm Clock

The manual of the alarm clock claims the "data port" spits out a 0-5 volt signal that is read by the external 300 W controller. With dreams of reusing parts of the PWM motor controller described here, I probed the output.

Turns out it's a 190 Hz 0-5 volt PWM signal with a duty cycle that varies in 44 increments of 120 us each.

Step 4: About the LEDs and Driver

You might, as I did, think that you could add a transistor to flip the duty cycle of the alarm clock and plug it straight into the external control of the BuckPuck (5V equals off, so if the driver is used without electronics its default state is on). This works, but the lowest brightness level from the clock (one 120 us long pulse every 5.2 ms) looks nearly the same as full blast. Incandescent lights only appeared as bright as the LEDs midway through the cycle.

So, I brought in a microcontroller to generate a PWM signal with greater resolution. (This project is totally doable without a microcontroller -- in fact, while getting up to speed on the Atmels used here, I used the LEDs under direct control of the alarm clock.) At 130 Hz, a pulse 1 us long does not turn the LEDs on; a 2 us long pulse just barely turns them on. So, 16 bit PWM appeared to be enough.

Step 5: Logarithmic Ramp

Again, due to the nature of the LEDs, a linear increase of the PWM signal did not look right. Knowing that the clock only has 44 discrete steps, I shaped an exponential function that would hit these approximate values:
f(0) = 65534 (65535 = 5 volts = off)
f(2) = 65533 (just barely on)
f(13) = 99.84% of 216 (somewhere around 20% of full on)
f(44) = 5% of 216 (full power)

A plain old exponential of the type f(x) = A(1-exp(Bx+C)) couldn't do it. The rate of change needed to change over the range of x, so I tried:
f(x) = A(1-exp( (Bx + D)x + C) )
Solving it directly proved too hard, so I made a spreadsheet and adjusted the parameters by hand.

This could also be done with a lookup table. However, when I started, I was convinced I could find the exact function, and so a lookup table seemed like a huge cop-out.

Step 6: Build Circuit

Build the driver circuit.

Step 7: Setup to Program Microcontrollers

I choose Atmel Mega8s because they are rapidly becoming the microcontroller of choice around Squid Labs. The Mega8s have some nice features that make them a great choice for this project including interrupts synced to external signals, 16-bit PWM, and an 8 Mhz clock. The one drawback is that you need an Atmel programmer. Here is a description of programming Atmels using the parallel port, which could be adapted to this project.

I use Context to edit my code, and avr-gcc from WinAVR to compile it. I couldn't get the programmer bundled with WinAVR to work with my programmer, so I used AVR Studio 4 instead.

When you open AVR Studio, press the small "AVR" button shaped like a microchip to get to the programmer menu.

Step 8: Wire Up Programmer

If you're like me, you'll need to compile and try the code many times before it actually works. Taking the Atmels in and out of the programmer can get really annoying, so I ran wires directly into the breadboard.

Run wires between the programmer and the ATMEGA8 for pins 1, 7 (VCC), 8 (GND), 17, 18, 19, 20 (AVCC), 21 (AREF), and 22 (GND).

Step 9: Program Microcontroller

The code and makefile are written to work with avr-gcc. Briefly, it calculates the duty cycle from the clock, calculates the desired LED control level, and spits out a PWM signal. There's some averaging of the input and output values to reduce undesired flashing of the LEDs (like when they are just starting a sunrise). Essentially, the microcontroller acts as a nonlinear PWM filter.

Code: (download the .c file rather than cut and pasting this text; there are some formatting issues with the syntax)

/* LED microcontroller dimmer for use with Soleil Sun AlarmWritten for Atmel ATMega8 and avr-gccEric J. WilhelmSquid Labs, LLCAttribution-NonCommercial-ShareAlike 2.5You are free:    * to copy, distribute, display, and perform the work    * to make derivative worksUnder the following conditions:by Attribution. You must attribute the work in the manner specified by the author or licensor.Noncommercial. You may not use this work for commercial purposes.Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one.    * For any reuse or distribution, you must make clear to others the license terms of this work.    * Any of these conditions can be waived if you get permission from the copyright holder.*/#include <inttypes.h>#include <avr/io.h>#include <avr/interrupt.h>#include <avr/signal.h>#include <math.h>#  define OC1 PB1#  define DDROC DDRB#  define OCR OCR1Avolatile uint16_t xtimer;volatile uint16_t timer0;volatile uint8_t status;SIGNAL(SIG_OVERFLOW0){  timer0++;  TCNT0=96;          // preload the timer with 96 to make this interrupt occur every 20 us.}SIGNAL(SIG_OVERFLOW1){  //The interrupts don&apos;t work properly without this definition.}// falling edge PWM signal (rising edge at clock; reversed due to optoisolator)SIGNAL(SIG_INTERRUPT1) {  // Zero timer0 to count the length of the positive pulse  timer0=0;  status=1;}//rising edge PWM signal (falling edge at clock; reversed due to optoisolator)SIGNAL(SIG_INTERRUPT0) {  //record the length of the positive pwm signal in xtimer  // if timer0 is greater than approximately 263 (at 20 us per interrupt) than the pulse was missed  if(timer0<270) xtimer=timer0;  status=0;}voidioinit (void){    // Timer1 does ~16-bit PWM    TCCR1A = _BV (COM1B1) | _BV (WGM11) | _BV (COM1A1);    TCCR1B = _BV (WGM13) | _BV (WGM12) | _BV (CS10);    ICR1 = 65535;    //Timer0 counts    TCCR0 =  _BV (CS00);    TCNT0 = 96;    timer0=0;    // set PWM value to 0    OCR = 0;    //enable OC1 as output    DDROC = _BV (OC1);    //enable external interrupts    GICR = _BV (INT1) | _BV (INT0);    //INT0 is rising edge, INT1 is falling edge    MCUCR = _BV (ISC01) | _BV (ISC00) | _BV(ISC11);    xtimer=0;    status=0;    //enable timers    timer_enable_int (_BV (TOIE1) | _BV (TOIE0) );    // enable interrupts    sei ();}intmain (void){    #define B -0.00325    #define C -11.09    #define D 0.396503    int i,on=0, oncounter=0;    unsigned int x(100), y;    long t(100), u;    ioinit ();    for (;;) {            //average xtimer over samples because it jumps around alot      for(i=99;i>0;i--) {        x(i) = x(i-1);      }      x(0) = xtimer;      y=0;      for(i=0;i<100;i++) {        y = y+x(i);      }      y=y/100;      //divide by 5 because the clock has 120 us resolution on its PWM      y=y/5;      // average the output so it doesn&apos;t jump around      for(i=99;i>0;i--) {        t(i) = t(i-1);      }      //determine what to do      if(timer0>270 && status == 1 && on == 1) {        //Turn light on        t(0) = 0;        on=1;        }      else if(timer0>270 && status == 0) {        //Turn light off        t(0) = 65535;        xtimer=0;        on=0;        oncounter=0;        }      else if(timer0<270){        t(0) = 65535*(1-exp((B*y + D)*y + C));        if(t(0)>65535) t(0) = 65535;        if(t(0)<0) t(0) = 0;      }      //oncounter prevents the light from turning on suddenly from an off state if timer0>270, but there&apos;s a positive pulse on the PWM      //this happens during the very start of a sunrise, when the clock&apos;s PWM hasn&apos;t quite turned on at the right frequency      else if(timer0>270 && status == 1) {        if(++oncounter==5) {          on = 1;          oncounter=0;        }      }      // average the output so it doesn&apos;t jump around      u=0;      for(i=0;i<100;i++) {        u=u+t(i);      }      //Change the output PWM      OCR = u/100;    }    return (0);}

Step 10: Build Connection Cable

Use two male 1/8 plugs and a length of wire to make a cable.

Step 11: Connect LED Light Box to Clock

Connect the LED light box to your clock and enjoy gradual blue LED sunrises.
<p>I have that same alarm clock and LOVE it; it was a hand-me-down from a friend-BUT, I don't have the external lamp-controller. That would be a neat add-on, though I can't find one anywhere (probably because it's a 10+ year old clock). <br>Do you have any insights on how to rig one up? Or maybe there's a different after product that would work? I can't even find any pictures of the lamp-controller, so I don't know at all where to start. </p>
So the datasheet for the BuckPuck says that the ref pin outputs at 5V. Is there any reason I should use the a separate voltage regulator, as you have, rather than just powering the control circuit off the ref pin?
I wasn't sure how much current that reference pin could source, so I added a regulator.
Im making a wake up light for my final engineering project and and unable to find useful information :( <br>Can anyone help me with the circuit for the wake up light, please.
This design involves a risk for the eyes. According to Lumileds documentation : <font color="#231f20" face="HelveticaNeue-Light" size="1"><font color="#231f20" face="HelveticaNeue-Light" size="1"><font color="#231f20" face="HelveticaNeue-Light" size="1"> <p align="left"><em>&quot;Blue and RoyalBlue power light sources represented here are IEC825 class 2 for eye safety.&quot;<br /> <br /> <a href="http://en.wikipedia.org/wiki/Laser_safety#Class_2">http://en.wikipedia.org/wiki/Laser_safety#Class_2</a></em><br /> <br /> This means that LED can cause damage is the user stares at them. HB LEDs should always have a diffusor in front of them.</p> </font></font></font>
If you really want to safe, use 505nm (Cyan) LEDs as well as a diffuser. That's what I am doing. It should be 60% as effective as blue while having &lt; 10% of Blue Light Hazard (photochemical damage of retina).
My only comment is a PWM frequency of 190 hz can be detected by some people (I, for one), particularly at really low intensities. Something in the khz range might be a better idea.
Are you sure? 190 Hz is three times faster than AC powered lights and LEDs. At 30 FPS (effectively 30 Hz for this matter), movies must look really choppy to you! G3 (the G right under middle C) is 196 Hz. Can you "see" middle C?
Is it possible that there is a beat frequency effect between the 190 Hz and 60Hz incandescent or fluorescent lighting? I know 60, 70, and 72 Hz monitor rates bother me, but 80 and up are fine.
Definitely - 60*3=180 so at 190hz there is a strong risk of a 10HZ beat going on... and a dimmed incandescent bulb (depending on the dimmer) may have more &quot;flicker&quot; than one running at full power (the power-output is closer to a square wave).<br><br>I've never noticed a flicker at 190Hz myself, but I used to have an old monitor that would drive me crazy at &quot;90hz&quot; that wasn't quite 90hz and had about a 1hz beat; 75 was fine.
You can see flicker well into the KHz if it's a point source and you move your eyes fast enough.<br />
It's kind of like the "fluorescent light flicker" thing. Also, the lower the duty cycle, the more visible the flicker. Movie theatres give me a headache, for the same reason, I suspect.
personally i like the lamp a lot better than the light. that reflective surface is awesome.
Oooo i'm so close; the circuit is made, the programmer is built.<br/>I've got it working without the nonlinear code; but I'm getting compile errors when running the makefile. :(<br/>I suspect they've changed the codebase of the reference files.<br/>downloading the latest avr-gcc, and comiling using the make files:<br/>make -f makefile.txt<br/>gives me the following error:<br/>Google search returns a couple of germans who've had similar problems but it looks like they didn't have resolution.<br/><hr/>C:\Users\Brian\Documents\atmel&gt;make -f makefile.txt<br/>avr-gcc -g -Wall -O2 -mmcu=atmega8 -c -o pwm_int.o pwm_int.c<br/>In file included from pwm_int.c:21:<br/>c:/progra~1/winavr-20070525/bin/../avr/include/avr/signal.h:36:2: warning: #warning &quot;This header file is obsolete. Use &lt;avr/interrupt.h&gt;.&quot;<br/>pwm_int.c: In function 'ioinit':<br/>pwm_int.c:88: warning: implicit declaration of function 'timer_enable_int'<br/>avr-gcc -g -Wall -O2 -mmcu=atmega8 -Wl,-Map,pwm_int.map -o pwm_int.elf pwm_int.o -lmpwm_int.o: In function `ioinit':<br/>C:\Users\Brian\Documents\atmel/pwm_int.c:88: undefined reference to `timer_enable_int'<br/>make: *** [pwm_int.elf] Error 1<br/>
Add #include <compat/deprecated.h> to pwm_int.c after the math.h line. HTH.
tried every version of avr-gcc back a couple of years, with mixed results; nothing quite as neat as the error I reported. Any chance you could help me out ewil? Brian
Here's my entire "alarm clock code" folder. Maybe something in it will help? As I've written before, if I were to do this project again, I'd us an Arduino to simply the coding.
Thanks ewil. Your circuit kicks'a.<br/>Just went to the electronics store and bought nigh on $150 of tools to build this.. :)<br/>I'm fairly experienced building circuits, but horrible at modifying circuits; and i've never created a digital circuit. I'm hoping this might break me into the techniques.<br/>I'm finding it hard to read the circuit diagram however. The text is nigh on unreadable; even after clicking the &quot;i&quot;.<br/>Also.. having tried to decifer the component list:<br/> Are they 1W or 3W stars?<br/> What wattage are the resistors?<br/> Will 1 watt voltage regulator do?<br/> I could only get a 24V 1000ma power supply. Do I need to modify the circuit at all?<br/> Also I couldn't get a hold of an optoisolator.. &quot;discontinued&quot; aparently; i'll get one online. Whats the purpose of this component? Simply to isolate it from the other circuit?<br/> I've never used a buckpuck. There are options i've got no idea about; No dimming, Dimming with internal pot, Dimming with external pot; Also flying lead option. re: <a rel="nofollow" href="http://www.cutter.com.au/proddetail.php?prod=cut131">http://www.cutter.com.au/proddetail.php?prod=cut131</a> Too many options! heh.<br/><br/>Thanks; i'm really lost.<br/><br/>Brian<br/>
Apollogies, I see there is an attachment link for the schematic now. All other questions still apply.
Forgive me for saying this, but if you're having trouble determining the wattage of the resistors, you might want to try a few simpler projects before diving into this one. That said, it is good to always do things just above your ability so you can learn the most. <br/><br/>As mentioned <a rel="nofollow" href="https://www.instructables.com/id/ETB5G02AF7EP286KJV/">here</a>, I used Luxeon III's, which are 3 watts. The wattage of the resistors doesn't matter because they are not being used as power (dissipating) resistors. The voltage regulator only powers the Atmel, which draws far less than 1 watt. A 24 V power supply will limit the total number of LEDs you can drive, because they are driven in series and the total voltage of the system has to be greater than the combined drop across all the LEDs. The optoisolator prevents this circuit from affecting the circuit in the Soleil alarm clock. <br/><br/>If I were to do this project again, I would probably use an Arduino to avoid dealing with the Atmel programmer directly. <br/>
Thanks ewil. The research I did yesterday answered most of my questions. However I don't have a brains trust to check with, so I left the question alive. Thanks very much for the oppertunity to break into digital eletronics! :) Great circuit. I'll let the thread know if the circuit works out.
I'm looking forward to your results!
Which programmer is this - it's an ATMEL, but which? Looks like it has everything but the kitchen sink! Is it also a development board / emulator?
check here: <a href="https://www.instructables.com/id/EN8MERV5QOEP286HTY/">https://www.instructables.com/id/EN8MERV5QOEP286HTY/</a><br/>
I think it's cool.
A couple questions, what is the purple box? Is the 5v regulator powering the atmel? Would attaching the optocoupler across the speaker of a regular alarm clock have the same effect? (assuming I was going to remove the speaker) Thanks for putting your project up, looks great!
for the less technically astute. You can use the open source Day application to display any instances of Sunrise through the Window API.
Paint your lamp a primary color and you've might have the worlds largest milton bradley Sorry! piece.

About This Instructable




Bio: Eric J. Wilhelm is the founder of Instructables. He has a Ph.D. from MIT in Mechanical Engineering. Eric believes in making technology accessible through ... More »
More by ewilhelm:LEGO table with integrated parts bin Custom Wooden Train Track X-crossing Mad Max and War Boy Nux father son costume 
Add instructable to: