How to manually start Blink Without Delay

As a learning process, I examined the code for Blink Without Delay and understand pretty much what each line does. Now I'd like to know a simple way to start it with a momentary button press.

(From my experience in general electronics, I am aware of issues like key bounce. The button is just representative of an input trigger).

I pursued several search results but the OPs all want to do something in addition to blinking an LED. The ensuing discussions and attempts to help quickly muddle up things for a raw beginner like me.

So could you please help by providing a straightforward way to manually start BWoD with a momentary LOW input on a pin?

I've tried a few ideas of my own and can run BWoD while a button is pressed. I'd like to know how to make it keep running after the button is released. The ultimate object is to learn how to control other processes using millis.

Here's my sketch for blinking while pressing a button:

unsigned long previousMillis = 0;

void setup()
{
pinMode(13, OUTPUT);
pinMode(4, INPUT_PULLUP);
}

void loop()
{
  unsigned long currentMillis = millis();

if (digitalRead(4) == LOW)
 {
  if (currentMillis - previousMillis >= 500) 
  {
    previousMillis = currentMillis;
  if (digitalRead(13) == LOW)
    {
  digitalWrite(13, HIGH);
    }
  else
    {
  digitalWrite(13, LOW);
    }
  }
 }
}


Change the code so that when a button press is detected a boolean variable is set to true

Take the BWoD code out of the test for the button press and make it run only when the boolean is true

Alternatively, test for the button press in setup() using a while loop and only end the while loop when you detect a button press. Put the normal BWoD code in loop()

This toggles the blink with a button.

// NonBlockedSketchLedAndButton v1.1 by GoForSmoke 03/15/24
// compiles, untested so far
// expect: ground pin 7 to toggle blink off/on

const byte blinkPin = 13; // Uno board LED pin13

const byte buttonPin = 7; // a jumper from pin 7 to GND = pressed
byte buttonStateNow, buttonStatePrev; // to compare what is to what was
const word debounce = 10; // ms delay while the contacts settle, dirty signal
word debounceStart; // interval is debounce above

byte blinkState;  // led13 0=OFF, not-0=ON
unsigned long blinkStart, blinkInterval = 500; // ON/OFF times are equal
const unsigned long interval = 500; // so blinkInterval can reset after change


void setup()
{
  pinMode( blinkPin, OUTPUT ); // LOW by default
  // blinkState is 0 by default
  pinMode( buttonPin, INPUT_PULLUP );
  buttonStateNow = buttonStatePrev = 1;
}

void blink()
{
  static unsigned long waitStart, waitMs;
  if ( blinkInterval == 0 )
  {
    return;
  }

  if ( waitMs > 0 ) // if-timer runs when set then turns itself off
  {
    if ( millis() - waitStart >= waitMs )  // see if wait is over
    {
      waitMs = 0; // wait is over, turn wait off!
    }
  }
  else
  {
    blinkState = !blinkState; // 0 <==> 1
    digitalWrite( blinkPin, blinkState ); // led ON
    waitMs = blinkInterval;
    waitStart = millis();
  }
  return;
}


void button()
{
  static byte State = 0;  //  local variable only the function uses
  static unsigned long waitStart, waitMs;  // local vars

  if ( waitMs > 0 ) // if-timer for state machine delays
  {
    if ( millis() - waitStart >= waitMs )
    {
      waitMs = 0;
    }
  }
  else
  {
    switch ( State )
    {
      case 0 :
        buttonStateNow = digitalRead( buttonPin );
        if ( buttonStateNow == 0 && buttonStatePrev == 1 ) // press detected
        {
          State = 1;
          waitMs = debounce;
          waitStart = millis();
        }
        else if ( buttonStateNow == 1 && buttonStatePrev == 0 ) // release detected
        {
          waitMs = debounce;
          waitStart = millis();
        }
        buttonStatePrev = buttonStateNow;
        break;

      case 1 :
        if ( blinkInterval > 0 )
        {
          blinkInterval = 0; // stop blinking
          digitalWrite( blinkPin, LOW );
        }
        else
        {
          blinkInterval = interval; // blink at interval
        }
        State = 0;
        break;
    }
  }
  return;
}

void loop()
{
  button();
  blink();
}

Thanks for the quick reply. I'll try that.
It will take me some time to do something an expert could do in seconds though.

Will try that too. Thank you.

Simply add this line at the end of setup()

  while (digitalRead(4) == HIGH);

EDIT: Sorry, @UKHeliBob you already suggested that!

Got questions, ask.

My button is a jumper that I put one end in pinhole 7 and the other, to press in GND pinhole or touch on the USB port box (grounded).

This demo has a blocked version. The unblocked version I posted is the blocked version converted to use millis.

It works! That, even I could do in seconds. Thanks.

The following example provides a class object for BWOD and a class object to debounce a pushbutton using BWOD, as well as the blinking and on/off logic.

/*  Blink Without Delay and Pushbutton Example
 *  by @Perehama
 */

class IntervalTimer {
  public:
    IntervalTimer(unsigned long i);
    void synchronizeTimer();
    bool intervalComplete();
    void setInterval(unsigned long i);
    unsigned long elapsedTime();
  private:
    unsigned long _interval;
    unsigned long _timestamp;
};

class PushButton {
  public:
    PushButton(int pinNumber, unsigned long debounceTime);
    void inputPullup() const;
    bool isPushed();
    unsigned long durationHeld();
    void setDebounce(unsigned long i);
  private:
    IntervalTimer _timer;
    int _preState = HIGH;
    unsigned char _debounceFlag = 0;
    const int _ButtonPin;
    const static int _RisingEdge = HIGH - LOW;
    const static int _FallingEdge = LOW - HIGH;
};

IntervalTimer::IntervalTimer(const unsigned long i) : _interval(i) {}

void IntervalTimer::synchronizeTimer() {
  _timestamp = millis();
}
bool IntervalTimer::intervalComplete() {
  if (millis() - _timestamp >= _interval) {
    _timestamp += _interval;
    return true;
  }
  return false;
}

void IntervalTimer::setInterval(unsigned long i) {
  _interval = i;
}

unsigned long IntervalTimer::elapsedTime() {
  unsigned long x = millis() - _timestamp;
  return x;
}

PushButton::PushButton(int pinNumber, unsigned long debounceTime) : _timer(debounceTime), _ButtonPin(pinNumber) { }

void PushButton::inputPullup() const {
  pinMode(_ButtonPin, INPUT_PULLUP);
}

bool PushButton::isPushed() {
  bool b = false;
  if (_debounceFlag == 1) {
    if (_timer.intervalComplete()) _debounceFlag = 0;
  }
  else {
    int sample = digitalRead(_ButtonPin);
    int state = sample - _preState;
    if (state == _FallingEdge) {
      _timer.synchronizeTimer();
      b = true;
      _debounceFlag = 1;
    }
    else if (state == _RisingEdge) {
      _timer.synchronizeTimer();
      _debounceFlag = 1;
    }
    _preState = sample;
  }
  return b;
}

unsigned long PushButton::durationHeld() {
  unsigned long u = 0;
  if (_preState == LOW) {
    u = _timer.elapsedTime();
    if (u == 0) u = 1;
  }
  return u;
}

void PushButton::setDebounce(unsigned long i) {
  _timer.setInterval(i);
}

const int ButtonPin = 8;
const int LedPin = LED_BUILTIN;
unsigned char onOffFlag;
unsigned char blinkerBit;

PushButton Button(ButtonPin, 50UL);

IntervalTimer BlinkTimer(500UL);

void setup() {
  Button.inputPullup();
  pinMode(LedPin, OUTPUT);
}

void loop() {
  if (onOffFlag > 0) {
    if (Button.isPushed()) {
      blinkerBit = onOffFlag = 0;
      digitalWrite(LedPin, LOW);
    }
    else if (BlinkTimer.intervalComplete()) {
      blinkerBit ^= 1;
      (blinkerBit > 0) ? digitalWrite(LedPin, HIGH) : digitalWrite(LedPin, LOW);
    }
  }
  else {
    if (Button.isPushed()) {
      BlinkTimer.synchronizeTimer();
      blinkerBit = onOffFlag = 1;
      digitalWrite(LedPin, HIGH);
    }
  }
}

The Pin assignment is around line 98.
To help with the debounce, I suggest the following push-button circuit.