YACS  -- Yet Another Candle Sketch

Oh no! Not again! Yes, more silliness from that weirdo in Texas.

This time it’s candle sketches – something I like to amuse myself with
from time to time. Below is my latest tinkerings combined with an idea
or two I got from Jon McPhalen’s article in October’s Nuts & Volts
magazine. Just hook up an LED to ground through an appropriately
valued resistor on pin 10 to your Arduino, download the sketch, and
you’re ready to melt some wax. One of the best ways to enjoy the
‘candle’ is to diffuse the LED with a “faux” flame tip off of a cheap,
electric tea candle.

Compared to some of the better commercial candles I don’t think it
flickers as quickly as some but this candle sketch doesn’t get on my
nerves as badly. (I can be a cranky OF :slight_smile: So give it try and let me know
what you think.

If you like this code, keep in mind that it compiles down to a mere
1414-bytes for a 168/328. For an ATTiny45/85 it compiles to 972-bytes
under v021 of the Arduino IDE on Linux. I also knocked out an
assembler version for the ATTiny13 that uses a whopping 140-bytes
and it’s been working just peachy for the past two weeks.

One more thing before the code… The algorithm is simple enough that
it only takes, at most, a small number of clocks during updates. The
PWM output is updated every 12-milliseconds. I’ve extended my code
in two ways. One is by using all six PWM outputs on a 328 for multiple
candles. Another is to use a TLC5940, with 12-bit PWM, for an up to
16-candle candelabra. So far I’ve only built up 8 wicks with the 5940
and it does put off a nice glow with yellow/amber colored LEDS.

OK, here’s the code. Have fun!

-Rusty-

//
// Candle - Simulate a candle flicker with one LED.
// Rusty Haddock, 10/31/2010  -- with an idea or two from Jon McPhalen's
//          article in Nuts&Volts, 10/2010 issue.
//
// The main idea behind this candle program is to set a target brightness
// and step to it (by brightnessStep).  Once the target is reached a new
// target and brightnessStep is generated and the process starts again.
// As each target is reached the direction to the new target is opposite
// of the last.  This is done by selecting a new target across the midpoint
// of brightness (e.g. if the current target has a value of 128-255 then
// the new target will be picked in the range 0-127, and vice versa.
// 
// I've played a bit with the brightnessStep setup, random(4,12).
// I'm liking those numbers. 

// #define LEDPIN 0            // For Tiny25/45/85 (physical pin 5, PortB0)
#define LEDPIN 10            // For Mega168/328

byte currentLevel,            // Current brightness of candle
     targetLevel;            // Brightness level we're going to.
char brightnessStep;            // How much to change brightness each step

unsigned int prnSeed = 0xa5a5u; // Do we really need to generate a "random" 
                                // number for the seed?  Save the memory...
                                // Any non-zero number will work just fine.


// Generate a 16-bit pseudo-random from lo to hi-1, inclusive.
//     Using this instead of random() saves about 600-bytes.
unsigned int random16(unsigned int lo, unsigned int hi)
{
    byte cnt, mask;
    unsigned int ans, bits;

    bits = prnSeed & 0xd008u;         // Feedback pattern for 16-bits
    mask = highByte(bits) | lowByte(bits);    // quickens the bit count
    
    // Count the bits we masked off.
    for (cnt=0; mask != 0; mask >>= 1) {
        if (mask & 0x01)
            cnt++;
    }

    prnSeed <<= 1;
    if (cnt & 1)        // If there was an odd # bits we feedback a 1-bit
      prnSeed++;

    ans = (prnSeed & (hi-lo-1)) + lo;         // (hi-low) needs to be a power of two
//  ans = (prnSeed % (hi-lo)) + lo;           // otherwise use this line.
    return ans;
}


void setup()
{
    currentLevel = 255;         // Initially the candle will "flare up" and
    targetLevel = 1;            // then ramp down.  Kinda let user know we're
    brightnessStep = -1;      // peachy keen.
}


void loop()
{
    boolean goingUp;             // Ramping up or down in brightness?

    goingUp = (brightnessStep > 0);

    // Have we reached our target?
    if ((goingUp && (currentLevel >= targetLevel))
        || (!goingUp && (currentLevel <= targetLevel))) 
    {
        // New target value please!
      targetLevel = random16(0,128);
        brightnessStep = random16(4, 12);

        if (goingUp)            // if were goingUp -- now go down.
            brightnessStep = -brightnessStep;
        else
            targetLevel += 128;
    }

    // The PWM is only 8-bits so... constrain ourselves. :-)
    currentLevel = constrain(currentLevel+brightnessStep, 0, 255);

    analogWrite(LEDPIN, currentLevel);

    delay(12);                  // I have NO IDEA where I got this value
                            // but it seems to work for me.
}

Looks good, I like the random brightness as WELL as the random brightness step change. Have you tested it and/or have a video of it working? I'm curious about it. I could try it on pin 13 on mine but I don't think it would do the program justice with that tiny baby LED.

Have you tested it and/or have a video of it working?

No, I do not have a video. No, I haven't tested it -- I post random code because I like to mess with people's minds. Please re-read my post.

I'm curious about it. I could try it on pin 13 on mine but I don't think it would do the program justice with that tiny baby LED.

Guess what? It won't work with the tiny baby LED on pin 13 because pin 13 doesn't have PWM output. But, like I said, you could attach an LED in series with a resistor from pin 10 to ground and try it out.

Two thoughts:

I wonder how cheap you could put accelerometer (or pressure sensor) on this, so it would flutter and flare when moved or blown on.

I found when converting old lanterns to stage use that multiple bulbs can sometimes be more pleasing. What about three to five ultra-mini LEDs all packed together, to give some "movement" to the flame?

I like the suggestion of re-purposing tea bulbs. Way back when, I found hand-pressed hot glue (from a hot glue gun) could make an optically pleasing shape.

I wonder how cheap you could put accelerometer (or pressure sensor) on this, so it would flutter and flare when moved or blown on.

It would probably be easier with a simple thermistor to detect a good breeze.
I’ve seen it done this way. Personally, I’m more interested in just the flicker,
not necessarily building a complete candle emulator.

I found when converting old lanterns to stage use that multiple bulbs can sometimes be more pleasing. What about three to five ultra-mini LEDs all packed together, to give some “movement” to the flame?

I wouldn’t doubt that multiple LEDs would be better, especially for larger light sources such
as a lantern. The problem now becomes more expense with more components and connections.
The simplicity of a single LED suits me for the most part since one processor pin can drive it
directly. On the other hand, even the Tiny13a has two PWM pins and running two LEDs of that
processor may be worth some experimentation.

-Rusty-