I decided to decorate my new desk. It has a dark grey metal screen around the back, and I thought it would look cool to shine some LEDs up there. I got half a dozen red LEDs, standard 5mm type, a 150-ohm resistor for each, an Arduino pro mini, and a tiny plastic housing. A little soldering and wiring later, and I had my gadget. I’ve spaced the LEDs evenly along the back of my desk, held on to the metal screen with binder clips. There is enough ambient light here that they don’t illuminate the screen quite as much as I’d hoped, but they still look cool, and it’s probably better not to make them too distracting anyway.
The first comment I got was “Looks cool! Next step RGB!”, which snapped my ego just a tiny little bit. No, really, I wanted to say, I could do full 24-bit color if I wanted to! Really! I’ve done it before! This whole “warm steady red” thing was an artistic choice! Er. Oh well, I like it.
// six-way LED fader for arduino
struct light_t {
int pin;
unsigned long startTime;
unsigned long period;
};
static const int kLights = 6;
static light_t light[kLights] = {
{3, 0, 0},
{5, 0, 0},
{6, 0, 0},
{9, 0, 0},
{10, 0, 0},
{11, 0, 0}
};
const int kMinPeriod = 4000;
const int kMaxPeriod = 32000;
unsigned long randomPeriod()
{
return random(kMinPeriod, kMaxPeriod);
}
float curve(float val)
{
// The apparent LED brightness should follow something like
// a bell curve: starting at zero, swelling up to 1.0 at
// the halfway point, then diminishing back to 0. We'll do
// this by mapping the input range over 2Ï€, then inverting
// a cosine wave and compressing it into our output range.
float curvemap = (1.0 - cos(val * 6.2831853071796)) / 2.0;
// Gamma-correct the value: optimal curve would be 2.2, but
// we can much more cheaply calculate ^2
return curvemap * curvemap;
}
void setup()
{
// Analog pin 0 is not connected to anything, so it will
// return some unpredictable noise. We will sample its
// starting value as our PRNG seed, guaranteeing that
// we get a different animation sequence each power-up.
randomSeed(analogRead(0));
// Pick a random starting period for each light.
for (int i = 0; i < kLights; i++) {
light[i].period = randomPeriod();
}
}
void loop()
{
unsigned long time = millis();
for (int i = 0; i < kLights; i++) {
// Subtract the current time from the start time, then use
// the sine to get the brightness appropriate to this point in
// the cycle. We do only half-cycles, the positive part.
unsigned long elapsedMillis = time - light[i].startTime;
float elapsed = (elapsedMillis * 1.0) / light[i].period;
int level = curve(elapsed) * 255;
analogWrite(light[i].pin, level);
if (elapsedMillis >= light[i].period) {
// Once we've finished the cycle, reset: pick a new, random
// period length, and start it up now.
light[i].startTime = time;
light[i].period = randomPeriod();
}
}
}
Pics! We need piiiiiiiiiiiics! :-)
Comment by Adam — June 25, 2010 @ 7:57 am