Trouble Integrating momentary switch into program

Hello, I'm having trouble understanding what I need to change in my program regarding a momentary switch. What I'm looking to do is have a momentary switch execute two modes for an led strip. One mode is a simple flash, the other is a fade followed by flashing. When the switch is not pressed (LOW) I want it to flash, when the switch is pressed i want it to start the second mode and stay in that mode until powered off. So do i need to write some sort of latch when the switch is high? In my program now i have to hold the switch closed for a few seconds before it executes the second mode, but as soon as i release the switch it goes back to the first mode. Here is a sample of my program:

#include "Adafruit_NeoPixel.h"

#define PIN 6
#define NUMPIXELS 4

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS,PIN,NEO_GRB +
NEO_KHZ800);

enum STATE {
STATE_FADE_OUT,
STATE_LIGHTNING
};

STATE currentState;
unsigned long time;
int brightness;
int switchState = 0;
int count = 0;
int lastState = 0;
int pushCount =0;

void setup() {
pinMode(2, INPUT);
currentState = STATE_FADE_OUT;
brightness = 255;
pixels.begin();

}

void loop() {
time = millis();
switchState = digitalRead(2);
if (lastState == switchState) {

for(int i=0;i<NUMPIXELS;i++){ //FIRST MODE, REPEATS UNTIL POWERED OFF IF SWITCH IS LOW
pixels.setPixelColor(0,255,255,225);
pixels.setPixelColor(1,200,200,200);
pixels.show();
}
delay(110);
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(0,0,0));
pixels.show();
}
delay(100);
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(1,180,180,180);
pixels.setPixelColor(2,255,255,225);
pixels.setPixelColor(3,200,200,200);
pixels.show();
}
delay(50);
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(0,0,0));
pixels.show();
}
delay(3000);
}

// 2ND MODE, REPEATS UNTIL POWER OFF IF SWITCH IS PRESSED

if(lastState != switchState){ / 2ND MODE, REPEATS UNTIL POWER OFF IF SWITCH IS PRESSED s switch(currentState){
case STATE_FADE_OUT:

if(time % 1000 == 0){
brightness--;
pixels.setPixelColor(0,(brightness250/255),(brightness38/255),(brightness0/255));
pixels.setPixelColor(1,(brightness
250/255),(brightness38/255),(brightness0/255));
pixels.show();

if(brightness==5)
{
currentState = STATE_LIGHTNING;
}
}
break;
case STATE_LIGHTNING:
while(true)
{
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(0,255,255,225);
pixels.setPixelColor(1,200,200,200);
//pixels.setPixelColor(2,140,140,225);
pixels.show();
}
delay(110);
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(0,0,0));
pixels.show();
}
delay(100);
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(2,255,255,225);
pixels.setPixelColor(3,200,200,200);
pixels.show();
}
delay(50);
for(int i=0;i<NUMPIXELS;i++){
pixels.setPixelColor(i, pixels.Color(0,0,0));
pixels.show();
}

delay(9000);
}
break;
}
}
}

Don't forget to highlight your code, then use the Code tag button </> to present your code in a box that's easier to read.

If you're not using an external pullup or pulldown resistor with your pushbutton, you could use INPUT_PULLUP with the button connected from input to GND.

Investigate using the millis() for time intervals rather than delay(). This will make monitoring the pushbutton status (and everything else) much more responsive.

You want to Change from Flash mode to fade mode once and only once.

Set mode = Flash in the Setup.

In the Loop
If in Flash mode, do the flashing
If in Fade mode, do the Fading

In the Flash mode, don't use delay (this is why it takes pressing the button for several seconds before it is recognized). Instead, write your own function, something like...

void wait(int delay_length)
{ int stop_millis = millis() + delay_length;

while (millis() < stop_millis)
{ if(digitalRead(2))
{ mode = fade; // Switch to fade mode
break; // And break out of the waiting Loop
}
}

Don't read the digital pin from within the main Loop, just read it from your waiting function.

}

@JaBa, you two, code tags :wink:

austin0ryan:
When the switch is not pressed (LOW)

That's an assumption... Did you indeed add a pull up resistor? Normally it's easier to connect the button between GND and a pin, enable the internal pull down and see a LOW when it IS pressed. Saves a resistor / makes it easier.

And JaBa is right about the delays(), those are a problem if you want to be able to interact with a program. See Blink without delay to get ride of the delay() (And after that, never use it again :smiley: )

But the solution of JaBa isn't that great to only check the button when in wait... Best is to let the loop() run freely! Then you also have time in the loop() to check buttons.

And another tip, make things easy and use a library for the button. This can do all the "heavy lifting" like detecting a button BECAME pressed (which is different then a button IS pressed) and debouncing in like 2 lines of code. I can recommend Bounce2.

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks.. Tom... :slight_smile:

Thanks for all of the replies, and sorry about not posting my code correctly. Using the Millis() function makes sense instead of delay. I've read through some tutorials but cannot figure out how to transfer my delay times into a Millis(). For example, in my above program, the flash mode (all the delay on and off times) is supposed to somewhat look like a lightning storm. So there are different delay times, 100mS, 50mS, 190mS, etc. How can I ditch the delay while using different delay times throughout the flash mode. I can blink an led without using delay, but how do you make it blink at different intervals as the "flash mode" progresses? Example, led on 50mS..off 100Ms.. on 190mS...off 110mS..etc. An example code would be very helpful if possible. Thanks again for any help, I'm a newbie obviously.

but cannot figure out how to transfer my delay times into a Millis().

That is the wrong approach. Delete ALL the code you have so far.

On every pass through loop(), millis() will tell you what time it is. It may, or may not, be time to do something.

It will be if now minus then is greater than some interval. If that is true, make whatever needs to happen happen, and set then to now. Change the interval, if appropriate.

The blink without delay example is a good starting point. If you get stuck, post your code, and tell us what it actually does, and how that differs from what you expect.

Here is a basic example where the interval varies each time you've completed a waiting period and once the full array of period is over, then there is no more animation going on.

to make it interesting I kinda hacked into the the timing some basic morse code duration. have a look, it's pretty crude and I'm no Morse code expert.

// constants won't change. Used here to set a pin number :
const int ledPin =  13;      // the number of the LED pin

// Variables will change :
int ledState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated


// ARDUINO in morse code = .- .-. -.. ..- .. -. ---
// The duration of a dash is three times the duration of a dot.
// Each dot or dash is followed by a short silence, equal to the dot duration.
// The letters of a word are separated by a space equal to three dots (one dash),
// and the words are separated by a space equal to seven dots.

#define BASICDOT 50
#define BASICDASH (3*BASICDOT)
#define SHORTSILENCE BASICDOT
#define LETTERSEPARATOR (BASICDASH+BASICDOT)

#define DOT BASICDOT,SHORTSILENCE,
#define DASH BASICDASH,SHORTSILENCE,
#define DOTLETTEREND BASICDOT,LETTERSEPARATOR
#define DASHLETTEREND BASICDASH,LETTERSEPARATOR

// A = .-  = DOT DASHLETTEREND,
// R = .-. = DOT DASH DOTLETTEREND,
// D = -.. = DASH DOT DOTLETTEREND,
// U = ..- = DOT DOT DASHLETTEREND,
// I = ..  = DOT DOTLETTEREND,
// N = -.  = DASH DOTLETTEREND,
// O = --- = DASH DASH DASHLETTEREND

const unsigned int intervalArray[] = {0, DOT DASHLETTEREND, DOT DASH DOTLETTEREND, DASH DOT DOTLETTEREND, DOT DOT DASHLETTEREND, DOT DOTLETTEREND, DASH DOTLETTEREND, DASH DASH DASHLETTEREND,0}; // list of interval at which to blink (milliseconds)
const unsigned int nbInterval = sizeof( intervalArray) / sizeof(intervalArray[0]);
unsigned int interval;  // interval at which to blink (milliseconds)
byte intervalIndex = 0; // interval at which to blink (milliseconds)
boolean keepgoing; // we want to play the sequence only once

void setup() {
  Serial.begin(115200);
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
  intervalIndex = 0;
  previousMillis = 0;
  interval = intervalArray[intervalIndex];
  ledState = LOW;
  keepgoing = true;
  delay(3000); // wait for 3 second to start
}

void loop() {

  if (keepgoing) { // the sequence is not finished, check if it is time to take action
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      // compute the next interval
      intervalIndex = intervalIndex + 1; // could be done with ++ and modulo but for code readability
      if (intervalIndex >= nbInterval) keepgoing = false; // sequence played
      else interval = intervalArray[intervalIndex];
      // if the LED is off turn it on and vice-versa:
      if (ledState == LOW) {
        ledState = HIGH;
        if (keepgoing) {
          Serial.print("will be HIGH for: ");
          Serial.print(interval);
          Serial.println("ms");
        } else {
          Serial.println("HIGH - End of Sequence");
        }
      } else {
        ledState = LOW;
        if (keepgoing) {
          Serial.print("will be  LOW for: ");
          Serial.print(interval);
          Serial.println("ms");
        } else {
          Serial.println("LOW - End of Sequence");
        }
      }
      digitalWrite(ledPin, ledState);
    }
  }

  // here you can do other things

}

should be pretty self explanatory, I took the code from "blink without using delay" and just changed a few things to have an array and printing stuff out so that you can see what's going on. (set your console at 115200)

hope this helps