Newbie can't get stepper to stop

Howdy. Newbie here, so pardon my inexperience.

I'm driving a stepper motor w/ an EasyDriver and I've got the interface working decently. Everything's talking, but I have some programming issues.

I've got it hooked to a potentiometer that controls the speed (through microstepping) of the motor, and a momentary switch that determines the direction the motor spins.

What I'd like to do is push the button and have the motor turn a predetermined number of steps and STOP. Then, release the button, turn a predetermined number of steps in the other direction and STOP.

Right now, it moves those steps, pauses, then moves again ad infinitum until I press or release the button.

How do I make it just move where I want and hold?

Here's the sketch:

const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin

int buttonState = 0; // variable for reading the pushbutton status
int dirpin = 3; // the number of stepper direction pin
int steppin = 12; // the number of stepper input
int sensorPin = 0; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
int i;

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

pinMode(ledPin, OUTPUT); // initialize the LED pin as an output
pinMode(buttonPin, INPUT); // initialize the pushbutton pin as an input
pinMode(dirpin, OUTPUT); // initialize stepper direction pin as output
pinMode(steppin, OUTPUT); // initialize stepper drive pin as output
}

void loop(){
buttonState = digitalRead(buttonPin); // read the state of the pushbutton value:
if (buttonState == LOW) { // check if the pushbutton is pressed.
// if it is, the buttonState is LOW
digitalWrite(ledPin, HIGH); // turn LED on
sensorValue = analogRead(sensorPin);
digitalWrite(dirpin, LOW); // Sets the direction.
delay(1); // smooths transition

Serial.println(">>");
for (i = 0; i<600; i++) // Iterate for 600 microsteps.
{
digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the
digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step.
delayMicroseconds(sensorValue); // Sets the speed based on pot setting
}
}
else {
sensorValue = analogRead(sensorPin);
digitalWrite(ledPin, LOW); // turn LED off
digitalWrite(dirpin, HIGH); // Change direction.
delay(1);

Serial.println("<<");
for (i = 0; i<600; i++) // Iterate for 600 microsteps
{
digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the
digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step.
delayMicroseconds(sensorValue); // Sets the speed based on pot setting
}
}
}

The problem is not with the code you have, but with code you don't have. You do one thing if the button is pressed, and something else if it isn't.

What you want to do is something if the button is pressed AND IT WASN"T PRESSED BEFORE, and something else if the button is not pressed AND IT WAS BEFORE.

So, you need to have a buttonState and oldButtonState variables.

Each time through loop, read the buttonState. If it is not the same as oldButtonState, do something, based on whether buttonState is HIGH or LOW, and then set oldButtonState to buttonState.

Initialize buttonState and oldButtonState to LOW (button was not pressed last time.

When loop starts, the states are the same, so nothing happens. Press the button. The states are no longer the same. Make the states the same again. Do something. Loop ends.

Loop runs again, sees that the button states are the same, so nothing happens.

Release the button. Loop runs, and sees that the states are not the same. Make them the same, and do something.

Thanks for getting back to me.

The logic of that makes a lot of sense. I'll see if I can actually code it. One question though, If you notice in the code, I have designated that the buttonState is LOW when the button is pressed. This is because, I think, the momentary switch I have is a normally open switch so the current is broken when the button is pressed.

Is that accounted for in your explanation when you say to "Initialize buttonState and oldButtonState to LOW"? Or would I set that as HIGH?

Thanks so much.

In a normally open switch, the connection is closed (made) when the button is pushed, and current flow. Depending on how the button is wired to the Arduino, that could make the pin go HIGH, if current then flows to the pin, or LOW, if current goes somewhere else, instead.

I wire switches so that current flows to the pin when the button is pressed. Conceptually, that's easy for me to understand.

Which ever state the pin is in when the button is not pressed is what you should initialize the global state variables to.

You're right. I actually meant to type "normally closed" but sometimes my brain and my fingers don't get along so well.

Thanks.

but sometimes my brain and my fingers don't get along so well

I know that feeling.

Alright, a little progress. When I press the button, it spins the right number of steps, then immediately starts spinning the other direction. It will spin that direction in infinite loops (even after I release the button) until I press it again.

I'm guessing there's something missing in the "else" portion of the equation.

I really, really appreciate the help.

The sketch:

const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin

int buttonState = HIGH; // variable for reading the pushbutton status
int oldbuttonState = HIGH;
int dirpin = 3; // the number of stepper direction pin
int steppin = 12; // the number of stepper input
int sensorPin = 0; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
int i;

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

pinMode(ledPin, OUTPUT); // initialize the LED pin as an output
pinMode(buttonPin, INPUT); // initialize the pushbutton pin as an input
pinMode(dirpin, OUTPUT); // initialize stepper direction pin as output
pinMode(steppin, OUTPUT); // initialize stepper drive pin as output
}

void loop(){
buttonState = digitalRead(buttonPin); // read the state of the pushbutton value:
if (buttonState != oldbuttonState) // check if the pushbutton is pressed.
{
// if it is, the buttonState is LOW
digitalWrite(ledPin, HIGH); // turn LED on
sensorValue = analogRead(sensorPin);
digitalWrite(dirpin, LOW); // Sets the direction.
delay(1); // smooths transition

Serial.println(">>");
for (i = 0; i<4000; i++) // Iterate for 600 microsteps.
{
digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the
digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step.
delayMicroseconds(sensorValue); // Sets the speed based on pot setting
}
oldbuttonState = buttonState;
}
else {
sensorValue = analogRead(sensorPin);
digitalWrite(ledPin, LOW); // turn LED off
digitalWrite(dirpin, HIGH); // Change direction.
delay(1);

Serial.println("<<");
for (i = 0; i<4000; i++) // Iterate for 600 microsteps
{
digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the
digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step.
delayMicroseconds(sensorValue); // Sets the speed based on pot setting
}
}
}

Move the "oldButtonState = buttonState;" line outside the if/else block. Basically, what you want to do is set the oldButtonState each time through the loop, so that you detect changes.

Getting closer. I moved the line to the end of the loop.

It spins counterclockwise over and over until I press the button. Then is spins clockwise one cycle, then switches back to counterclockwise infinitely.

If I release the button, it does the same. Clockwise one cycle, then back to counterclockwise over and over.

Somehow I've lost the directional control via the button.

You need two if tests:

if(buttonState != oldButtonState)
{
   if(buttonState == HIGH)
   {
       // Do the HIGH thing
   }
   else
   {
       // Do the LOW thing
   }
   oldButtonState = buttonState;
}

Sorry for the confusion.

Hooray! It works.

You're the best, man. Next time you're in Houston the beer is on me.

I don't know if you're still watching this thread or not, but...

I got everything to work beautifully and decided I needed to complicate the matter. What I'm trying to do now is make a "go" button.

Basically, I want to be able to set a toggle switch to run the motor either forward or backward. But I don't want it to actually move yet. Then, when the time is right, hit a momentary switch to make the motor actually go in the specified direction.

I tried to program this using your advice about buttonState and oldbuttonState which works well for the toggle. Right now, though, when I push the button to make it run, nothing happens.

What's wrong with my code?

const int togglePin = 2; // the number of the toggle pin
const int ledPin = 13; // the number of the LED pin
const int buttonPin = 8; // the number of the pushbutton pin

int buttonState = LOW; // variable for reading the pushbutton status
int oldbuttonState = LOW;
int toggleState = HIGH; // variable for reading the toggle status
int oldtoggleState = HIGH;
int dirpin = 3; // the number of stepper direction pin
int steppin = 12; // the number of stepper input
int sensorPin = 0; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
int i;

void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT); // initialize the pushbutton as an input
pinMode(ledPin, OUTPUT); // initialize the LED pin as an output
pinMode(togglePin, INPUT); // initialize the toggle pin as an input
pinMode(dirpin, OUTPUT); // initialize stepper direction pin as output
pinMode(steppin, OUTPUT); // initialize stepper drive pin as output
}

void loop(){
buttonState = digitalRead(buttonPin); // reads the state of the pushbutton value
if (buttonState != oldbuttonState) // check if the button is pressed
{
if (buttonState == HIGH) // if it is, buttonState is HIGH
{
toggleState = digitalRead(togglePin); // read the state of the toggle value:
if (toggleState != oldtoggleState) // check if the toggle is pressed.
{
if(toggleState == LOW)
{ // if it is, the toggleState is LOW
digitalWrite(ledPin, HIGH); // turn LED on
sensorValue = analogRead(sensorPin); // read state of pot
digitalWrite(dirpin, LOW); // Sets the direction.
delay(1); // smooths transition

Serial.println(">>");
for (i = 0; i<4000; i++) // Iterate for 4000 microsteps.
{
digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the
digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step.
delayMicroseconds(sensorValue); // Sets the speed based on pot setting
}
}
else { // if toggle is off
sensorValue = analogRead(sensorPin); // read state of pot
digitalWrite(ledPin, LOW); // turn LED off
digitalWrite(dirpin, HIGH); // Change direction.
delay(1);

Serial.println("<<");
for (i = 0; i<4000; i++) // Iterate for 4000 microsteps
{
digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the
digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step.
delayMicroseconds(sensorValue); // Sets the speed based on pot setting
}
}
oldtoggleState = toggleState; // change toggle state back to equal
}
}
oldbuttonState = buttonState; // change button state back to equal
}
}

What do you have as a physical device attached to togglePin and buttonPin?

I presume that one of them, at least is a momentary contact, single pole, single throw, normally open switch. Are they both?

If so, then you need to check for button presses completely independently:

int toggleState = LOW;
int buttonState = LOW;

int oldToggleState = LOW;
int oldButtonState = LOW;

int goForward = 0;

void loop()
{
// See if toggle button was pressed
toggleState = digitalRead(togglePin);
if(toggleState == HIGH)
{
// See if state is same as previous state.
// If so, button was held or never pushed
if(toggleState != oldToggleState) // toggle changed
{
if(goForward == 0)
goForward = 1;
else
goForward = 0;
}
oldToggleState = toggleState;
}

// Then, see if button (go) was pressed. If it was, the
// direction to go is to be based on goForward
}

Thanks for all your help, man. I discovered that I had actually written a working sketch. The problem was that pin 8 on my Arduino isn't working. I plugged it in to another pin and voila!

I also discovered that pin 7 is bad. Is that common? I can live without those pins, but if there's a fix I wouldn't mind knowing it.

All my pins, on all 4 of my Arduinos, still work. So, I guess it is not a common problem. It's likely that you have, at one time or another, overloaded, current-wise, the damaged pin(s).

Yeah, that sounds like something I'd do.