Need programming help

Hello experienced coders, inexperienced students here. We are trying to do a simple project involving neopixels, we haven’t been able to find anything else online that quite does what we are trying to do with our project. We need some help to configure a pushbutton with a neopixel strip so that it activates our LED’s when we push the button and then off after another push. Anybody that could tell us how to do this or anyone who would like to look at our code here and add it to their own code to achieve our goal here would be greatly appreciated.

#include <Adafruit_NeoPixel.h>
#define PIN 6
#define NUM_LEDS 34
// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

// *** REPLACE FROM HERE ***
void loop() {
  Fire(55,120,15);
}

void Fire(int Cooling, int Sparking, int SpeedDelay) {
  static byte heat[NUM_LEDS];
  int cooldown;
 
  // Step 1.  Cool down every cell a little
  for( int i = 0; i < NUM_LEDS; i++) {
    cooldown = random(0, ((Cooling * 10) / NUM_LEDS) + 2);
   
    if(cooldown>heat[i]) {
      heat[i]=0;
    } else {
      heat[i]=heat[i]-cooldown;
    }
  }
 
  // Step 2.  Heat from each cell drifts 'up' and diffuses a little
  for( int k= NUM_LEDS - 1; k >= 2; k--) {
    heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
  }
   
  // Step 3.  Randomly ignite new 'sparks' near the bottom
  if( random(255) < Sparking ) {
    int y = random(7);
    heat[y] = heat[y] + random(160,255);
    //heat[y] = random(160,255);
  }

  // Step 4.  Convert heat to LED colors
  for( int j = 0; j < NUM_LEDS; j++) {
    setPixelHeatColor(j, heat[j] );
  }

  showStrip();
  delay(SpeedDelay);
}

void setPixelHeatColor (int Pixel, byte temperature) {
  // Scale 'heat' down from 0-255 to 0-191
  byte t192 = round((temperature/255.0)*191);
 
  // calculate ramp up from
  byte heatramp = t192 & 0x3F; // 0..63
  heatramp <<= 2; // scale up to 0..252
 
  // figure out which third of the spectrum we're in:
  if( t192 > 0x80) {                     // hottest
    setPixel(Pixel, 255, 255, heatramp);
  } else if( t192 > 0x40 ) {             // middle
    setPixel(Pixel, 255, heatramp, 0);
  } else {                               // coolest
    setPixel(Pixel, heatramp, 0, 0);
  }
}
// *** REPLACE TO HERE ***

void showStrip() {
 #ifdef ADAFRUIT_NEOPIXEL_H
   // NeoPixel
   strip.show();
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   FastLED.show();
 #endif
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
 #ifdef ADAFRUIT_NEOPIXEL_H
   // NeoPixel
   strip.setPixelColor(Pixel, strip.Color(red, green, blue));
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   leds[Pixel].r = red;
   leds[Pixel].g = green;
   leds[Pixel].b = blue;
 #endif
}

void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue);
  }
  showStrip();
}

Anybody that could tell us how to do this

You should look at two things.
The first is the state change example in the IDE. This will allow you to in effect count the number of changes of state of the button rather than just detect if the button is being held.
Then you have to rewrite the Fire function as a state machine. I have posted this code many times here so do some more searching.

The state machine and the state change button code are run one after the other in a constant loop.

Use the forum Google search function in the upper right of this page to search for the key words of your project, like "toggle" or "flip flop". You will probably find many similar previous project discussions and code to get you started.

Try this. Compiles, not tested.

Didn’t have time to comment extensively. Ask if you have trouble or questions.

#include <Adafruit_NeoPixel.h>

#define PIN         6
#define NUM_LEDS    34

//
#define BTN_READ_INTERVAL   50ul    //mS    button read interval
// 
const byte pinBtn = 2;
byte btnLast;
bool bPutOnAShow;

// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

void setup() 
{
    pinMode( pinBtn, INPUT_PULLUP );
    btnLast = digitalRead( pinBtn );
    bPutOnAShow = false;
    
    strip.begin();
    strip.show(); // Initialize all pixels to 'off'
        
}//setup

// *** REPLACE FROM HERE ***
void loop() 
{
    ReadButton();
    
    if( bPutOnAShow )   
        Fire( 55, 120, 15);
    
}//loop

void ReadButton( void )
{
    byte
        btnNow;
    static unsigned long
        timeBtn = 0;
    unsigned long
        timeNow;

    timeNow = millis();
    if( timeNow - timeBtn < BTN_READ_INTERVAL )
        return;

    timeBtn = timeNow;
        
    btnNow = digitalRead( pinBtn );
    if( btnNow != btnLast )
    {
        btnLast = btnNow;
        if( btnNow == LOW )
        {
            //toggle show boolean
            bPutOnAShow ^= true;

            //if low, clear the strip and show it
            if( !bPutOnAShow )
            {
                strip.clear();
                strip.show();
                
            }//if
            
        }//if
        
    }//if
       
}//ReadButton

void Fire( int Cooling, int Sparking, int SpeedDelay ) 
{
    static byte heat[NUM_LEDS];
    int cooldown;
 
    // Step 1.  Cool down every cell a little
    for( int i = 0; i < NUM_LEDS; i++) 
    {
        cooldown = random( 0, ((Cooling * 10) / NUM_LEDS) + 2 );
   
        if(cooldown>heat[i]) 
        {
            heat[i]=0;
            
        }//if
        else 
        {
            heat[i]=heat[i]-cooldown;
            
        }//else
        
    }//for
 
    // Step 2.  Heat from each cell drifts 'up' and diffuses a little
    for( int k= NUM_LEDS - 1; k >= 2; k--) 
    {
        heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
        
    }//for
   
    // Step 3.  Randomly ignite new 'sparks' near the bottom
    if( random(255) < Sparking ) 
    {
        int y = random(7);
        heat[y] = heat[y] + random(160,255);
        //heat[y] = random(160,255);
        
    }//if

    // Step 4.  Convert heat to LED colors
    for( int j = 0; j < NUM_LEDS; j++) 
    {
        setPixelHeatColor(j, heat[j] );
    }

    showStrip();
    delay(SpeedDelay);
}

void setPixelHeatColor (int Pixel, byte temperature) 
{
    // Scale 'heat' down from 0-255 to 0-191
    byte t192 = round((temperature/255.0)*191);
 
    // calculate ramp up from
    byte heatramp = t192 & 0x3F; // 0..63
    heatramp <<= 2; // scale up to 0..252
 
    // figure out which third of the spectrum we're in:
    if( t192 > 0x80) 
    {                     // hottest
        setPixel(Pixel, 255, 255, heatramp);
        
    }//if 
    else if( t192 > 0x40 ) 
    {             // middle
        setPixel(Pixel, 255, heatramp, 0);
        
    }//else if
    else 
    {                               // coolest
        setPixel(Pixel, heatramp, 0, 0);
        
    }//else
    
}//setPixelHeatColor

// *** REPLACE TO HERE ***

void showStrip() 
{
#ifdef ADAFRUIT_NEOPIXEL_H
    // NeoPixel
    strip.show();
#endif

#ifndef ADAFRUIT_NEOPIXEL_H
    // FastLED
    FastLED.show();
#endif

}//showStrip

void setPixel(int Pixel, byte red, byte green, byte blue) 
{
#ifdef ADAFRUIT_NEOPIXEL_H
    // NeoPixel
    strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif

#ifndef ADAFRUIT_NEOPIXEL_H
    // FastLED
    leds[Pixel].r = red;
    leds[Pixel].g = green;
    leds[Pixel].b = blue;
#endif

}//setPixel

void setAll(byte red, byte green, byte blue) 
{
    for(int i = 0; i < NUM_LEDS; i++ ) 
    {
        setPixel(i, red, green, blue);
        
    }//for
    
    showStrip();
    
}//setAll

The OP said

that it activates our LED's when we push the button and then off after another push.

That code will not turn off the show on a second push. It will only start the show on the push of a button.

Grumpy_Mike:
The OP saidThat code will not turn off the show on a second push. It will only start the show on the push of a button.

I'm not that familiar with neopixels. I assumed that using .clear() and .show() if bPutOnAShow is false after toggling its state in the button read function:

            //toggle show boolean
            bPutOnAShow ^= true;

            if( !bPutOnAShow )
            {
                strip.clear();
                strip.show();
               
            }//if

would turn off the individual LEDs internally and then externally. Since the Fire() function is called from within loop only if bPutOnAShow is true:

    if( bPutOnAShow )   
        Fire( 55, 120, 15);

the act of clearing and showing immediately should turn them off and leave them off until bPutOnAShow is toggled true again with another button press.

But as I mentioned, I'm not that familiar with neopixels so maybe .clear() doesn't do what I think it does.

Or am I missing something else?

Blackfin:
I'm not that familiar with neopixels. I assumed that using .clear() and .show() if bPutOnAShow is false after toggling its state in the button read function:

            //toggle show boolean

bPutOnAShow ^= true;

if( !bPutOnAShow )
            {
                strip.clear();
                strip.show();
             
            }//if




would turn off the individual LEDs internally and then externally. Since the Fire() function is called from within loop only if bPutOnAShow is true:



if( bPutOnAShow ) 
        Fire( 55, 120, 15);




the act of clearing and showing immediately should turn them off and leave them off until bPutOnAShow is toggled true again with another button press.

But as I mentioned, I'm not that familiar with neopixels so maybe .clear() doesn't do what I think it does.

Or am I missing something else?

Nope! this code works just fine! Thanks guys so much for giving input we appreciate it so much.

Or am I missing something else?

Yes, the button is only looked at when the fire function has finished so while it will trigger a show a second press won’t stop it.

this code works just fine

But it is not what you asked for.

Grumpy_Mike:
Yes, the button is only looked at when the fire function has finished so while it will trigger a show a second press won’t stop it.
But it is not what you asked for.

Actually, it does. Fire() requires ~21mS to execute according to my testing. The program is responsive to the press of a switch on pin 2. It may have a bit of latency but it does work as is.

OP has verified. It could be made better by removing the delay(SpeedDelay) call at the end of Fire() and replacing it with millis(). If the OP wants to polish it he can do that himself.