Computing stuff tied to the physical world

A color-shifting LED Node

In AVR, Software on Nov 5, 2011 at 00:01

Yesterday’s post described the logic which should be implemented in the LED node. It is fairly elaborate because I want to support subtle gradual color changes to simulate the natural sunrise and sunset colors.

Here’s the ledNode sketch – with a few parts omitted for brevity:

Screen Shot 2011 10 27 at 04 56 36

It’s pretty long, but I wanted to include it anyway to show how yesterday’s specifications can be implemented with not too much trouble.

The main trick is the use of fractional integers in the useRamps() routine. The point is that to get from brightness level X to Y in N steps, you can’t just use integers: say red needs to change from 100 to 200 in 100 steps, then that would simply be a delta of 1 for each step, but if blue needs to change from 10 to 20 in exactly the same amount of time, then the blue value really should be incremented only once every 10 steps, i.e. an increment of 0.1 if it were implemented with floating point.

And although the gcc compiler fully supports floating point on an ATmega, this really has a major impact on code size and execution performance, because the entire floating point system is done in software, i.e. emulated. An ATmega does not have hardware floating point.

It’s not hard to avoid using floating point. In this case, I used 32-bit (long) ints, with a fixed decimal point of 23 bits. IOW, the integer value 99 is represented as “99 << 23” in this context. It’s a bit like saying, let’s drop the decimal point and write down all our currency amounts in cents – i.e. 2 implied decimals (€10 = 1000, €1 = 100, €0.50 = 50, etc).

To make this work for this sketch, all we need to do is shift right or left by 23 bits in the right places. It turns out that is only affects the setLeds() and useRamp() code. As a result, RGB values will change in whatever small increments are needed to reach their final value in the desired number of 0.01s steps.

The sketch compiles to just slightly over 5 Kb by the way, so all this fractional trickery could have been avoided. But for me, writing mean and lean code has become second nature, and sort of an automatic challenge and puzzle I like to solve. Feel free to change as you see fit, of course – it’s all open source as usual.

So there you go: a color-shifting LED strip driver. Now I gotta figure out nice ramp presets for sunrise & sunset!

  1. But for me, ogling in amazement the mean and lean code others have written has become second nature, and sort of an automatic puzzle encouraging me to learn more, faster.

  2. Nice, but I think handling the chains inside the ramps will hurt flexibility in the end.

    How about defining chains seperatly (e.g. just as a list of ramps).

    That way you could have: 1 – Fast Red ramp 2 – Fast Blue ramp 3 – Slow Green ramp

    And a chain “Blink 3 times then go green”: 1,2,1,2,1,2,3,0

    With your current way you’d have to waste 7 ramps to achieve that.

    • You’re right of course, that’s a fine way to do it. I’m only planning to use this for one or two chains of red -> warm-white -> cold-white transitions, so for me the limitation was not important.

      I will probably change one more thing, though, and switch from a red-green-blue model to hue-saturation-brightness, because that probably creates better transition paths from color A to B, again for the specific purpose of mimicking sunrise & sunset.

Comments are closed.