loading
Picture of Simple Arduino Sunrise Lamp
Hate waking up in the dark? Me too.  I found a cheap 24 LED lamp and thought it would be fairly easy to make it turn on slowly using my Arduino, which should help banish some of those "waking up in the dark" winter blues.

You'll need:
- a "camping" LED lamp- I used one like this one
- an Arduino or other programmable microcontroller
- a timeswitch
- a "wall-wart" power supply
- transistors capable of switching about 500mA
 
Remove these adsRemove these ads by Signing Up

Step 1: Pulse width what now?

Picture of Pulse width what now?
sunrise_actualtime.PNG
sunrise_perceivedtime.PNG
A little background:

LEDs aren't like incandescent lightbulbs in the way they dim.  If you supply an incandescent lightbulb with a reduced voltage, it doesn't put out as much light.  LEDs don't work quite like this, and tend to turn on suddenly with a small increase in voltage.  The usual way of dimming LEDs is to turn them on and off very quickly- this is known as pulse-width modulation (PWM), because by varying the amount of time the LED is switched on (the pulse width) you can control precisely how bright it appears.

All we need to do is write a simple program that will turn on the LEDs dimly at first, with short pulses separated by longer periods of being switched off, and gradually increase the length of each pulse so making the LEDs appear brighter.

This gets a little bit more complicated when you involve the human eye.  It turns out, if you halve the amount of light an LED is actually producing, it appears more than half as bright.  The human eye perceives a very small difference in low light levels as significant, but doesn't notice small differences between higher light levels.  This means if we were to brighten the LEDs uniformly (starting at 10% brightness, then 20%, then 30% and so on) to a human observer it looks like it gets brighter very quickly at first, then slowly increases through higher levels of brightness.  To compensate for this we need to switch the LEDs on more slowly at first, then accelerate through higher light levels.

If that all sounds overly complicated to just turn some lights on, don't worry- I've done the maths so you don't have to!

Step 2: Software, part 1

The software consists of two nested loops- one to perform the actual switching on and off (PWM) and one to go through the increasing levels of brightness.  I wrote a loop to do the PWM by hand because the Arduino's built-in PWM only has 255 available levels of brightness, which meant that the lights would jump in brightness when first switched on.  I wrote a simple PWM loop with 1000 possible levels of brightness, which makes it more smooth.
int duty = 0;
int steps = 64;
int sunrisespeed = 5000;
int i;
int j;
int pulsepin = 11;

int lookup[64] = {1,2,4,6,9,12,16,20,25,30,36,
42,49,56,64,72,81,90,100,110,121,132,
144,156,169,182,196,210,225,240,256,272,289,
306,324,342,361,380,400,420,441,462,484,506,
529,552,576,600,625,650,676,702,729,756,784,
812,841,870,900,930,961,992,992,992};


// there are freq steps in the phasing
void setup()
{
  pinMode(pulsepin, OUTPUT);
}
The initialisation code declares two constants: steps and sunrisespeedsteps represents the number of different light levels the controller will use.  I used 64 as an arbitrary choice, and because it made the maths easier.  Sunrisespeed determines how long the program will spend at each light level- specifically, how many pulses it will output for a given pulse width.  Each on-off pulse in the PWM is 5 milliseconds long, so a sunrisespeed of 200 will produce 1 second (200 pulses of 5ms) of each light level.  WIth 64 steps this means the whole sunrise process would take about one minute, so to make the sunrise last for a more realistic half an hour we would set sunrisespeed to 200*30 = 6000.

int lookup[64] is an array- a list of numbers that can be accessed individually by giving a position in the list.  Rather than write a program with the necessary maths in it to calculate an increasing list of numbers that would account for the human eye's non-linear response, it was easier to just work out the list and save it in the program.  This is a programming technique known as a lookup table, often used when a program wants access to a short list of numbers that take a long time to calculate but aren't likely to change.

duty, i and j are variables that the program will use while generating the pulses.

Step 3: Software, part 2

Picture of Software, part 2
void loop()
{
  for (i=0; i<steps; i++)
  {
    duty = lookup[i] * 5;
    for (j=0; j<sunrisespeed; j++)
    {
      // one pulse of PWM
      digitalWrite(pulsepin, HIGH);
      delayMicroseconds(duty);
      digitalWrite(pulsepin, LOW);
      delayMicroseconds(5000-duty);
    }
  }
}

This is the part of the program that produces the pulses.  The inner loop produces a series of pulses at a given brightness.  It turns the LEDs on for a number of microseconds determined by the current brightness level, then turns them off for the remainder of 5 milliseconds.  This means the program generates a constant-frequency signal, which makes timing simpler.  The number of pulses is determined by sunrisespeed, which in turn determines how quickly the lamp brightens.

The outer loop steps through the array of brightness values, reading them out in order and producing a series of pulses of the specified brightness.  In this case, it multiplies the value from the lookup table by 5, because I initially calculated the values to range from 0-1000, but the Arduino isn't accurate at timing intervals less than 5 microseconds.  I used 5 milliseconds as the pulse frequency as a compromise- trying to pulse faster than this reduces the number of possible brightness values because of the Arduino's timing limitations, but pulses much longer than 5ms start to be visible to the human eye as flicker.

Once the loop reaches the end it just restarts at the lowest brightness setting- ideally at this point you would be awake, so can set the timeswitch to turn off the Arduino after the time taken by one complete cycle (in my case about 25 minutes).

Step 4: Hardware

Picture of Hardware
P7060023.JPG
The circuit needed is a little bit more complicated than the average "turn an LED on and off" circuit.  The lamp I used had 20 LEDs in the outer ring (I'm not using the inner ring). I used a multimeter to measure the current flowing when all of these LEDs were supplied with 5V, and it's about 650mA.  That is much more power than a single Arduino pin should output, so driving the LEDs straight from the Arduino would risk damaging it. 

The usual solution to needing more output current is to use the Arduino pin to switch a transistor on and off, but in this case I was a little dubious about even that.  I looked up the specification of the 2N222A transistor that came with my ARD-X kit and they can only handle 500mA each, so even one of those would be overloaded driving these LEDs.  Fortunately, the kit came with three of them so I put two in parallel to halve the current they would each be switching.

Once you've completed the circuit and tested it, upload the program to the microcontroller and disconnect it from the computer.  You can then connect the microcontroller to the power supply and plug the power supply into a timeswitch.  Set the timeswitch to turn on about 20 minutes before your actual alarm is due to go off, and turn off about 25 minutes after it turns on. If you have a 7-day digital timeswitch, you can even set it to turn on Monday-Friday and forget about it at weekends :)
Smelter_uk9 months ago

Is there a line of code that can be added to stop the "pulsepin" going "HIGH" at power up?

When I power up the Arduino the LED flashes at full strength before starting the ramp up.

Kind of ruins the point of the project.

hanlin_y1 year ago
Can you use analogWrite to adjust the brightness levels instead? Would the flickering be less noticeable? Here's a sketch without using delay. You can add other features to the lamp. I'm working on a sunrise simulator.
jcalbeto3 years ago
Wow! I am impressed!

I am working on a prototype that consists in a sensor (I don't know yet what sensor, maybe pressure sensor or light sensor) that switches on a set of LEDs that gradually light up (during 6 min more or less). At the end, there is a second sensor to switch off the light when wanted.

I am familiar with Arduino and I am able to understand more or less the easy code but I am not able to write it. So your code is exactly what I was looking for, thanks so much!

But I have some questions on how to addapt it:

- Which value should I write at the sunrisespeed to increase the time to 6 minutes? I messed up the maths...

and

- How do I mention the sensors to switch on and off the light at the code?


If you could respond in a short time I would really appreciate it!
Thanks a lot for your help!
PKM (author)  jcalbeto3 years ago
Making it switch on over a different time period is easy. It spends (0.005 * sunrisespeed) seconds at each brightness level, so (0.3 * sunrisespeed) seconds over the whole sequence. If you want this to take 6 minutes, that would be 360 seconds, and 360/0.3 is 1200.

(A simpler way to work this out is that I want mine to take 25 minutes and have sunrisespeed at 5000. 6 minutes is about a quarter of 25, so we want a quarter of 5000, or 1250.)

Making it respond to buttons is a bit more involved: you have to make the Arduino code check the values of input pins and start or stop the loop according to their values. How to do that depends on the switch or sensor you are using- if you already have an Arduino and the sensors you want to use I suggest finding a tutorial on using that type of button as an input and writing some examples.
jcalbeto PKM3 years ago
Thank you PKM!
I think I will manage with that!
gerrymoore53 years ago
Hi...this works perfectly but I want the light to stay on full brightness at the end of the lookup table...I was good with BASIC but not sure how to add this to the ardunio code...any ideas please...Gerry
PKM (author)  gerrymoore53 years ago
You could make it stay on indefinitely after turning on by replacing the loop function with
void loop()
{
  for (i=0; i<steps; i++)
  {
    duty = lookup[i] * 5;
    for (j=0; j<sunrisespeed; j++)
    {
      // one pulse of PWM
      digitalWrite(pulsepin, HIGH);
      delayMicroseconds(duty);
      digitalWrite(pulsepin, LOW);
      delayMicroseconds(5000-duty);
    }
  }
  digitalWrite(pulsepin, HIGH);
  while (1==1)
  {
  }
}

This means it will run through the fade-on sequence and then stay on forever, or until you turn the Arduino off.
gerrymoore5 PKM3 years ago
That's great!! I was looking at 'if then else' statements but the answer is so much simpler!!

As I want to build this as a permanent (winter) addition to our bedroom, and as I would prefer not to tie up my Arduino board, would it be possible to use this code on a little 8 pin Pic? I have a pic programmer but, as with the Arduino code, I struggle with the syntax for the language.

I am very impressed with the code...it seems very compact yet the 64 levels of brightness work perfectly...thank you for posting it.

cheers Gerry
PKM (author)  gerrymoore53 years ago
Hi Gerry,

Hardware-wise, this should be no problem. It's a very small program that I'd guess will fit on all but the smallest of microcontrollers. I'm not used to programming with PICs, but it seems you can write code for them in C so this program will probably work with only minor alterations. I don't know what facilities they have for timing delays, though, and I don't have access to a PIC programmer to experiment with so I'm afraid I can't help you with the specifics of the code.
gerrymoore5 PKM3 years ago
No probs...I need to learn anyway!!!! I'm pretty sure they have internal crystals so the delay should not be a problem....beauty is, it costs nothing to try :-))

Thank you again for your quick replies.....Gerry.
dmcvey13 years ago
Awesome project! I would love to do this project! However, I am very unfamiliar with Ardiuno. It is hard to tell the difficulty scale of this project. How long did this take you to do? Also, do you have more pictures of the final product?
PKM (author)  dmcvey13 years ago
I don't have any more pictures of the finished product, but it's not that pretty!

This project took me a while to do, mostly because I was experimenting while I did it to try to minimise flicker and provide the smoothest possible transition. All you have to do is copy and paste my code, maybe change the value of sunrisespeed if you want it to be faster or slower, and build the circuit.

I don't know how long that will take, but it's a fairly simple design so it should be quick once you have all the parts. Actually wiring everything up should only take you a few minutes if you have built circuits before, and once you know your way around the Arduino software then adding the code should be very quick too.