Stepper motor rotate on switch and rotate once after switch is released

Hello all,

im new to arduino, just picked up a super kit from elegoo and trying to wrap my head around it.

basically im not sure how to call the stepper to rotate one full rotation after switch is released. i made a ghetto way of accomplishing it with on trigger, to rotate the stpper 2 full rotations so if its released, it continues around but i know theres a better way. i think i have to record state changes? not sure.

but heres what i got so far. dont laugh. lol

#include <Stepper.h>

#define STEPS 2048
const int stepsPerRevolution = 2048;
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11);
const int buttonPinBlue = 2;

void setup() {

myStepper.setSpeed(10);
}

void stepp() {

myStepper.step(1);

pinMode(buttonPinBlue, INPUT);
}

void loop() {

if (digitalRead(buttonPinBlue) == HIGH) {

Serial.print(“pin is high”);

Serial.println(“clockwise”);
myStepper.step(4096);
delay(10);
}

}

Use the state change detection method to detect the on to off transition (or off to on).

Put the pinMode in setup(). The more accepted way to wire a switch is to wire one side to ground and the other to an input set to pinMode INPUT_PULLUP. The switch will be HIGH when not pressed and LOW when pressed.

joewagner:
basically im not sure how to call the stepper to rotate one full rotation after switch is released.

You have not told us what is to happen when the switch is pressed.

The usual way to tell if a switch is released is to check when it changes from pressed to not pressed - something like this

previousSwitchState = newSwitchState;
newSwitchState = digitalRead(switchPin);
if ( newSwitchState == HIGH and previousSwitchState == LOW) { // assumes LOW when pressed
  // switch has just been released
}

...R

oh sorry. i want the stepper to continue to rotate while button is pressed. and then when the switch is released it does another full rotation. it will then wait for the switch to be pressed again. basically a small conveyor belt.

previousSwitchState = newSwitchState;
newSwitchState = digitalRead(switchPin);
if ( newSwitchState == HIGH and previousSwitchState == LOW) { // assumes LOW when pressed
  // switch has just been released
}


im getting newswitchstate does not name a type....

Robin2's solution was a snippet; you would need to declare the variable newSwitchState as any other.

thank you sooo much. like i said i just got this yesterday for a project im doing. greatly appreciated.
this is my code so far and its working.

#include <Stepper.h>

#define STEPS 2048
const int stepsPerRevolution = 2048;
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11);
const int buttonPinBlue = 2;
int previousSwitchState = 0;
int newSwitchState = 0;

void setup() {

myStepper.setSpeed(10);
}

void stepp() {

myStepper.step(1);

pinMode(buttonPinBlue, INPUT);
}

void loop() {

if (digitalRead(buttonPinBlue) == HIGH) {

Serial.print(“pin is high”);

Serial.println(“clockwise”);
myStepper.step(1);

}
previousSwitchState = newSwitchState;
newSwitchState = digitalRead(buttonPinBlue);

if ( newSwitchState == LOW and previousSwitchState == HIGH) { // assumes LOW when pressed
// switch has just been released
myStepper.step(4096);

}
}

joewagner:
i just got this yesterday for a project im doing.

Kudos on your progress...

jubukraa:
Kudos on your progress...

thanks

odd thing i noticed. with the above code. i got it to rotate on button press. and rotate twice when button is released. but it appears that if you dont hold the button down before 2nd rotation it only completes 2 rotations.

so my motor does a rotation of 2048 steps. the code says upon release of the button rotate twice (4096)

if i hold down the button for 4095 steps and release it. it only rotates 1 step to complete the 4096

hope that makes sense. wondering if theres a way around it.

Referring to Reply #9

I think the problem is that the line

myStepper.step(4096);

does all 4096 steps before the Arduino can check anything else - in other words it blocks the Arduino until the whole move is complete and therefore it cannot read the switch.

It will be easier to help if you put your code into code tags using the code button </> so that I can easily copy it to my text editor for study.

…R

sorry about that. this is the latest code that i put together.

so to recap i want the relay to trigger and the stepper to rotate while holding down the button. on release, i want the relay to stay on and the stpper to rotate fully twice, then turn off and relay off. it works great but if the stepper doesnt rotate past two full rotations before you release the button it just completes up to 2 full rotations. hope that makes sense.

i tried putting the switch change above the continual press to no avail.

#include <Stepper.h>
#define STEPS 2048
const int stepsPerRevolution = 2048;
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11);
const int  buttonPinBlue = 2;
int previousSwitchState = 0;
int newSwitchState = 0;
const int relay = 3;
int relayState = 0;






void setup() {
  
  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);
  myStepper.setSpeed(17);
 
}

void stepp() {

 myStepper.step(1);

  pinMode(buttonPinBlue, INPUT);
}

void loop() {

{
  previousSwitchState = newSwitchState;
  newSwitchState = digitalRead(buttonPinBlue);

if ( newSwitchState == LOW and previousSwitchState == HIGH) { // assumes LOW when pressed
  // switch has just been released
  myStepper.step(4096);
  digitalWrite(8,LOW);
  digitalWrite(10,LOW);
  digitalWrite(9,LOW);
  digitalWrite(11,LOW); 
  digitalWrite(relay, HIGH);
}
delay(1);
}
if (digitalRead(buttonPinBlue) == HIGH) {

  Serial.print("pin is high");

   Serial.println("clockwise");
  myStepper.step(1);
digitalWrite(relay, LOW);
  }

}

I think you need something more like the following code

It checks for when the button is first pressed and it also works as long as the button is pressed without using a blocking WHILE and without blocking the Arduino with the stepper movement. This allows it to detect the button being released after every step. I may not have the delayMicroseconds() value correct for your stepper speed.

Then there is other stuff that only happens when the button is released.

void loop() {

    static int stepCount = 0;

    previousSwitchState = newSwitchState;
    newSwitchState = digitalRead(buttonPinBlue);

    if ( newSwitchState == LOW) { // assumes LOW when pressed
        if (previousSwitchState == HIGH) { // switch has just been pressed
            stepCount = 0;
        }
        if (stepCount < 2048) {
            myStepper.step(1);
            delayMicroseconds(1700);
            stepCount ++;
        }
    }

    if (newSwitchState == HIGH and previousSwitchState == LOW) { // switch has been released

        digitalWrite(8,LOW);
        digitalWrite(10,LOW);
        digitalWrite(9,LOW);
        digitalWrite(11,LOW); 
        digitalWrite(relay, HIGH);
        
        // not sure what other stuff should happen here
    }
}

…R

On further thinking I suspect I should not have included the step counting as you probably want the motor to rotate indefinitely while the button is pressed. In other words, much simpler like this

   if ( newSwitchState == LOW) { // assumes LOW when pressed
            myStepper.step(1);
            delayMicroseconds(1700);
    }

...R

thanks that worked!!

i changed it to “delayMicroseconds(1);” as it changed the RPMs noticeably. any reason why that change could cause a problem with the stepper? dont want to cook it early over a simple setting like that.

joewagner:
i changed it to "delayMicroseconds(1);" as it changed the RPMs noticeably. any reason why that change could cause a problem with the stepper? dont want to cook it early over a simple setting like that.

You need to post your program so we can see exactly what you have. Also provide details of how it was before you changed to delayMicroseconds()

...R

#include <Stepper.h>
#define STEPS 2048
const int stepsPerRevolution = 2048;
Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11);
const int  buttonPinBlue = 2;
int previousSwitchState = 0;
int newSwitchState = 0;
const int relay = 3;
int relayState = 0;






void setup() {
 
  pinMode(relay, OUTPUT);
  digitalWrite(relay, HIGH);
  myStepper.setSpeed(17);
 
}

void stepp() {

 myStepper.step(1);

  pinMode(buttonPinBlue, INPUT);
}

void loop() {

{
  previousSwitchState = newSwitchState;
  newSwitchState = digitalRead(buttonPinBlue);

if ( newSwitchState == LOW and previousSwitchState == HIGH) { // assumes LOW when pressed
  // switch has just been released
  myStepper.step(4096);
  digitalWrite(8,LOW);
  digitalWrite(10,LOW);
  digitalWrite(9,LOW);
  digitalWrite(11,LOW);
  digitalWrite(relay, HIGH);
}
delay(1);
}
if (digitalRead(buttonPinBlue) == HIGH) {

  Serial.print("pin is high");

   Serial.println("clockwise");
  myStepper.step(1);
  delayMicroseconds(1);
digitalWrite(relay, LOW);
  }
}

4th line from bottom.

This does not make sense

    if ( newSwitchState == LOW and previousSwitchState == HIGH) { // assumes LOW when pressed
        // switch has just been released

If the switch produces a LOW when pressed then this code detects when it is first pressed, not when it is released.

If you have wired the switch the other way then change the comments to match.

I can't see the point of a 1 micro-second delay. The time between steps is determined by how long it takes loop() to repeat. Adding a 1 microsec delay is not going to be noticeable. How many steps per second do you want to achieve?

Don't read the pin a second time like this

   if (digitalRead(buttonPinBlue) == HIGH) {

you already have a value in newSwitchState so use that. If you read the pin a second time you may get a different value which will confuse the logic.

...R