The Code

Written by Rob on Wednesday 10th January 2024

This is the latest version of the coded used on the lamps…

                            #include <Arduino.h>
#include <FastLED.h>
#include <math.h>

#define NUM_LEDS  51

#define COOLING  50
#define SPARKING 60

#define FPS 30   // 60 is ideal

#define ARM_1_PIN 2
#define ARM_2_PIN 3
#define ARM_3_PIN 4
#define ARM_4_PIN 5

#define VOLT_LIMIT 5
#define MILLIAMP_LIMIT 3000

#define AMP_LIMIT_LED_PIN 7

#define MIN_BRIGHTNESS 10
#define MAX_BRIGHTNESS 255

#define BRIGHTNESS_PIN A4

#define PALETTE_PIN A2

#define NUM_AVERAGE_SAMPLES 30

byte heat[ 4 ][ NUM_LEDS ] = { 0 };

CRGB leds[ 4 ][ NUM_LEDS ] = { 0 };

void setup()
{
    delay( 2000 ); // power-up safety delay

    FastLED.addLeds<WS2812B, ARM_1_PIN, GRB>( leds[ 0 ], NUM_LEDS );
    FastLED.addLeds<WS2812B, ARM_2_PIN, GRB>( leds[ 1 ], NUM_LEDS );
    FastLED.addLeds<WS2812B, ARM_3_PIN, GRB>( leds[ 2 ], NUM_LEDS );
    FastLED.addLeds<WS2812B, ARM_4_PIN, GRB>( leds[ 3 ], NUM_LEDS );

    pinMode( AMP_LIMIT_LED_PIN, OUTPUT );   // just in case it's not set

    set_max_power_indicator_LED( AMP_LIMIT_LED_PIN );
    
    FastLED.setMaxPowerInVoltsAndMilliamps( VOLT_LIMIT, MILLIAMP_LIMIT );
        
    FastLED.setBrightness( MAX_BRIGHTNESS );

    Serial.begin( 115200 );

    if ( 0 )
    {
        all_white( leds[ 0 ] );
        all_white( leds[ 1 ] );
        all_white( leds[ 2 ] );
        all_white( leds[ 3 ] );

        FastLED.show();
    }
}

CRGBPalette16 palettes[] = {
    HeatColors_p,
    RainbowColors_p,
    CloudColors_p,
    ForestColors_p,
    OceanColors_p
};

void loop()
{
    EVERY_N_MILLISECONDS( 1000 / FPS ){
    
        // update the brightness

        FastLED.setBrightness( _get_normalised_brightness_value() );

        for ( int i = 0; i < 4; i++ )
        {
            fire( leds[ i ], heat[ i ] );

            // knight_rider( leds[ i ] );

             // all_white( leds[ 0 ] );
             // all_white( leds[ 1 ] );/home/rob/Arduino/blink/blink.ino
             // all_white( leds[ 2 ] );
             // all_white( leds[ 3 ] );
        }
  
        FastLED.show();

    }

    // delay(100);

}

int _get_normalised_brightness_value()
{
    int brightness_pin_value = analogRead( BRIGHTNESS_PIN );

    int brightness_value = map(
        brightness_pin_value,
        0, 1023,
        MIN_BRIGHTNESS, MAX_BRIGHTNESS
    );

    return brightness_value;
}


void fire( CRGB leds[], byte heat[] )
{
    // cool down every cell a little
    
    for ( int i = 0; i < NUM_LEDS; i++ )
    {
        heat[ i ] = qsub8( heat[ i ], random8( 0, ( ( COOLING * 10 ) / NUM_LEDS ) + 2 ) );
    }
  
    // heat from each cell drifts 'up' and diffuses a little

    for ( int i = NUM_LEDS - 1; i >= 2; i-- )
    {
        heat[ i ] = ( heat[ i - 1 ] + heat[ i - 2 ] + heat[ i - 2 ] ) / 3;
    }
    
    // randomly ignite new 'sparks' of heat near the bottom

    if ( random8() < SPARKING )
    {
        int y = random8( 7 );

        heat[ y ] = qadd8( heat[ y ], random8( 160, 255 ) );
    }

    // map from heat cells to LED colors

    CRGBPalette16 palette = HeatColors_p;   // default

    int num_palettes = sizeof( palettes ) / sizeof( CRGBPalette16 );

    // map the analogue input (0-1023) to an index in our array of palettes

    int analogue_value = analogRead( PALETTE_PIN );

    int averaged_analogue_value = _averageAnalogueRead( PALETTE_PIN );

    int mapped_value = map(
        averaged_analogue_value,
        0, 1023,
        0, num_palettes - 1
    );

    char serial_out[255];

    sprintf( serial_out, "Total palettes %d, analogue pin %d, averaged analogue value %d, mapped %d", num_palettes, analogue_value, averaged_analogue_value, mapped_value );



    // Serial.println( serial_out );

    palette = palettes[ mapped_value ];

    for ( int i = 0; i < NUM_LEDS; i++ )
    {
        // Scale the heat value from 0-255 down to 0-240
        // for best results with color palettes.

        byte colorindex = scale8( heat[ i ], 240 );

        CRGB color = ColorFromPalette( palette, colorindex );

        leds[ i ] = color;
    }
}

int _averageAnalogueRead( int pin )
{
    static int values[ NUM_AVERAGE_SAMPLES ] = { 0 };

    static int last_element = -1;

    last_element ++;

    if ( last_element == NUM_AVERAGE_SAMPLES )
    {
        last_element = 0;
    }

    int value = analogRead( pin );

    values[ last_element ] = value;

    int average = 0;

    for ( int i = 0; i < NUM_AVERAGE_SAMPLES; i++ )
    {
        average += values[ i ];
    }

    return average / NUM_AVERAGE_SAMPLES;
}

void all_white( CRGB leds[] )
{
    fill_solid( leds, NUM_LEDS, CRGB::White );
}

void knight_rider( CRGB leds[] )
{
    uint8_t sinBeat = beatsin8( 120, 0, NUM_LEDS - 1, 0, 0 );

    leds[ sinBeat ] = CRGB::Red;

    fadeToBlackBy(leds, NUM_LEDS, 10);
}
                            
                        

Similar Articles

Start Here
Start Here

Full disclosure, I didn't invent this, but I will show you step-by-step how to build it.

Purchasing The Hardware
Purchasing The Hardware

Here's a list of all the physical hardware needed to build the Fire Lamp, and where to buy, in the UK.