Stepper Motor Programming Questions

Hi all, I am 100% new to the Arduino scene. I am a Mechanical engineer and i know some MATLAB, but coding is definitely not my specialty. I am trying to setup a code in which the following happens: A button is pressed, the stepper motor turns a set number of revolutions, and then stops. Then, when the button is pressed again, the motor runs in reverse the same number of steps, and then stops. (I am trying to raise and lower something with the bush of a button. I am currently using a code by Superb to change the direction the motor, but in this code the motor is running continuously. I feel that only slight modification would be needed to make this code do what I want. See the code below:

// Stepper motor run code with a4988 driver
// by Superb

const int stepPin = 3;
int dirPin = 4;
int dirButton = 2;
int state = HIGH;
int reading;
int previous = LOW;
int stepDelay=1000;

long time = 0;
long debounce = 200;

void setup() {
pinMode(stepPin,OUTPUT);
pinMode(dirPin,OUTPUT);
pinMode(dirButton, INPUT_PULLUP);

}

void loop() {
reading = digitalRead(dirButton);

// if the input just went from LOW and HIGH and we've waited long enough
// to ignore any noise on the circuit, toggle the output pin and remember
// the time
if (reading == HIGH && previous == LOW && millis() - time > debounce) {
if (state == HIGH)
state = LOW;
else
state = HIGH;

time = millis();    

}

digitalWrite(dirPin, state);

previous = reading;

digitalWrite(stepPin, HIGH);
delayMicroseconds(stepDelay);
digitalWrite(stepPin, LOW);
delayMicroseconds(stepDelay);
}

How can the motor ever stop? You are not counting steps, so it will ALWAYS step in whatever direction was last selected. You need to count steps to track position, and STOP stepping when you've taken enough steps to reach your target position. Stepping one direction should increase the the step count, the other direction should decrease the step count. When you reach either maximum or minimum position, stop.

You MAY get away with simply changing direction on the fly like that, IF you are stepping slowly. At higher speeds, doing that will cause the stepper to lose steps, or simply stall. A proper steppers driver should use acceleration and deceleration to gradually change the speed to avoid lost steps or stalling.

Hi Ray,
Are you saying that this likely cannot be done? (if so that is understandable because I am new to this)

consider (i needed to slow the step rate to verify with LEDs)

// Stepper motor run code with a4988 driver
// by Superb
#undef MyHW
#ifdef MyHW
const int stepPin   = 10;
const int dirPin    = 11;
const int butPin = A1;
const unsigned stepDelay=50;

#else
const int stepPin = 10;
int dirPin = 4;
int butPin = 2;
const unsigned stepDelay=1000;
#endif

int butLst;

#define N_STEP  100
int steps = 0;

void setup () {
    Serial.begin (9600);

    digitalWrite (stepPin, LOW);
    digitalWrite (dirPin,  LOW);

    pinMode (stepPin, OUTPUT);
    pinMode (dirPin,  OUTPUT);

    pinMode (butPin, INPUT_PULLUP);
    butLst = digitalRead (butPin);
    Serial.println (__func__);
}

void loop () {
    int but = digitalRead (butPin);
    if (butLst != but)  {
        butLst = but;

        if (LOW == but)
            if (0 == steps)
                steps = N_STEP;

        Serial.println (steps);
        delay (10);     // debounce
    }

    if (steps)  {
        steps--;
        digitalWrite (stepPin, HIGH);
#ifdef MyHW
        delay (stepDelay);
#else
        delayMicroseconds (stepDelay);
#endif

        digitalWrite (stepPin, LOW);
#ifdef MyHW
        delay (stepDelay);
#else
        delayMicroseconds (stepDelay);
#endif
    }
}

gcjr,
Thanks for the help!
So a tried that code (without making any modifications to the code or my circuitry) and this is what happened:

Upon uploading the code, the stepper ran continuously. When the button is pressed, the stepper pauses until the button is released. Then it continue. And then begins slowing down (roughly. not a smooth deceleration) and eventually came to a stop.

Yes, what you are trying to do will work, but there is nothing in the code that says to stop.

First, please read: How to get the best out of this forum

In particular use code tags to post your code. (But first, in the IDE use CTRL-T to clean up your indentation).

It is strongly recommended that you don't use reserved words, like "time" as a variable name. If you ever introduce a clock into your project the compiler will complain a lot. Use something more descriptive, like "buttonTime". First this makes the code easier to read and second, there is virtually no chance that "buttonTime" is a reserved word.

Your debounce timing won't work because your variable "time" is uninitialized on the first loop.

Personally, I use a library function called "Bounce2.h" when I want to debounce a button. The Bounce2 library simplifies debouncing and can have two actions if the button is held for a short or long press. For example, press and hold to start the servo or press briefly to stop it.

About how many revolutions is that? And how many steps in a revolution?

I would recommend the AccelStepper library. It will keep track of the stepper's current position and allow you to move to any specific position, like this:

#include <AccelStepper.h>

const int stepPin = 3;
const int dirPin = 4;
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);

const int StepsPerRevolution = 200;
const int Revolutions = 30;
const long Top = StepsPerRevolution * Revolutions;
const long Bottom = 0;

const int dirButton = 2;
int state = LOW;  // Starting at Bottom

unsigned long debounce = 200;

void setup()
{
  pinMode(dirButton, INPUT_PULLUP);
  stepper.setMaxSpeed(100);
  stepper.setAcceleration(20);
}

void loop()
{
  stepper.run();

  static int previous = HIGH;
  static unsigned long time = 0;
  int reading = digitalRead(dirButton);

  // if the input just went from LOW and HIGH and we've waited long enough
  // to ignore any noise on the circuit, toggle the output pin and remember
  // the time
  if (reading == HIGH && previous == LOW && millis() - time > debounce)
  {
    time = millis();

    if (state == HIGH)
    {
      stepper.moveTo(Bottom);
      state = LOW;
    }
    else
    {
      stepper.moveTo(Top);
      state = HIGH;
    }
  }
  previous = reading;
}

that's not what i would expect to happen. when i tested the code, both the LEDs, representing the step and dir pins were on. these are active low so being on indicates the pins were LOW.

when i press the button, one LED begins flashing and then eventually stops, becoming on again.

the code you posted uses delayMicrosecond() and a delay of 1000 (1ms). this means ~msec /step and only 0.2 sec for 100 steps.

i don't understand several things which may (???) be explained if the code is stepping the motor too quickly.

of course, you need to understand what the code is doing. i added serial prints to help debug.

you could slow things down, at least 10 msec per step, verify the function of the button, determine why the motor does not stop. how fast can the motor be stepped?

I am not exactly sure how many revolutions I need yet. This will require testing for the raising and lowering because I am using a "reeling" method. The stepper I am using is a nema17 which has 200 steps per revolution.

Ok. I will try the code again and make sure wiring is correct. As for the issues in the code that I posted, that code is pulled from a tutorial that I watched which performed what I presumed to be a similar operation. Again, I may not quite realize what I need due to my lack of programming knowledge.

again ... try a longer delay

1 Like

Hi John,
I installed the library and tried your code. It works flawlessly! Thank you very much for your help!