Stepper control with multiple momentary toggles

Hi all, I rarely post on forums so hopefully I'm following all of the rules. I could use some advice on a project. I've read several forum posts and blogs trying to implement what is seemingly simple, and have tried many different methods, but I think that my programming chops just aren't up to par. I'm not looking for a hand hold, just a point in the right direction.

Essentially, I'm looking to control the speed of a NEMA 17 stepper motor, with the TB6600 controller with a potentiometer. Then also toggle On/Off, Direction, and Enable with momentary switches acting as toggles. Ideally, I want the motor to turn indefinitely until there is user input.

The different implementations of using a momentary switch as a toggle, either by using millis or by using something like state=!state don't seem to work, because when they are inserted into the main loop, it's getting thrown off by the indefinite loop that is turning the motor. If I insert code into the loop that is turning the motor, it goes by so fast that it's not catching my button presses. Occasionally I can get one of the buttons to work, until the iteration repeats and resets.

Do I need to be using switch cases and programming every different possibility of button combinations then breaking out of each loop? It seems like a waste of code to me. Should I be looking at libraries instead? To me, logically, the DIR and ENA states should be variables, but I have no way of changing them while the motor iterates. Am I asking too much from an Arduino UNO? Anyways, you guys are the experts, just looking for ideas on the most efficient way to implement this. Thanks for any ideas that you have!

Here is my base code which I've been modifying and trying different things (please don't burn me). You won't see the button toggle code in here, simply because every method I've tried hasn't worked. The speed controller works fine.

int PUL=7; //define Pulse pin 
int DIR=6; //define Direction pin 
int ENA=5; //define Enable Pin
int customDelay,customDelayMapped; // Defines speed variables
int buttonOnOff=8; //On Off toggle
int buttonDir=4; //direction toggle
int buttonEna=3; //enable toggle

void setup() { 
    pinMode (PUL, OUTPUT); 
    pinMode (DIR, OUTPUT); 
    pinMode (ENA, OUTPUT);
    pinMode (buttonOnOff, INPUT_PULLUP);
    pinMode (buttonDir, INPUT_PULLUP);
    pinMode (buttonEna, INPUT_PULLUP);
    digitalWrite(ENA,HIGH); //Disable ENA on startup
    } 

//variable for speed control via potentiometer
int speedUp() {  
        int customDelay = analogRead(A0); // Reads the potentiometer 
        int newCustom = map(customDelay, 0, 1023, 10 ,1000);
        return newCustom;
    }

void loop() { 
    for (int i=0; i<1600; i++) //sets motor steps
    { 
      digitalWrite(ENA,LOW);
      digitalWrite(DIR,LOW);
      customDelayMapped = speedUp();
      digitalWrite(PUL,HIGH);
      delayMicroseconds(customDelayMapped);
      digitalWrite(PUL,LOW);
      delayMicroseconds(customDelayMapped);
     }
}

Your code looks quite okey. Create a button checking function. Call this function at the beginning of loop().
F ex read_dir_button(), read_go_button() and they should return a code You choose. Do the for_loop if read_go_button is true... Use the read_dir_button value for direction.

Thank you for the advice! In this example I've created the onOff button toggle function, and call it at the beginning of the loop. It works fantastically to start up the stepper motor. The problem is that I can't toggle it off until I push the button at just the right time. I'm assuming because it's outside of the for loop. Logically I need a way to have it check the button state while it's in the for loop, then break out to the else function to complete the toggle. I hope this makes sense.

int PUL=7; //define Pulse pin 
int DIR=6; //define Direction pin 
int ENA=5; //define Enable Pin
int customDelay,customDelayMapped; // Defines speed variables
int buttonOnOff=8; //On Off toggle
int buttonDir=4; //direction toggle
int buttonEna=3; //enable toggle
boolean on=false;
int onState = 0;

void setup() { 
    pinMode (PUL, OUTPUT); 
    pinMode (DIR, OUTPUT); 
    pinMode (ENA, OUTPUT);
    pinMode (buttonOnOff, INPUT_PULLUP);
    pinMode (buttonDir, INPUT_PULLUP);
    pinMode (buttonEna, INPUT_PULLUP);
    digitalWrite(ENA,HIGH); //Disable ENA on startup
    } 

//variable for speed control via potentiometer
int speedUp() {  
        int customDelay = analogRead(A0); // Reads the potentiometer 
        int newCustom = map(customDelay, 0, 1023, 10 ,1000);
        return newCustom;
    }
void onOff (){
     onState = digitalRead(buttonOnOff);
    if (onState == HIGH) {
        if (on==true){
            on = false;
        } else {
            on = true;
        }
    }
}
    
void loop() {  
    onOff();     
    for (int i=0; i<1600; i++);
     if (on==true){
      digitalWrite(ENA,LOW);
      digitalWrite(DIR,LOW);
      customDelayMapped = speedUp();
      digitalWrite(PUL,HIGH);
      delayMicroseconds(customDelayMapped);
      digitalWrite(PUL,LOW);
      delayMicroseconds(customDelayMapped);
     } else {
        
        digitalWrite(ENA,HIGH);
    }
}

Rather than doing all the stepper moves in a FOR loop just do them one step at a time and use a variable keep count. That way the buttons can be tested between every step.

...R

Thanks R! That idea works pretty good. I have a little bit of debouncing to do, but it's fairly responsive to on/off.

I added the "count" variable and did away with the for loop.

The only thing I'm still scratching my head about is that it stops stepping after a certain number of iterations. I don't think it's because of bouncing, I think it's something in my code. If I turn on the stepper, ideally I'd like it to run infinitely until I tell it to stop with the toggle. Does it have to do with the way I'm iterating the count int?

int count = 1600

void loop() {  
    onOff();     
    if (on==true && count<1600){
      digitalWrite(ENA,LOW);
      digitalWrite(DIR,LOW);
      customDelayMapped = speedUp();
      digitalWrite(PUL,HIGH);
      delayMicroseconds(customDelayMapped);
      digitalWrite(PUL,LOW);
      delayMicroseconds(customDelayMapped);
     } 
    count++;
    }
}

What is the significance of the 1600 count?

What is supposed to happen when it gets to 1600?

...R

Oh my gosh, thanks for asking that. I now see the error in my ways. I thought I was using it previously in my for loop, for micro stepping. Being that I don't care about the number of steps, I got rid of the count int altogether and everything works fantastically. Thanks so much for straightening me out everyone!