// Stepper motor, no delay(), no library, non-blocking

byte dirPin   = 2;
byte stepPin  = 3;
byte limitPin = 4;
byte startPin = 5;

bool stepNow   = 0;       // flag to indicate time to step
bool stepState = LOW;     // used to start a stepper pulse
bool currentButtonState;  // current button state (pressed/not pressed)
bool lastButtonRead;      // previous button reading

unsigned long previousMillis = 0;   // store last step
unsigned long interval = 2;         // (milliseconds) half-interval for stepping
unsigned long debounceTimeout = 50; // debounceTimeout
unsigned long timer = 0;            // measures button press time

void setup() {
  Serial.begin(9600);
  pinMode(dirPin, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(limitPin, INPUT_PULLUP);
  pinMode(startPin, INPUT_PULLUP);
  digitalWrite(dirPin, HIGH); // 1 = CW
  welcome();
  while (digitalRead(startPin)); // wait for START button press
  Serial.print("*** PRESS LIMIT ***");
}

void loop() {
  checkElapsedTime();
  stepMotor();
  readLimit();
}

void readLimit() {
  bool currentButtonRead = digitalRead(limitPin);  // read button pin
  if (currentButtonRead != lastButtonRead) {        // if button pin reading changes...
    timer = millis();                               // ...start a timer
    lastButtonRead = currentButtonRead;             // ... and store current state
  }

  if ((millis() - timer) > debounceTimeout) {                   // if button read change was longer than debounceTimeout
    if (currentButtonState == HIGH && lastButtonRead == LOW) {  // ... and State NOT pressed while Button PRESSED

      changeMotorDirection(dirPin); // call function after button is pressed and released

    }
    currentButtonState = currentButtonRead;  // change the state
  }
}

void changeMotorDirection(byte dirPin) {
  digitalWrite(dirPin, !digitalRead(dirPin));
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  if (digitalRead(dirPin))
    Serial.print(" CW");
  else
    Serial.print(" CCW");
}

void checkElapsedTime() { // for the stepper motor
  unsigned long currentMillis = millis(); // store the time
  if (currentMillis - previousMillis >= interval) { // compare elapsed time to interval
    previousMillis = currentMillis; // store last step time
    stepNow = 1; // flag to indicate it is time to step the motor
  }
}

void stepMotor() {
  if (stepNow) {
    stepNow = 0; // clear step flag

    // two methods to step the stepper...
    // squarewave(); // HIGH for interval, LOW for interval
    singlepulse(); // HIGH/LOW pulse then wait for next interval
  }
}

void squarewave() { // toggle the state
  stepState = !stepState;
  delay(10); // let the motor arrive at the next step
  digitalWrite(stepPin, stepState); // step the motor
}

void singlepulse() { // minimum requirement to step a stepper
  digitalWrite(stepPin, HIGH);
  delay(10); // let the motor arrive at the next step
  digitalWrite(stepPin, LOW);
}

void welcome() {
  Serial.println("Step and change direction using event timing.");
  Serial.println("- non-blocking\n- no library\n- square wave or single pulse\n ** PRESS START **");
}
A4988
LIMIT
START