Instantly stopping for loop on button press

Hello all, i have my code below. in this case my code switches state only after the for loop in each case is finished, how can i go about instantly stopping for loop and moving on to the next given state?

thanks!

#include <FastLED.h>

#define NUM_LEDS 30
#define LED_PIN 3

CRGB leds[NUM_LEDS];

const int buttonPin = 2;

int buttonState = 0;
int prevbuttonState = 0;
int State = 1;

void setup() {
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness (96);
Serial.begin(9600);
}

void loop() {

checkbuttonState();

switch (State)
{
case 1:
 RedcrossingLED();
 break;
case 2:
  brainMelter();
  break;
case 3:
  //placeholder
  break;
case 4:
  //placeholder
  break;
case 5:
  //placeholder
  break;
}
}

////////////////////////////////////////////////////////////////////////

void checkbuttonState()
{
  buttonState = digitalRead(buttonPin);
if (buttonState != prevbuttonState) {
    if (buttonState == LOW) {
      State++;
      Serial.println(State);
 }
 if (State > 5){
  State = 1;
 }
 }
 prevbuttonState = buttonState;
}
////////////////////////////////////////////////////////////////////////

void RedcrossingLED()
{
  
  for (int i = 0; i < NUM_LEDS; i++) {
    checkbuttonState();
    leds[i] = CRGB::Red;
    FastLED.show();
    delay(100);
    leds[i] = CRGB::Black;
  }
  for (int i = NUM_LEDS - 1; i >=- 0; i--){
    checkbuttonState();
    leds[i] = CRGB::Red;
    FastLED.show();
    delay(100);
    leds[i] = CRGB::Black;
    
  }
}
////////////////////////////////////////////////////////////////
void brainMelter()
{
  static uint8_t hue = 0;
  Serial.print("x");
  // First slide the led in one direction
  for(int i = 0; i < NUM_LEDS; i++) {
    checkbuttonState();
    // Set the i'th led to red 
    leds[i] = CHSV(hue++, 255, 255);
    // Show the leds
    FastLED.show(); 
    // now that we've shown the leds, reset the i'th led to black
    // leds[i] = CRGB::Black;
    fadeall();
    // Wait a little bit before we loop around and do it again
    delay(10);
  }
  Serial.print("x");

  // Now go in the other direction.  
  for(int i = (NUM_LEDS)-1; i >= 0; i--) {
    checkbuttonState();
    // Set the i'th led to red 
    leds[i] = CHSV(hue++, 255, 255);
    // Show the leds
    FastLED.show();
    // now that we've shown the leds, reset the i'th led to black
    // leds[i] = CRGB::Black;
    fadeall();
    // Wait a little bit before we loop around and do it again
    delay(10);
  }
}
////////////////////////////////////////////////////////////////

void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }

////////////////////////////////////////////////////////////////

Welcome to the forum

The obvious way would be to read the button state inside the for loop and if you find that the button is pressed use break; to exit from the for loop

The delay(100) will be the main cause for latency.

A lag of 1/10th of a second is considered in many studies (since 1993) as the upper limit for a human interface before it starts feeling laggy (nowadays gamers wants low single digit ms lag ).

So I would also replace the call to delay by a custom millis() based function where you also check the button.


The better design would be to use state machine based non blocking functions for the led animations that would be called repetitively from the loop which would also check the button. That’s more work

1 Like

consider which demonstrates use of millis()

// demonstrate reaction time test

byte ButPin     = A1;
byte butState;

byte LedPins [] = { 10, 11, 12, 13 };
#define N_LED  sizeof(LedPins)
unsigned ledIdx;

enum { Off = HIGH, On = LOW };

#define N_STATE 2
unsigned state;

unsigned long msecPause = 100;
unsigned long msecLst;
unsigned long msec;

// -----------------------------------------------------------------------------
void scan ()
{
    // wait for time to expire
    if (msec - msecLst > msecPause)  {
        msecLst = msec;

        // advance LED
        digitalWrite (LedPins [ledIdx], Off);
        if (N_LED <= ++ledIdx)
            ledIdx = 0; 
        digitalWrite (LedPins [ledIdx], On);
    }
}

// -----------------------------------------------------------------------------
void chkButton ()
{
    byte but = digitalRead (ButPin);
    if (butState != but) {
        butState = but;

        if (but == LOW) {
            state++;
            Serial.println (state);
        }
        if (state >= N_STATE)
            state = 0;
    }
}

// -----------------------------------------------------------------------------
void loop ()
{
    msec = millis ();

    chkButton ();

    switch (state) {
    case 0:
        scan ();
        break;

    case 1:
        break;
    }
}

// -----------------------------------------------------------------------------
void setup() {
    Serial.begin(9600);

    pinMode (ButPin, INPUT_PULLUP);
    butState = digitalRead (ButPin);

    for (unsigned n = 0; n < N_LED; n++)  {
        digitalWrite (LedPins [n], Off);
        pinMode      (LedPins [n], OUTPUT);
    }
}

Very interesting...

speech coders generate new phonemes every 20 ms. in other words, the vocal chords can generate a new phoneme 50 times/sec. this applies to other muscles as well. athletes have faster reaction times.

not obvious to me how quickly someone can perceive seeing something change. American TVs refresh the screen at 60Hz which is in line with above

Milliseconds count in many application areas.

Younger ppl are more sensitive, percussionists of any age…

So whenever, wherever you can make something instant or nearly so, and doing is easy, you should because there will inevitably be other sources of lag.

Why contribute even 1 ms to that?

a7

what's required?

why not, if accepting a 1ms delay significantly simplifies the code? what if the processing requires > 1msec?

when i worked on processing voice (mu-law) voice sample, everything needed to be done < 125 usec.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.