Not the outcome i was looking for

I work on sections at a time. This part of my program is for two sets of strobe patterns. Each set has 6 functions in it. They are connected to pen 7 and pen 8. I know the patterns work great as they have been tested.

What I was looking for was if you pressed button on pen 10 for 3 seconds it would start a set up where it takes the first pattern in the set and run it 20 seconds then pen 7 to high for 3 seconds and then run the next pattern and continue until the button is pressed. at the time it would stop and write that pattern to epprom. now if you hold th button for 6 seconds it would do all this but witht he second set on pen 8
What I get is when I hold the button for 3 seconds pen 7 LED is on and stays on till i hit the button then its off. If I do it for 6 I get LED on pen 8 on with same results. Its not running the pattersn.

#include <EEPROM.h>

// Pin Definitions
const int stro1led = 7;
const int stro2led = 8;
const int BUTTON_PIN = 10;

// EEPROM Memory Addresses
const int EEPROM_ADDR_SP1 = 0;
const int EEPROM_ADDR_SP2 = 1;

// Timing Constants (in milliseconds)
const unsigned long HOLD_S1_TIME = 3000; // 3 seconds
const unsigned long HOLD_S2_TIME = 6000; // 6 seconds
const unsigned long RUN_DURATION = 20000; // 20 seconds
const unsigned long PAUSE_DURATION = 3000; // 3 seconds

// State Machine Definitions
enum SystemState { IDLE, RUNNING_S1, PAUSING_S1, RUNNING_S2, PAUSING_S2 };
SystemState currentState = IDLE;

// Execution Tracking
int currentFunctionIndex = 0;
unsigned long stateStartTime = 0;
unsigned long buttonPressStartTime = 0;
bool buttonWasPressed = false;

// strobe 1 patterns
//--------------------------------------------------------------------------------------------------------------
void s1pattern1() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p1intervals[4] = {15, 100, 15, 1370}; 
  const int s1p1ledStateValues[4] = {HIGH, LOW, HIGH, LOW}; 

      if (s1currentMillis - s1previousMillis >= s1p1intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 3)
      s1currentState = (s1currentState + 1) % 4;
      // Apply the new LED state
      digitalWrite(stro1led, s1p1ledStateValues[s1currentState]);
    }
  }
  void s1pattern2() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p2intervals[2] = {15, 1485}; // pattern 2
  const int s1p2ledStateValues[2] = {HIGH, LOW}; // pattern 2

      if (s1currentMillis - s1previousMillis >= s1p2intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s1currentState = (s1currentState + 1) % 2;
      // Apply the new LED state
      digitalWrite(stro1led, s1p2ledStateValues[s1currentState]);
    }
  }
 void s1pattern3() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p3intervals[2] = {15, 985}; // pattern 3
  const int s1p3ledStateValues[2] = {HIGH, LOW}; // pattern 2

      if (s1currentMillis - s1previousMillis >= s1p3intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s1currentState = (s1currentState + 1) % 2;
      // Apply the new LED state
      digitalWrite(stro1led, s1p3ledStateValues[s1currentState]);
    }
 }
    void s1pattern4() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p4intervals[2] = {15, 735}; // pattern 2
  const int s1p4ledStateValues[2] = {HIGH, LOW}; // pattern 2

      if (s1currentMillis - s1previousMillis >= s1p4intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s1currentState = (s1currentState + 1) % 2;
      // Apply the new LED state
      digitalWrite(stro1led, s1p4ledStateValues[s1currentState]);
    }
    }
    void s1pattern5() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p5intervals[2] = {15, 585}; // pattern 2
  const int s1p5ledStateValues[2] = {HIGH, LOW}; // pattern 2

      if (s1currentMillis - s1previousMillis >= s1p5intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s1currentState = (s1currentState + 1) % 2;
      // Apply the new LED state
      digitalWrite(stro1led, s1p5ledStateValues[s1currentState]);
    }
  }
     void s1pattern6() {
	 digitalWrite(stro1led, LOW);
}	 
// strobe 2 patterns
//--------------------------------------------------------------------------------------------------------------
void s2pattern1() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p1intervals[4] = {15, 100, 15, 1270}; 
  const int s2p1ledStateValues[4] = {HIGH, LOW, HIGH, LOW  }; 

      if (s2currentMillis - s2previousMillis >= s2p1intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 3)
      s2currentState = (s2currentState + 1) % 4;
      // Apply the new LED state
      digitalWrite(stro2led, s2p1ledStateValues[s2currentState]);
    }
  }
  void s2pattern2() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p2intervals[5] = {750, 15, 100,  15,  620}; 
  const int s2p2ledStateValues[5] = {LOW, HIGH, LOW, HIGH, LOW};; 

      if (s2currentMillis - s2previousMillis >= s2p2intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 5;
      // Apply the new LED state
      digitalWrite(stro2led, s2p2ledStateValues[s2currentState]);
    }
  }
 void s2pattern3() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p3intervals[3] = {750, 15, 735}; 
  const int s2p3ledStateValues[3] = {LOW, HIGH, LOW}; 

      if (s2currentMillis - s2previousMillis >= s2p3intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 3;
      // Apply the new LED state
      digitalWrite(stro2led, s2p3ledStateValues[s2currentState]);
    }
  }
    void s2pattern4() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p4intervals[3] = {500, 15, 485}; 
  const int s2p4ledStateValues[3] = {LOW, HIGH, LOW}; 

      if (s2currentMillis - s2previousMillis >= s2p4intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 3;
      // Apply the new LED state
      digitalWrite(stro2led, s2p4ledStateValues[s2currentState]);
    }
  }
    void s2pattern5() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p5intervals[3] = {375, 15, 360};
  const int s2p5ledStateValues[3] = {LOW, HIGH, LOW}; 

      if (s2currentMillis - s2previousMillis >= s2p5intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 3;
      // Apply the new LED state
      digitalWrite(stro2led, s2p5ledStateValues[s2currentState]);
    }
  }
      void s2pattern6() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p6intervals[3] = {300, 15, 285}; 
  const int s2p6ledStateValues[3] = {LOW, HIGH, LOW}; 

      if (s2currentMillis - s2previousMillis >= s2p6intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 3;
      // Apply the new LED state
      digitalWrite(stro2led, s2p6ledStateValues[s2currentState]);
    }
  }

// Function Pointers for the 2 Sets
void (*set1_functions[6])() = {s1pattern1, s1pattern2, s1pattern3, s1pattern4, s1pattern5, s1pattern6};
void (*set2_functions[6])() = {s2pattern1, s2pattern2, s2pattern3, s2pattern4, s2pattern5, s2pattern6};

void setup() {
  pinMode(stro1led, OUTPUT);
  pinMode(stro2led, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP); // Assumes button connects pin to GND
  
  digitalWrite(stro1led, LOW);
  digitalWrite(stro2led, LOW);
  Serial.begin(9600);
}

void loop() {
  int buttonState = digitalRead(BUTTON_PIN);
  unsigned long currentMillis = millis();

  // --- BUTTON PRESS LOGIC ---
  if (buttonState == LOW) { // Button is being pressed
    if (!buttonWasPressed) {
      buttonPressStartTime = currentMillis;
      buttonWasPressed = true;
    }
  } else { // Button is released
    if (buttonWasPressed) {
      unsigned long pressDuration = currentMillis - buttonPressStartTime;
      buttonWasPressed = false;

      if (currentState != IDLE) {
        // Immediate Stop if already running a sequence
        stopAndSave();
      } else {
        // Start sequences from IDLE state
        if (pressDuration >= HOLD_S2_TIME) {
          startSequence(RUNNING_S2, EEPROM_ADDR_SP2);
        } else if (pressDuration >= HOLD_S1_TIME) {
          startSequence(RUNNING_S1, EEPROM_ADDR_SP1);
        }
      }
    }
  }

  // --- SEQUENCE EXECUTION STATE MACHINE ---
  if (currentState != IDLE) {
    unsigned long elapsedTime = currentMillis - stateStartTime;

    switch (currentState) {
      case RUNNING_S1:
        digitalWrite(stro1led, HIGH);
        set1_functions[currentFunctionIndex](); // Continuously fire current function
        if (elapsedTime >= RUN_DURATION) {
          goToPauseState(PAUSING_S1);
        }
        break;

      case PAUSING_S1:
        digitalWrite(stro1led, HIGH); // Pin stays HIGH during pause
        if (elapsedTime >= PAUSE_DURATION) {
          goToNextFunction(RUNNING_S1, EEPROM_ADDR_SP1);
        }
        break;

      case RUNNING_S2:
        digitalWrite(stro2led, HIGH);
        set2_functions[currentFunctionIndex]();
        if (elapsedTime >= RUN_DURATION) {
          goToPauseState(PAUSING_S2);
        }
        break;

      case PAUSING_S2:
        digitalWrite(stro2led, HIGH); // Pin stays HIGH during pause
        if (elapsedTime >= PAUSE_DURATION) {
          goToNextFunction(RUNNING_S2, EEPROM_ADDR_SP2);
        }
        break;

      default:
        break;
    }
  }
}

// --- STATE HELPER FUNCTIONS ---
void startSequence(SystemState targetState, int eepromAddr) {
  currentState = targetState;
  
  // Read saved progress from EEPROM
  int savedIndex = EEPROM.read(eepromAddr);
  
  // If memory is empty (255) or out of bounds, start from 0
  if (savedIndex >= 6 || savedIndex < 0) {
    currentFunctionIndex = 0;
  } else {
    currentFunctionIndex = savedIndex;
  }
  
  Serial.print("Starting sequence. Resuming at function index: ");
  Serial.println(currentFunctionIndex);
  
  stateStartTime = millis();
}

void goToPauseState(SystemState pauseState) {
  currentState = pauseState;
  stateStartTime = millis();
}

void goToNextFunction(SystemState runState, int eepromAddr) {
  currentFunctionIndex++;
  
  if (currentFunctionIndex >= 6) { 
    // Finished all 6 functions cleanly: reset index in memory to 0
    EEPROM.update(eepromAddr, 0); 
    Serial.println("Sequence complete. Resetting EEPROM memory to 0.");
    resetSystem();
  } else {
    currentState = runState;
    stateStartTime = millis();
  }
}

void stopAndSave() {
  if (currentState == RUNNING_S1 || currentState == PAUSING_S1) {
    EEPROM.update(EEPROM_ADDR_SP1, currentFunctionIndex);
    Serial.print("Stopped S1. Saved progress: ");
    Serial.println(currentFunctionIndex);
  } else if (currentState == RUNNING_S2 || currentState == PAUSING_S2) {
    EEPROM.update(EEPROM_ADDR_SP2, currentFunctionIndex);
    Serial.print("Stopped S2. Saved progress: ");
    Serial.println(currentFunctionIndex);
  }
  resetSystem();
}

void resetSystem() {
  currentState = IDLE;
  digitalWrite(stro1led, LOW);
  digitalWrite(stro2led, LOW);
}

Every single time your code goes through loop(), if your currentState isn't IDLE, your loop code does this:

         case <not IDLE>:
            digitalWrite(stroNled, HIGH);

So yeah, your various sNpatternN functions can do whatever they like to the LED but as soon as control passes back to your loop() the output is set HIGH. A scope on one of your LED pins would probably reveals very short low pulses from the sNpatternN function, but they're cut short by loop().

My "this code looks... strange" meter is twitching.

Same. Long press or short press only gets a blip from the corresponding LED, and this...



Starting sequence. Resuming at function index: 0
Stopped S1. Saved progress: 0
Starting sequence. Resuming at function index: 0
Stopped S2. Saved progress: 0
Starting sequence. Resuming at function index: 0
Stopped S2. Saved progress: 0
Starting sequence. Resuming at function index: 0
Stopped S1. Saved progress: 0
Starting sequence. Resuming at function index: 0
Stopped S1. Saved progress: 0
Starting sequence. Resuming at function index: 0
Stopped S2. Saved progress: 0
Starting sequence. Resuming at function index: 0
Stopped S2. Saved progress: 0
Starting sequence. Resuming at function index: 0
Stopped S1. Saved progress: 0
Starting sequence. Resuming at function index: 0
Stopped S2. Saved progress: 0
Starting sequence. Resuming at function index: 0
Stopped S1. Saved progress: 0

look this button press and timeout routine

  • rather than wait until a button is released, it timesout after the longer HOLD_S2 and when released, if checks if the HOLD_S1 time has expired
  • it trackes when a button state change occurs, debounceMsec to debounce the state changes
  • i left various prints to show what it happening
unsigned long debounceMsec;
int           buttonState;

void butPress ()
{
    // skip checking button is immediately after state change
    if (currentMillis - debounceMsec < 50)
        return;

    byte but = digitalRead (BUTTON_PIN);

    // button state change
    if (buttonState != but)  {
        buttonState  = but;
        debounceMsec = currentMillis;

        if (LOW == but) {               // Button is being pressed
            Serial.println ("  butPress: press");

            if (IDLE != currentState)
                stopAndSave ();

            else {
                buttonWasPressed     = true;
                buttonPressStartTime = currentMillis;
            }
        }
        else {                          // Button is released
            sprintf (s,"  butPress: release %8lu msec",
                            currentMillis - buttonPressStartTime);
            Serial.println (s);

            // has HOLD_S2_TIME already been processed
            if (buttonWasPressed)  {
                buttonWasPressed = false;
                if (currentMillis - buttonPressStartTime >= HOLD_S1_TIME)  {
                    Serial.println ("  butPress: HOLD_S1 expired");
                    startSequence (RUNNING_S1, EEPROM_ADDR_SP1);
                }
            }
        }
    }

    // is button still pressed and HOLD_S2_TIME expired
    else if (buttonWasPressed)  {
        if (currentMillis - buttonPressStartTime >= HOLD_S2_TIME)  {
            Serial.println ("  butPress: HOLD_S2 timeout");

            buttonWasPressed = false;
            Serial.println ("butPress: HOLD_S2 expired");
            startSequence (RUNNING_S2, EEPROM_ADDR_SP2);
        }
    }
}

your pattern functions can be simplified by using global variables global and shortening names.

making code readable will help with debugging

not all LEDs are wired to turn on when the pin i HIGH

enum { LedOff = LOW, LedOn = HIGH };

int             s2State = 0;
unsigned long   s2Millis;

void s2pattern1 ()
{
 // const unsigned long intervals [4] = {   15,     100,   15, 1270 };
    const unsigned long intervals [4] = { 1000,     100,  1000,    100 };
    const int           vals      [4] = { LedOn, LedOff, LedOn, LedOff };

    if (currentMillis - s2Millis >= intervals [s2State]) {
        digitalWrite (stro2led, vals [s2State]);

        s2State  = ++s2State % 4;
        s2Millis = currentMillis;
    }
}

void s2pattern2 () {
    static int s2currentState = 0; // Keeps state between calls
    unsigned long s2currentMillis = millis ();
    static unsigned long s2previousMillis = 0; // Keeps time between calls
    const unsigned long s2p2intervals[5] = {750, 15, 100,  15,  620};
    const int s2p2ledStateValues[5] = {LOW, HIGH, LOW, HIGH, LOW};

    if (s2currentMillis - s2previousMillis >= s2p2intervals[s2currentState]) {
        s2previousMillis = s2currentMillis; // Save the time of the change
        // Move to the next state (loops back to 0 after 1)
        s2currentState = (s2currentState + 1) % 5;
        // Apply the new LED state
        digitalWrite (stro2led, s2p2ledStateValues[s2currentState]);
    }
}
  // --- SEQUENCE EXECUTION STATE MACHINE ---
  if (currentState != IDLE) {
    unsigned long elapsedTime = currentMillis - stateStartTime;

    switch (currentState) {
      case RUNNING_S1:
        set1_functions[currentFunctionIndex](); // Let the pattern handle its own pin changes
        if (elapsedTime >= RUN_DURATION) {
          goToPauseState(PAUSING_S1);
        }
        break;

      case PAUSING_S1:
        digitalWrite(stro1led, HIGH); // Pin stays solid HIGH during pause
        if (elapsedTime >= PAUSE_DURATION) {
          goToNextFunction(RUNNING_S1, EEPROM_ADDR_SP1);
        }
        break;

      case RUNNING_S2:
        set2_functions[currentFunctionIndex](); // Let the pattern handle its own pin changes
        if (elapsedTime >= RUN_DURATION) {
          goToPauseState(PAUSING_S2);
        }
        break;

      case PAUSING_S2:
        digitalWrite(stro2led, HIGH); // Pin stays solid HIGH during pause
        if (elapsedTime >= PAUSE_DURATION) {
          goToNextFunction(RUNNING_S2, EEPROM_ADDR_SP2);
        }
        break;

      default:
        break;
    }
  }
}

I'm by far an expert coder. I would have thought by the code above it would run the first pattern and then at the pause it would put LED at high for 3 seconds.

never minde. I see the issue now

      case RUNNING_S2:
        digitalWrite(stro2led, HIGH);
        set2_functions[currentFunctionIndex]();
        if (elapsedTime >= RUN_DURATION) {
          goToPauseState(PAUSING_S2);

Whatever else your code is doing or not doing, your button handling is flawed.

This small sketch is your button handling extrzcted. The last line of it is commented out, but it is a way to globally if crudley debounce any switches. Try the dem0 first, then uncomment that delay(25) and give it another whirl.

Here:


The code:

const int BUTTON_PIN = 10;

unsigned long buttonPressStartTime = 0;
bool buttonWasPressed = false;

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP); // Assumes button connects pin to GND

  Serial.begin(9600);
  Serial.println("hi Mom!\n");

}

void loop() {
  int buttonState = digitalRead(BUTTON_PIN);
  unsigned long currentMillis = millis();

  // --- BUTTON PRESS LOGIC ---
  if (buttonState == LOW) { // Button is being pressed
    if (!buttonWasPressed) {
Serial.println("                                 mouse down,");
      buttonPressStartTime = currentMillis;
      buttonWasPressed = true;
    }
  } else { // Button is released
    if (buttonWasPressed) {
      unsigned long pressDuration = currentMillis - buttonPressStartTime;

      buttonWasPressed = false;
Serial.print("         mouse    up after ");
Serial.println(pressDuration);
    }
  }

//  delay(25);  // poor man's debounce 
}

HTH

a7

I'm trying to keep from using delay in my program. I made the changes at it appears to be working.

A quick question, full code above but when i change this section

switch (currentState) {
      case RUNNING_S1:
	    st1 = 0;
        set1_functions[currentFunctionIndex](); // Continuously fire current function
        if (elapsedTime >= RUN_DURATION) {
          goToPauseState(PAUSING_S1);
        }
        break;

      case PAUSING_S1:
        digitalWrite(stro1led, HIGH); // Pin stays HIGH during pause
        if (elapsedTime >= PAUSE_DURATION) {
          goToNextFunction(RUNNING_S1, EEPROM_ADDR_SP1);
        }
        break;

I added the st1 = 0 My script that will be running may have st1 = 1 so its running a strobe patter. I added the st1 = 0 as that will stop any strobe patterns. When I push the button I get HIGH on that pen for 3 seconds and then very very dim I can see the LED flashing. Any clue why this is? I would like for both of the sets if a flash pattern is running, when the button is pushed for that strobe it will stop, run the setup. When the button is pushed it stores it in epprom and then loads that as a flash pattern

i see st1 in the code you posted in the other thread: Puzzled on issue with LED not this version posted above

your switch statement can only run one strobe at a time,not both. why not run separate sequencers for each LED?

Of course you are. Is is in fact the lack of any delay or significant time wasting that makes the button logic fail.

Did you run my demo, edit it and run it again?

Did you put similar print statements into your sketch to see if your button logic is flawed? It is possible I damaged it when I isolated it.

You've made changes that "fix" the code. Pease post the complete you think it works sketch. Let's see if something else you did fixed the issue, or if the issue is actually not a problem somehow.

Something as innocent as changing the baud rate on the serial printing can chage things, especially in a non-blocking sketch. Let's see if something anything else you may have done fixed the issue, or if the issue is not a problem somehow.

a7

novices tend to write code that describes what they want to do in logic rather than data. They duplicate code to do one more thing and logic changes now require making the same change in all the duplcated code.

a data driven approach captures the data in arrays (see K&R pg 83). but the various other variables can be captured in a user defined data type, struct (see K&R pg 114).

the following code does this, capturing the pattern arrays in a structure and having an array of structures pat1 and pat2 for the 2 LEDs and capturing the ancillary variables to track which pattern, patIdx and the msec interval msecIdx within the pattern, along with the PinLed, EEPROM Adr and various timer constants and variables: RunMsec, patMsec and runMsec.

const byte  Nul = 255;
const int   Nmsec = 2;

struct Pattern {
    unsigned long msec [Nmsec];
};

Pattern pat1 [] = {
    {  200,  200 },
    { 1000, 1000 },
    {  Nul },
};

Pattern pat2 [] = {
    { 2900,   100 },
    { 2500,   500 },
    { 2000,  1000 },
    { 1500,  1500 },
    { 1000,  2000 },
    {  500,  2500 },
    {  Nul },
};

// -------------------------------------
struct Sequence {
    const byte    PinLed;
    const int     Adr;
    unsigned long RunMsec;
    Pattern      *pat;

    int           patIdx;
    int           msecIdx;
    unsigned long patMsec;
    unsigned long runMsec;
}
seqs [] = {
    { 10,  0, 5000, pat1 },
    { 11,  1, 6000, pat2 },
    { 12,  2, 9000, pat1 },
};
const int Nseq = sizeof(seqs) /sizeof(Sequence);

I hope you see that additional patterns for each LED can easily be addes as well as handling more than 2 LEDs

these data structures are processed by single function, sequencer() that handles that various variables using indices.

void sequencer ()
{
    for (int n = 0; n < Nseq; n++)  {
        Sequence *seq = & seqs [n];

        // advacne to next pattern
        if (msec - seq->runMsec >= seq->RunMsec)  {
            seq->runMsec = msec;

            seq->msecIdx = 0;
            seq->patIdx++;
            if (Nul == seq->pat [seq->patIdx].msec [0])
                seq->patIdx = 0;
            digitalWrite (seq->PinLed, LedOff);

            sprintf (s, "%40s sequencer: seq %d, pat %d", "", n, seq->patIdx);
            Serial.println (s);
        }

        // toggle LED
        if (msec -seq->patMsec >= seq->pat [seq->patIdx]. msec [seq->msecIdx]) {
            seq->patMsec = msec;

            byte pin   = seq->PinLed;
            digitalWrite (pin, ! digitalRead (pin));        // toggle

            if (Nmsec <= ++seq->msecIdx)
                seq->msecIdx = 0;
        }
    }
}

no doubt this may seem overwhelming, but it appears your spending a lot of time debugging your current code

Again, I'm far from an expert.

//try with setup strobe
#include <EEPROM.h>
   
int st1 = 1; 
int st2 = 1; 
int s1p = 1; 
int s2p = 1; 

// Pin Definitions
const int stro1led = 7;
const int stro2led = 8;
const int BUTTON_PIN = 10;

// EEPROM Memory Addresses
const int EEPROM_ADDR_SP1 = 0;
const int EEPROM_ADDR_SP2 = 1;

// Timing Constants (in milliseconds)
const unsigned long HOLD_S1_TIME = 3000; // 3 seconds
const unsigned long HOLD_S2_TIME = 6000; // 6 seconds
const unsigned long RUN_DURATION = 20000; // 20 seconds
const unsigned long PAUSE_DURATION = 3000; // 3 seconds

// State Machine Definitions
enum SystemState { IDLE, RUNNING_S1, PAUSING_S1, RUNNING_S2, PAUSING_S2 };
SystemState currentState = IDLE;

// Execution Tracking
int currentFunctionIndex = 0;
unsigned long stateStartTime = 0;
unsigned long buttonPressStartTime = 0;
bool buttonWasPressed = false;

// strobe 1 patterns
//--------------------------------------------------------------------------------------------------------------
void s1pattern1() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p1intervals[4] = {15, 100, 15, 1370}; 
  const int s1p1ledStateValues[4] = {HIGH, LOW, HIGH, LOW}; 

      if (s1currentMillis - s1previousMillis >= s1p1intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 3)
      s1currentState = (s1currentState + 1) % 4;
      // Apply the new LED state
      digitalWrite(stro1led, s1p1ledStateValues[s1currentState]);
    }
  }
  void s1pattern2() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p2intervals[2] = {15, 1485}; // pattern 2
  const int s1p2ledStateValues[2] = {HIGH, LOW}; // pattern 2

      if (s1currentMillis - s1previousMillis >= s1p2intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s1currentState = (s1currentState + 1) % 2;
      // Apply the new LED state
      digitalWrite(stro1led, s1p2ledStateValues[s1currentState]);
    }
  }
 void s1pattern3() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p3intervals[2] = {15, 985}; // pattern 3
  const int s1p3ledStateValues[2] = {HIGH, LOW}; // pattern 2

      if (s1currentMillis - s1previousMillis >= s1p3intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s1currentState = (s1currentState + 1) % 2;
      // Apply the new LED state
      digitalWrite(stro1led, s1p3ledStateValues[s1currentState]);
    }
 }
    void s1pattern4() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p4intervals[2] = {15, 735}; // pattern 2
  const int s1p4ledStateValues[2] = {HIGH, LOW}; // pattern 2

      if (s1currentMillis - s1previousMillis >= s1p4intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s1currentState = (s1currentState + 1) % 2;
      // Apply the new LED state
      digitalWrite(stro1led, s1p4ledStateValues[s1currentState]);
    }
    }
    void s1pattern5() { 
  static int s1currentState = 0; // Keeps state between calls
  unsigned long s1currentMillis = millis(); 
  static unsigned long s1previousMillis = 0; // Keeps time between calls
  const unsigned long s1p5intervals[2] = {15, 585}; // pattern 2
  const int s1p5ledStateValues[2] = {HIGH, LOW}; // pattern 2

      if (s1currentMillis - s1previousMillis >= s1p5intervals[s1currentState]) {
      s1previousMillis = s1currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s1currentState = (s1currentState + 1) % 2;
      // Apply the new LED state
      digitalWrite(stro1led, s1p5ledStateValues[s1currentState]);
    }
  }
     void s1pattern6() {
	 digitalWrite(stro1led, LOW);
}	 
// strobe 2 patterns
//--------------------------------------------------------------------------------------------------------------
void s2pattern1() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p1intervals[4] = {15, 100, 15, 1270}; 
  const int s2p1ledStateValues[4] = {HIGH, LOW, HIGH, LOW  }; 

      if (s2currentMillis - s2previousMillis >= s2p1intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 3)
      s2currentState = (s2currentState + 1) % 4;
      // Apply the new LED state
      digitalWrite(stro2led, s2p1ledStateValues[s2currentState]);
    }
  }
  void s2pattern2() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p2intervals[5] = {750, 15, 100,  15,  620}; 
  const int s2p2ledStateValues[5] = {LOW, HIGH, LOW, HIGH, LOW};; 

      if (s2currentMillis - s2previousMillis >= s2p2intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 5;
      // Apply the new LED state
      digitalWrite(stro2led, s2p2ledStateValues[s2currentState]);
    }
  }
 void s2pattern3() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p3intervals[3] = {750, 15, 735}; 
  const int s2p3ledStateValues[3] = {LOW, HIGH, LOW}; 

      if (s2currentMillis - s2previousMillis >= s2p3intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 3;
      // Apply the new LED state
      digitalWrite(stro2led, s2p3ledStateValues[s2currentState]);
    }
  }
    void s2pattern4() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p4intervals[3] = {500, 15, 485}; 
  const int s2p4ledStateValues[3] = {LOW, HIGH, LOW}; 

      if (s2currentMillis - s2previousMillis >= s2p4intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 3;
      // Apply the new LED state
      digitalWrite(stro2led, s2p4ledStateValues[s2currentState]);
    }
  }
    void s2pattern5() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p5intervals[3] = {375, 15, 360};
  const int s2p5ledStateValues[3] = {LOW, HIGH, LOW}; 

      if (s2currentMillis - s2previousMillis >= s2p5intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 3;
      // Apply the new LED state
      digitalWrite(stro2led, s2p5ledStateValues[s2currentState]);
    }
  }
      void s2pattern6() { 
  static int s2currentState = 0; // Keeps state between calls
  unsigned long s2currentMillis = millis(); 
  static unsigned long s2previousMillis = 0; // Keeps time between calls
  const unsigned long s2p6intervals[3] = {300, 15, 285}; 
  const int s2p6ledStateValues[3] = {LOW, HIGH, LOW}; 

      if (s2currentMillis - s2previousMillis >= s2p6intervals[s2currentState]) {
      s2previousMillis = s2currentMillis; // Save the time of the change
      // Move to the next state (loops back to 0 after 1)
      s2currentState = (s2currentState + 1) % 3;
      // Apply the new LED state
      digitalWrite(stro2led, s2p6ledStateValues[s2currentState]);
    }
  }

// Function Pointers for the 2 Sets
void (*set1_functions[6])() = {s1pattern1, s1pattern2, s1pattern3, s1pattern4, s1pattern5, s1pattern6};
void (*set2_functions[6])() = {s2pattern1, s2pattern2, s2pattern3, s2pattern4, s2pattern5, s2pattern6};

void setup() {
  pinMode(stro1led, OUTPUT);
  pinMode(stro2led, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP); // Assumes button connects pin to GND
  
  digitalWrite(stro1led, LOW);
  digitalWrite(stro2led, LOW);
  Serial.begin(9600);
}

void loop() {
  // Strobe 1
  //------------------------------------------------------------------------------
 // Pick strobe 1 pattern
  if (st1 == 1 && s1p == 1) {
    s1pattern1();
  }
  else if (st1 == 1 && s1p == 2) {
    s1pattern2();
  }
    else if (st1 == 1 && s1p == 3) {
    s1pattern3();
  }
    else if (st1 == 1 && s1p == 4) {
    s1pattern4();
  }
    else if (st1 == 1 && s1p == 5) {
    s1pattern5();
  }
  else {
    digitalWrite(stro1led, LOW);
  }   //  led off
// Strobe 2
//------------------------------------------------------------------------------
// Pick strobe 1 pattern
  if (st2 == 1 && s2p == 1) {
    s2pattern1();
  }
  else if (st2 == 1 && s2p == 2) {
    s2pattern2();
  }
    else if (st2 == 1 && s2p == 3) {
    s2pattern3();
  }
    else if (st2 == 1 && s2p == 4) {
    s2pattern4();
  }
    else if (st2 == 1 && s2p == 5) {
    s2pattern5();
  }
    else if (st2 == 1 && s2p == 6) {
    s2pattern6();
  }
  else {
    digitalWrite(stro2led, LOW);
  }   //  led off

  int buttonState = digitalRead(BUTTON_PIN);
  unsigned long currentMillis = millis();

  // --- BUTTON PRESS LOGIC ---
  if (buttonState == LOW) { // Button is being pressed
    if (!buttonWasPressed) {
      buttonPressStartTime = currentMillis;
      buttonWasPressed = true;
    }
  } else { // Button is released
    if (buttonWasPressed) {
      unsigned long pressDuration = currentMillis - buttonPressStartTime;
      buttonWasPressed = false;

      if (currentState != IDLE) {
        // Immediate Stop if already running a sequence
        stopAndSave();
      } else {
        // Start sequences from IDLE state
        if (pressDuration >= HOLD_S2_TIME) {
          startSequence(RUNNING_S2, EEPROM_ADDR_SP2);
        } else if (pressDuration >= HOLD_S1_TIME) {
          startSequence(RUNNING_S1, EEPROM_ADDR_SP1);
        }
      }
    }
  }

  // --- SEQUENCE EXECUTION STATE MACHINE ---
  if (currentState != IDLE) {
    unsigned long elapsedTime = currentMillis - stateStartTime;

    switch (currentState) {
      case RUNNING_S1:
      st1 = 0;
        set1_functions[currentFunctionIndex](); // Continuously fire current function
        if (elapsedTime >= RUN_DURATION) {
          goToPauseState(PAUSING_S1);
        }
        break;

      case PAUSING_S1:
        digitalWrite(stro1led, HIGH); // Pin stays HIGH during pause
        if (elapsedTime >= PAUSE_DURATION) {
          goToNextFunction(RUNNING_S1, EEPROM_ADDR_SP1);
        }
        break;

      case RUNNING_S2:
      st2 = 0;
        set2_functions[currentFunctionIndex]();
        if (elapsedTime >= RUN_DURATION) {
          goToPauseState(PAUSING_S2);
        }
        break;

      case PAUSING_S2:
        digitalWrite(stro2led, HIGH); // Pin stays HIGH during pause
        if (elapsedTime >= PAUSE_DURATION) {
          goToNextFunction(RUNNING_S2, EEPROM_ADDR_SP2);
        }
        break;

      default:
        break;
    }
  }
}

// --- STATE HELPER FUNCTIONS ---
void startSequence(SystemState targetState, int eepromAddr) {
  currentState = targetState;
  
  // Read saved progress from EEPROM
  int savedIndex = 0;
  
  // If memory is empty (255) or out of bounds, start from 0
  if (savedIndex >= 6 || savedIndex < 0) {
    currentFunctionIndex = 0;
  } else {
    currentFunctionIndex = savedIndex;
  }
  
  Serial.print("Starting sequence. Resuming at function index: ");
  Serial.println(currentFunctionIndex);
  
  stateStartTime = millis();
}

void goToPauseState(SystemState pauseState) {
  currentState = pauseState;
  stateStartTime = millis();
}

void goToNextFunction(SystemState runState, int eepromAddr) {
  currentFunctionIndex++;
  
  if (currentFunctionIndex >= 6) { 
    // Finished all 6 functions cleanly: reset index in memory to 0
    EEPROM.update(eepromAddr, 0); 
    Serial.println("Sequence complete. Resetting EEPROM memory to 0.");
    resetSystem();
  } else {
    currentState = runState;
    stateStartTime = millis();
  }
}

void stopAndSave() {
  if (currentState == RUNNING_S1 || currentState == PAUSING_S1) {
    EEPROM.update(EEPROM_ADDR_SP1, currentFunctionIndex);
    Serial.print("Stopped S1. Saved progress: ");
    Serial.println(currentFunctionIndex);
  } else if (currentState == RUNNING_S2 || currentState == PAUSING_S2) {
    EEPROM.update(EEPROM_ADDR_SP2, currentFunctionIndex);
    Serial.print("Stopped S2. Saved progress: ");
    Serial.println(currentFunctionIndex);
  }
  resetSystem();
}

void resetSystem() {
  currentState = IDLE;
  digitalWrite(stro1led, LOW);
  digitalWrite(stro2led, LOW);
}

I'm running it on my breadboard setup and also in the demo you made in. On my setup I see its working i think. I can hold for 3 seconds and when released I can see the led do one of two things. It give me a HIGH for 3 seconds or the patter is very dimly flashing. I can press the button and it stops. Same for the 6 second hold. I'm going line by line to see why the LED is dim for the patterns.

When I run it on the online demo you made the LEDs flash normal so i'm puzzled.
I added the int st1 = 1; , and int st2 = 1; so that makes both strobes flash in a pattern and they run the pattern a full brightness. So this tells me its not a breadboard issue. Then when i run the case I have it to set st1 or st2 to 0 so it stops the pattern so I can run the setup. That all is working. its just in the setup that the led is very dim on the pattern.

yes it is overwhelming so from what you are saying this is a different way of running a set of patterns that are already defined. I will have to try to wrap my head around what you are doing.

This is just four button presses. The "released after [> 100 ms]" are legit, those that clock in at 0 or 1 ms are… not.

            button press acted upon
// Button is released after 0
            button press acted upon
// Button is released after 966
            button press acted upon
// Button is released after 1


            button press acted upon
// Button is released after 0
            button press acted upon
// Button is released after 849
            button press acted upon
// Button is released after 1


            button press acted upon
// Button is released after 0
            button press acted upon
// Button is released after 1099
            button press acted upon
// Button is released after 0


            button press acted upon
// Button is released after 0
            button press acted upon
// Button is released after 1699
            button press acted upon
// Button is released after 1

From your code with added print statements, and I separated the four actual pressings. This issue is sensitive to how much printing you do and at what baud rate. Button handling should not be so fragile.
 int buttonState = digitalRead(BUTTON_PIN);
 unsigned long currentMillis = millis();

 // --- BUTTON PRESS LOGIC ---
 if (buttonState == LOW) { // Button is being pressed

   if (!buttonWasPressed) {

Serial.println("             button press acted upon");

     buttonPressStartTime = currentMillis;
     buttonWasPressed = true;
   }
 } else { // Button is released
   if (buttonWasPressed) {

Serial.print("// Button is released after ");

     unsigned long pressDuration = currentMillis - buttonPressStartTime;

Serial.println(pressDuration);

     buttonWasPressed = false;

     if (currentState != IDLE) {
       // Immediate Stop if already running a sequence
       stopAndSave();
     } else {
       // Start sequences from IDLE state
       if (pressDuration >= HOLD_S2_TIME) {
         startSequence(RUNNING_S2, EEPROM_ADDR_SP2);
       } else if (pressDuration >= HOLD_S1_TIME) {
         startSequence(RUNNING_S1, EEPROM_ADDR_SP1);
       }
     }
   }
 }

You have said "I'm far from an expert." so I have to ask - who wrote all that code?

The switch bounces and your code's reaction to them may be no problem at all. But it does mean the code is not doing what you think - never a good thing, and maybe an accident waiting to happen.

a7

over 10 years ago i with the help of google, a few books and a fresh out of collage co worker i learned the basic parts of coding. I wrote the basic part of my program. I will also say at the age of 8 my first computer was a radio shack TRS 80 that connected to my TV. I wrote some programs back then with basic. Just a few months ago i wanted to go from one to 6 patterns and add more options. All the coding for the button parts again came from googling and reading post by others.

on my 3 hour drive out of town my mind was thinking about the code and why my LEDs when i run the setup were dim. It hit me. I have a section in my code where it takes two int to tell it which patter to to run. If they do not meet then a else statement tells the LED low
else {
digitalWrite(stro1led, LOW);
} // led off

When i get back home I will pull that part and see if it helps. After much thought on my program. for this setup part i can use a delay in the programing. just cant have a delay when the program is running I also agree with your info above where if you do not hit the button close to the exact time it will not work. I have started readying on how I can make that timing part with in a range of a second.

was this due to your original problem with the missing if? LEDs were turned on in the first if but turned of in the else condition of the following if?

    if (st2 == 1 && s2p == 1 ){
        if (msec2 - msec2lst >= s2p1intervals [s2currentState]) {
            msec2lst = msec2; // Save the time of the change

            // Move to the next state (loops back to 0 after 3)
            s2currentState = (s2currentState + 1) % 4;
            .
            // Apply the new LED state
            digitalWrite (PinLed2, s2p1ledStateValues [s2currentState]);
        }
    }
    //pattern 2
    // Check if it is time to switch to the next step
    if (st2 == 1 && s2p == 2 ){

isn't this because the code doesn't handle bounce, and that bounce when releasing the button can immediately invoke stopAndSave()?

the button code in post #4 handle bounce using a timer instead of delay()

As far as I can tell, the poor man's debounce (throttling the loop with a simple delay(25)), resolves the bounce issue.

All the times in the sketch activities are long enough so looping at 40 Hz isn't going to be noticed.

This would allow @cubmanky to get the code she wrote or cobbled together, whatever, to work better, maybe even work to plan.

Then if she cared, she could figure out some decent button handling, maybe use a library for it.

Or not.

a7

I will look into this on my code. Yes I’m having some issues.