Trying to use class to control NEMA17 with the A4988 Driver without using delay

Hello,

I’m trying to create a class that will allow me to control the NEMA17 Stepper motor with the A4988 stepper motor driver. As I understand it, this setup requires the rapid oscillation of one digital pin from HIGH to LOW connected to the driver that causes the motor to turn based off of directional input from another pin. At the moment, I’m using the exact setup described in this tutorial, except I’m using an Arduino mega.

My motor rotates perfectly using microsecond delays as described in the tutorials but I’m trying to accomplish the same rotation but with a class that doesn’t use delay(). Here’s my code:

#include <Stepper.h>

class Motor //used to control stepper motors
{
  int stepPin;
  int dirPin;

  int state;
  unsigned long previousMillis;

public:
  Motor(int stepPin, int dirPin)
  {
     unsigned long lastUpdate; // last update of position
     stepPin = stepPin;
     dirPin = dirPin;

  }

  void setPins ()
  {
    pinMode(stepPin, OUTPUT);
    pinMode(dirPin, OUTPUT);
    Serial.print ("Pins Set");
  }
  
  void rotate (int dir, int rate)
  {
    if (dir != 0) 
    {
      if (dir == -1) {
        digitalWrite(dirPin, LOW);
      }
      if (dir == 1) {
        digitalWrite(dirPin, HIGH);
      }
      // check to see if it's time to change the state of the LED
      unsigned long currentMillis = millis();
       
      if((currentMillis - previousMillis >= rate) && (state == HIGH))
      {
        state = LOW;  // Turn it off
        digitalWrite(stepPin, LOW);  // flip the value heading to the motor
        Serial.print("LOW");
        previousMillis = currentMillis;  // Remember the time
      }
      else if ((currentMillis - previousMillis >= rate) && (state == LOW))
      {
        state = HIGH;  // turn it on
        Serial.print("HIGH");
        digitalWrite(stepPin, HIGH);   // flip the value heading to the motor
        previousMillis = currentMillis;   // Remember the time
      }
    }
    else 
    {
      digitalWrite(stepPin, LOW); //otherwise stay still
    }
  }
};

Motor test(53,52);

void setup() {
  Serial.begin(9600);
  Serial.print("Start");
  test.setPins();
}

void loop() {
  test.rotate(1, 3);

}

The idea was to create a class for motors in this setup. The rotate function should set the stepPin output to HIGH, wait a very small amount of time (without using delay) then switch it to LOW and repeat indefinitely.

When I run this code, the motor vibrates slightly but does not turn, which is typically also what happens when it has power but no driver input. Of course, I tried lots values for the rate but none worked. I also attempted using digitalWrite straight to the pin ( eg. digitalWrite(53, HIGH)) to see if my class variables somehow weren’t being passed down but that didn’t have any effect.

When I run this code, the serial monitor displays a rapid oscillation of HIGH and LOW as you can see in the code. I compared it to the original code in the tutorial by adding the Serial.print lines to the original and the oscillation of HIGH and LOW speed and pattern seems similar. Thus, my assumption is that there’s something wrong in my class setup with the variables but I can’t figure out what, and everything I’ve thought of trying hasn’t worked.

Please help! The end goal is to have multiple stepper motors running alongside various other components. I don’t want to use delay since I’ll need to have each component adapt to inputs instantly and delay would lock in signals.

Thank you so much, let me know asap if you have any questions or suggestions or leads to other threads that might provide insight into the problem.

          digitalWrite(55, HIGH);  // flip the value heading to the motorWhy are you writing to pin 55 ?

  Motor(int stepPin, int dirPin)
  {
     unsigned long lastUpdate; // last update of position
     stepPin = stepPin;
     dirPin = dirPin;

  }

lastUpdate is local to the constructor, and goes out of scope when the constructor is done. It is, therefore, useless.

      if((currentMillis - previousMillis >= rate) && (state == HIGH))

previousMillis? What the heck is THAT supposed to mean? Is that the lastTimeToStep? Why not use a name that makes sense?

        state = LOW;  // Turn it off
        digitalWrite(stepPin, LOW);  // flip the value heading to the motor
        Serial.print("LOW");

It is too easy, with silly code like this, to get state and the state of the pin out of sync.

        state = LOW;
        digitalWrite(stepPin, state);
        Serial.print("LOW");

With this, with the useless comments removed, the pin state and the variable contents can never get out of sync.

I can't see the value of your class over the tested-and-proven AccelStepper class that does the same thing.

Ethmeister:
but I'm trying to accomplish the same rotation but with a class that doesn't use delay(). Here's my code:

It looks as if your code is trying to step the motor every 6 millisecs. Try a much slower speed - maybe 5 steps per second to start with.

Your code should distinguish between the duration of the step pulse (10 microsecs should be enough) and the interval between steps which is what determines the motor speed. Have a look at the second example in this Simple Stepper Code

You can probably create a suitable step pulse with this simple code

digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);

because the digitalWrite() function is quite slow.

If you need higher speeds you could use the digitalWriteFast library but then I think you would need an explicit step duration. But you need to study the documentation for the stepper driver you are using to see what minimum pulse duration it requires.

...R

UKHeliBob:
          digitalWrite(55, HIGH);  // flip the value heading to the motorWhy are you writing to pin 55 ?

Sorry, that was some legacy code from when I was testing out a different set of pins directly. I changed it back to stepPin, still have the same problem.

PaulS:
I can't see the value of your class over the tested-and-proven AccelStepper class that does the same thing.

I didn't know such a class existed. Thanks for the tip, AccelStepper works great!