Introduction: 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
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
Step 1: Pulse Width What Now?
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!
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 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.
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 sunrisespeed. steps 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
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
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 :)
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 :)