Stepper motor sketch works only with use of delay()

So I try to get multiple steppermotors to drive to different positions (at different speeds), using the RAMPS1.4 Shield, the drivers that came with it and a MEGA2560.
But I’m currently stuck having not even one Motor driving as intended.

#define MAX 4480
unsigned long current_time = 0;

//Loopvariables

int i = 0;
int j = 0;
int k = 0;
int l = 0;
int m = 0;
int n = 0;
int z = 0;


class Motor
{
  int En_pin;
  int Step_pin;
  int Dir_pin;
  int Min_pin;

  bool cur_state;
  bool prev_state;

  unsigned int Speed_motor;
  unsigned long Time_motor;

  public:
  Motor(int En, int Step, int Dir, int Min, unsigned int Speed)
  {
    En_pin = En;
    Step_pin = Step;
    Dir_pin = Dir;
    Min_pin = Min;
    pinMode(En_pin, OUTPUT);
    pinMode(Step_pin, OUTPUT);
    pinMode(Dir_pin, OUTPUT);
    pinMode(Min_pin, INPUT_PULLUP);

    Speed_motor = Speed;
    
    Time_motor = 0;
    cur_state = 0;
    prev_state = 0;
    
  }

  bool drive(bool direction)
  {
    digitalWrite(Dir_pin, richtung);
    //digitalWrite(En_pin, 0);
    if((cur_state == 0) && (current_time - Time_motor) >= (Speed_motor))
    {
      prev_state = cur_state;
      cur_state = 1;
      digitalWrite(En_pin, 0);
      digitalWrite(Step_pin, cur_state);
      Time_motor = current_time;
      return(0);
    }
    else if((cur_state == 1) && (current_time - Time_motor) >= (Speed_motor))
    {
      prev_state = cur_state;
      cur_state = 0;
      digitalWrite(Step_pin, cur_state);
      digitalWrite(En_pin, 1);
      Time_motor = current_time;
      return(1);
    }   
  }

  void middle()
  {
    while(m < MAX/2)
    {
      current_time = micros();
      k = drive(0);
      if (k == 1)
      {
        m++;
        k = 0;
        //delayMicroseconds(200);
        //Serial.println(m);
      }
    }
  }




  
};

Motor Motor1(38, A0, A1, 14, 200);

void setup()
{
  Serial.begin(9600);
  m = 0;

}
void loop()
{
  current_time = micros();
  Motor1.middle();
}

If I comment out the delayMicroseconds(200) and the Serial.print(m), the motor jumps making only one step, if I leave it in, it drives as it should do.

My next problem is that if I increase the speed (decrease the number) when constructing Motor1, it also doesn’t drive to the intended position, but shorter (no problem by decreasing speed).

I came to the conclusion that my m gets incremented to fast, but I can’t wrap my head around why that is the case.

The Motor usually handles speeds as low as 100 Microsecs well and doesn’t jump any steps (at least as I can tell).
Also yes, this is all the code, as I scrapped my old try.

Any help would be greatly appreciated.

I found a workaround(/the answer?):

    if((cur_state == 0) && (current_time - Time_motor) >= (Speed_motor))
    {
      prev_state = cur_state;
      cur_state = 1;
      digitalWrite(En_pin, 0);
      digitalWrite(Step_pin, cur_state);
      Time_motor = current_time;
      return(0);
    }
    else if((cur_state == 1) && (current_time - Time_motor) >= (Speed_motor))
    {
      prev_state = cur_state;
      cur_state = 0;
      digitalWrite(Step_pin, cur_state);
      digitalWrite(En_pin, 1);
      Time_motor = current_time;
      return(1);
    }  
    
     else
    {
      return(0);
    }

I only added a else return 0.
I don't know how that fixed it/why it works, but the motor sped up and the speed problem also doesn't affect it any more.

ricktac:
But I'm currently stuck having not even one Motor driving as intended.

Start simple.

Use the examples in this Simple Stepper Code to test each motor in turn - with suitable changes for the step and direction pins.

...R
Stepper Motor Basics

Here is code that answers how to wait without delay().

It is a dead simple example. Maybe you can add independent leds or serial I/O as similar tasks.

// add-a-sketch_status_blinker 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 30/2018 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch shows blinking a led with a 16 bit timer, good for a minute.
// This task makes a status blinker. If it blinks, the sketch is running.

byte ledState, ledPin = 13; // use byte for small values, int cost 2 bytes
word startBlink, waitBlink; // 16 bit millis is good to time 65.535 seconds

void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Blink Led, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch shows blinking a led with a 16 bit timer." ));

  pinMode( ledPin, OUTPUT );

  waitBlink = 333;
}

void Blinker()
{
  // word( millis()) turns 32-bit millis() return into the low 16 bits as type word
  if ( word( millis()) - startBlink >= waitBlink ) // difference in time by subtracting start from end
  {
    ledState = !ledState; // ! is logical NOT: 0 becomes 1, not 0 becomes 0. 0 is false.
    digitalWrite( ledPin, ledState ); // the led changes to the new state.
    startBlink += waitBlink; // next blink starts when it should, even if this is late.
  }
}

void loop() // runs over and over 
{
  Blinker();
}

The sketch runs a task to add to other no-delay tasks in a project sketch. This one blinks led13 on time to show that the system is running well. Another displays the loop() count every second. A lightly loaded sketch might run average 67KHz, you need the counter task to know. When you add to a sketch the counter can tell you the speed difference.

I have button, multi-buttons, and button-matrix tasks, a demo task that modifies the action of another task, an example of outputting serial to an ANSI terminal emulator (cursor control and keys sent when pressed), and the un-delay demo for removing delays() from a sketch.
Every task from those can run along with any other tasks in a single sketch. Any new task that shares cycles is good too.

Robin2:
Start simple.

Use the examples in this Simple Stepper Code to test each motor in turn - with suitable changes for the step and direction pins.

...R
Stepper Motor Basics

I started simple (I feel).

This is actually the third time I'm writing code for this application. First was with delay(), second was with micros(), and this time with classes.

And both of the previous projects had been up and running (not very fast), but it was just to much of a mess to optimize them (delay() ruined the first one after i understood the implications, the second had no classes and ~700 lines of code), so I scrapped them and started new.

And while I ran in the "motor doesn't drive without delay" problem in the second one, it was only 20 micros needed to fix it, which seemed acceptable at the time.

GoForSmoke:

// add-a-sketch_status_blinker 2018 by GoForSmoke @ Arduino.cc Forum

// Free for use, Apr 30/2018 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch shows blinking a led with a 16 bit timer, good for a minute.
// This task makes a status blinker. If it blinks, the sketch is running.

byte ledState, ledPin = 13; // use byte for small values, int cost 2 bytes
word startBlink, waitBlink; // 16 bit millis is good to time 65.535 seconds

void setup()
{
 Serial.begin( 115200 );
 Serial.println( F( "\n\n\n  Blink Led, free by GoForSmoke\n" ));
 Serial.println( F( "This sketch shows blinking a led with a 16 bit timer." ));

pinMode( ledPin, OUTPUT );

waitBlink = 333;
}

void Blinker()
{
 // word( millis()) turns 32-bit millis() return into the low 16 bits as type word
 if ( word( millis()) - startBlink >= waitBlink ) // difference in time by subtracting start from end
 {
   ledState = !ledState; // ! is logical NOT: 0 becomes 1, not 0 becomes 0. 0 is false.
   digitalWrite( ledPin, ledState ); // the led changes to the new state.
   startBlink += waitBlink; // next blink starts when it should, even if this is late.
 }
}

void loop() // runs over and over
{
 Blinker();
}

Isn't that pretty much what I'm doing in my sketch above?

ricktac:
If I comment out the delayMicroseconds(200) and the Serial.print(m), the motor jumps making only one step, if I leave it in, it drives as it should do.

You learned to time but there’s more to it than that and that’s why yer stuck here:

  void middle()
  {
    while(m < MAX/2)
    {
      current_time = micros();
      k = drive(0);
      if (k == 1)
      {
        m++;
        k = 0;
        //delayMicroseconds(200);
        //Serial.println(m);
      }
    }
  }

Get rid of the while, make it an if ( m < MAX/2 ).
Use void loop() to drive code loops that were necessary with the top-down code approach.
Now you can use micros() timing?

Timing with millis/micros you can write functions for loop() that count how many times has this been run rather than stay here until something is done so many times which slows everything else. Another technique called state machine is to track the process state and use that to choose what the function does next. Usually the heart of the SM is a switch-case statement with a case per state.

I use loop() to iterate through 2 leds here, there can be more than 2 but the indexing is the point.
You may find something to like, pick up a trick.
Using one task to operate on another older already debugged task takes away any need to add complexity and indent levels to the older one forcing another debug. Simpler to write an operator task.

// add-a-sketch_multi_blinkers 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 30/2018 by GFS. Compiled on Arduino IDE 1.6.9.
// 1 bug removed, 1/1/19 

// multi_blinkers vars
const byte blinkers = 2;
byte blinkerPin[ blinkers ] = { 2, 3 };
byte blinkerState[ blinkers ];
word startBlink[ blinkers ];
word waitBlink[ blinkers ] = { 1000, 250 }; // 2 millis timers per blinker
// type word (16 bit unsigned) good to 65,535. as millis it is > 1 minute.

// multi_blink switching vars
byte blinkCounter[ blinkers ], lastBlinkerState[ blinkers ]; 
byte switchBlinks[ blinkers ] = { 5, 8 }; // blink X times then pause   
word startOffTime[ blinkers ];
word waitOffTime[ blinkers ] = { 5000, 8000 }; // pause millis

void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Blink Led, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch shows a led blink task turned on-off by another task." ));

  for ( byte i = 0; i < blinkers; i++ )
  {
    pinMode( blinkerPin[ i ], OUTPUT );
  }
}

void MultiBlinkers() // you change the blink by changing blinkWait[ blinker ]
{
  static byte index; // static vars keep their data. this 'index' is for this function
  
  if ( waitBlink[ index ] > 0 ) // this is the on/off switch
  {
    // word( millis()) gets the low 16 bits of the 32-bit millis() return.
    if ( word( millis()) - startBlink[ index ] >= waitBlink[ index ] )
    {   // difference in time given by subtracting start from end
      blinkerState[ index ] = !blinkerState[ index ];  // ! is logical NOT, make opposite
      digitalWrite( blinkerPin[ index ], blinkerState[ index ] ); 
      startBlink[ index ] += waitBlink[ index ]; // next blink starts when it should.
    }
  }
  else if ( digitalRead( blinkerPin[ index ] ) > 0 ) // waitBlink == 0 turns blinking off
  {
    digitalWrite( blinkerPin[ index ], LOW ); //  if it's on, turn the led is OFF
  } 

  // this adds 1 to index then compares to blinkers, keeps index inside the array 
  if ( ++index >= blinkers )    index = 0; // if at array end, loop around to start
  // note that only 1 blinker is checked per call. Don't Block, make loop run fast.
}

void MultiBlinkSwitcher()
{
  static byte index; // static vars keep their data. this 'index' is for this function

  // this task pauses the blinker after X blinks then turns blinking back on, repeat.
  if ( waitBlink[ index ] > 0 ) // while the led is blinking
  {
    if ( blinkerState[ index ] != lastBlinkerState[ index ] ) // blink has just transitioned
    {
      if ( blinkerState[ index ] == 0 ) // count a blink only if turned off, blink is finished
      {
        blinkCounter[ index ]++;
        if ( blinkCounter[ index ] == switchBlinks[ index ] ) // X blinks then none for 3 seconds
        {
          blinkCounter[ index ] = 0; // the if has the ++ first, count stats at 1.
          waitBlink[ index ] = 0; // turn the blinking off, start off timing
          startOffTime[ index ] = millis(); // set start to off time
        }
      }
      lastBlinkerState[ index ] = blinkerState[ index ];
    }
  }
  else // this only runs when blinking is off
  {
    // word( millis()) -- gets the low 16 bits of the 32-bit millis() return.
    if ( word( millis()) - startOffTime[ index ] >= waitOffTime[ index ] )
    {
      startBlink[ index ] = millis();
      waitBlink[ index ] = 250;
    }
  }

  byte rtn = index;
  if ( ++index >= blinkers )    index = 0; // if at array end, loop around to start
}

void loop()
{
  // this is the interruptable blink task
  MultiBlinkers(); // sets 'now' only when blinking
  // this task pauses the blinker after 5 blinks then turns blinking back on, repeat.
  MultiBlinkSwitcher();
}