Stepper motor cancellation

I want to cancel the button1 with the button2 but I can't figure it out how

It's a personal project where the stepper motor is running at first and when the button1 is pressed, it will stop, then when the button 2 is pressed the button 1 will cancel and the stepper motor will run again

#include <Stepper.h>

int stepsPerRevolution = 2048;
int motSpeed = 50;
int dt = 500;

#define buttonPin  6
#define buttonPin2 7
int motDir = 1;
bool motRun = false;

Stepper myStepper(stepsPerRevolution, 2, 4, 3, 5);

void setup()
{
  Serial.begin(9600);
  myStepper.setSpeed(motSpeed);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(buttonPin2, INPUT_PULLUP);
  
}

void loop()
{
  bool button1State = digitalRead(buttonPin);
  bool button2State = digitalRead(buttonPin2);

  {while(digitalRead(buttonPin) ==LOW)
    myStepper.step(motDir * 1);
      delayMicroseconds(dt);


  if (digitalRead(buttonPin) == HIGH)
  
    myStepper.step(0);
  }
  if (digitalRead(button1State == HIGH && button2State == LOW))
  {buttonPin == LOW;
    
  }  


  
}

I would use a "state machine", where operation is controlled by a variable, rather than a button.
e.g.

int state = 0; //stepper stopped
...
if (digitalRead(button)==HIGH) state = 1; //set stepper state to running

The Arduino state machine example will give you some ideas, or search for other examples.

Hi @shigs555 ,

if you read your sketch carefully you will find this:

 {while(digitalRead(buttonPin) ==LOW)
    myStepper.step(motDir * 1);
      delayMicroseconds(dt);

I think that the curly bracket is at the wrong place here. It should be on the right hand side:

 while(digitalRead(buttonPin) ==LOW){
      myStepper.step(motDir * 1);
      delayMicroseconds(dt);

Otherwise only the line " myStepper.step(motDir * 1);" would be inside the while loop().

Feel free to check out this sketch:

/*
  Forum: https://forum.arduino.cc/t/stepper-motor-cancellation/1213693
  Wokwi: https://wokwi.com/projects/387464144368906241
*/

#include <Stepper.h>

int stepsPerRevolution = 2048;
int motSpeed = 50;
int dt = 500;

const byte button1Pin = 6;
const byte button2Pin = 7;
int motDir = 1;
bool motRun = false;

Stepper myStepper(stepsPerRevolution, 2, 4, 3, 5);

void setup()
{
  Serial.begin(9600);
  myStepper.setSpeed(motSpeed);
  pinMode(button1Pin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);

}

void loop()
{
  bool button1State = digitalRead(button1Pin);
  motRun = (button1State == LOW);
  while (motRun){
    bool button2State = digitalRead(button2Pin);
    myStepper.step(motDir * 1);
    delayMicroseconds(dt);
    motRun = (button2State == HIGH);
  }
}

which you can test on Wokwi: https://wokwi.com/projects/387464144368906241

Explanation:

void loop()
{
  // Read the status of button1 in loop()
  bool button1State = digitalRead(button1Pin);
  
  // if the button is pressed set motRun to true, else to false
  motRun = (button1State == LOW);

 // While motRun is true do what's in the while-loop()
  while (motRun){

   // Read the state of button2 
    bool button2State = digitalRead(button2Pin);

   // Control the stepper
    myStepper.step(motDir * 1);

  // Wait for dt micro seconds
    delayMicroseconds(dt);

   // If button2 is pressed (LOW) set motRun to false else to true
  // So if button2 is pressed leave the while loop() which stops the stepper
  // as it is no longer stimulated by myStepper.step()
    motRun = (button2State == HIGH);
  }
}

This can be seen as a "minimum state machine" depending on the boolean motRun ...

The nice thing is that due to the use of two buttons and the immediate change into the other state where the specific button is no longer evaluated there is no need to debounce the buttons.

As this is a special case I recommend to have a look at debouncing buttons, e.g. here https://www.circuitbasics.com/how-to-use-switch-debouncing-on-the-arduino/

Otherwise sooner or later it will create trouble :wink:

Good luck!

Already checked it, I think I confused you

I forgot to state that I'm using a normally closed limit switch for the button 1

The stepper motor will run when the code starts and when the limit switch is pressed, it will stop the stepper motor

And then when button 2 is pressed the stepper motor will run again

And then repeat

Thank you for this, I'll try to make one using that

Does it mean that the stepper shall start moving again when button2 is pressed , regardless of the state of the limit switch?

That could be done like this:

/*
  Forum: https://forum.arduino.cc/t/stepper-motor-cancellation/1213693
  Wokwi: https://wokwi.com/projects/387470045236839425
*/

#include <Stepper.h>

int stepsPerRevolution = 2048;
int motSpeed = 50;
int dt = 500;

const byte button1Pin = 6;
const byte button2Pin = 7;
int motDir = 1;

Stepper myStepper(stepsPerRevolution, 2, 4, 3, 5);

void setup()
{
  Serial.begin(115200);
  myStepper.setSpeed(motSpeed);
  pinMode(button1Pin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);

}

byte runStepper = true;

void loop()
{
  if (digitalRead(button2Pin) == LOW) {
    runStepper = true;
  }
  while (runStepper) {
    myStepper.step(motDir * 1);
    delayMicroseconds(dt);
    if (limitSwitch()) {
      runStepper = false;
    }
  }
}

boolean limitSwitch() {
  static unsigned long lastChange = 0;
  static byte lastState = HIGH;
  static byte state = HIGH;
  byte actState = digitalRead(button1Pin);
  if (actState != lastState) {
    lastChange = millis();
    lastState = actState;
  }
  if (state != actState && millis() - lastChange > 20 ) {
    state = actState;
    Serial.println(state);
    return state;
  }

  return false;

}

see here https://wokwi.com/projects/387470045236839425

After stopping by button1 and restart with button2 you have to move button1 to close and then to open to get a reaction (to stop the stepper).

The function limitSwitch() only returns true on a change from LOW to HIGH.

Yes exactly

Thank you very much for helping me

Will also review it for future projects, thanks again sir

Hello again, I tried to modify the code, i want to have 5 second delay when the button 2 is pressed before the stepper motor runs again but it immediately stops

I added it after the acstates in the code

Post the new code ... That's making things easier.





#include <Stepper.h>

int stepsPerRevolution = 2048;
int motSpeed = 50;
int dt = 500;

const byte button1Pin = 6;
const byte button2Pin = 7;
int motDir = 1;

Stepper myStepper(stepsPerRevolution, 2, 4, 3, 5);

void setup()
{
  Serial.begin(115200);
  myStepper.setSpeed(motSpeed);
  pinMode(button1Pin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);

}

byte runStepper = true;

void loop()
{
  if (digitalRead(button2Pin) == LOW) {
    runStepper = true;
  }
  while (runStepper) {
    myStepper.step(motDir * 1);
    delayMicroseconds(dt);
    if (limitSwitch()) {
      runStepper = false;
    }
  }
}

boolean limitSwitch() {
  static unsigned long lastChange = 0;
  static byte lastState = HIGH;
  static byte state = HIGH;
  byte actState = digitalRead(button1Pin);
  delay(5000);
  if (actState != lastState) {
    lastChange = millis();
    lastState = actState;
  }
  if (state != actState && millis() - lastChange > 20 ) {
    state = actState;
    Serial.println(state);
    return state;
  }

  return false;

}

This is just what I did

That's destroying the functionality of a debouncing routine... :wink:

It's definitely the wrong place to delay an activity. In general the function delay() should be used carefully, if you use delay(5000) the controller cannot handle anything in the meantime (except interrupt driven routines, but that's a different topic).

The right place to make a function work after a certain time has expired is loop() and the use of the millis() function.

What is it what you want to achieve?

Shall the effect of the limitSwitch be delayed and become effective 5 seconds later so that the motor stops 5 seconds after the limit switch was activated?

Or do you want the restart to be delayed for 5 seconds after the limit switch was released?

Ohh my bad my bad😅

Well generally i want to use delay because I want to delay when will the stepper motor to run again, because I plan is to add servo motor

I just thought it's easy for me to add delay to see if my idea is possible but I guess i get the programming wrong

The thing that I want to achieve is to delay the stepper motor to run again

Because generally my idea is that
The servo will move 90 degrees, and then when the button 2 is pressed. It will make the servo to revert back to its original position and the delay to happen

Ps. I'm using servo motor to control a control valve for a hydraulic pump that's why I needed the delay so it can have enough time for the hydraulic boom to retract before running the stepper motor again

That's why I tried using delay first and start from it, only the delay and the servo motor is I want to add for it to be simple

Try this

/*
  Forum: https://forum.arduino.cc/t/stepper-motor-cancellation/1213693
  Wokwi: https://wokwi.com/projects/387900608246250497

*/
#include <Stepper.h>

int stepsPerRevolution = 2048;
int motSpeed = 50;
int dt = 500;

const byte button1Pin = 6;
const byte button2Pin = 7;
int motDir = 1;

enum stateType {RUNNING, STOPPED, WAITTORUN};
stateType state = RUNNING;
const unsigned long waitToRunInterval = 5000;
unsigned long limitSwitchActivateTime = 0;

Stepper myStepper(stepsPerRevolution, 2, 4, 3, 5);

void setup()
{
  Serial.begin(115200);
  Serial.println("Running");
  myStepper.setSpeed(motSpeed);
  pinMode(button1Pin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);
}

void loop()
{
  stateMachine();
}


void stateMachine() {
  switch (state) {
    case RUNNING:
      myStepper.step(motDir * 1);
      delayMicroseconds(dt);
      if (limitSwitch()) {
        limitSwitchActivateTime = millis();
        state = STOPPED;
        Serial.println("Stopped");
      }
      break;
    case STOPPED:
      if (digitalRead(button2Pin) == LOW) {
        state = WAITTORUN;
        Serial.println("Start again if delay time is expired");
      }
      break;
    case WAITTORUN:
      if (millis()-limitSwitchActivateTime >= waitToRunInterval){
         state = RUNNING;
      }
      break;
  }
}


boolean limitSwitch() {
  static unsigned long lastChange = 0;
  static byte lastState = HIGH;
  static byte state = HIGH;
  byte actState = digitalRead(button1Pin);
  if (actState != lastState) {
    lastChange = millis();
    lastState = actState;
  }
  if (state != actState && millis() - lastChange > 20 ) {
    state = actState;
    return state;
  }

  return false;

}

Wokwi:

Your idea is a good application for a small state machine ... :wink:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.