Stepper with push buttons speed control

Hi All,

First post here, I'm an Arduino beginner and would love to get some helping hand.

My project is a simple telescope mount control (1 axis motor). I found a nice code on the web that does micro-stepping with a similar setup to mine - here is the link:

The code works nicely and i'm using the quarter step portion of the code to step the motor (it provides Full, Half, and several micro-stepping options).

I tried adding some code to control the speed of the motor by 2 push buttons and display the speed on a 4 digit display.

The problem - while my code works perfectly alone, once I comment-in the function to tun the motor, the buttons stops responding..

Here is the full sketch i'm using after cleaning up the portions of stepping I don't use:

#include <TM1637Display.h>

// Module connection pins (Digital Pins)
#define CLK 7
#define DIO 6

int A = 8;
int B = 9;
int C = 10;
int D = 11;
long duty = 50;

int waitMicroSeconds = 279.052328; // Actual calculated is 279052.328;
int pulseCount = 1000;

int pinButtonL = 2;
int pinButtonR = 3;
int stateMotorSpeed = waitMicroSeconds;
int stateButtonL;
int stateButtonR;

long time = 0;
long debounce = 200;

// Create display object of type TM1637Display:
TM1637Display display(CLK, DIO);

void setup() {  

 pinMode(pinButtonL, INPUT_PULLUP);
 pinMode(pinButtonR, INPUT_PULLUP);
  
  pinMode(A, OUTPUT);     
  pinMode(B, OUTPUT);     
  pinMode(C, OUTPUT);     
  pinMode(D, OUTPUT);    
}

void one(){
  digitalWrite(A, HIGH);   
  digitalWrite(B, LOW);   
  digitalWrite(C, HIGH);   
  digitalWrite(D, LOW);   
}

void two(){
  digitalWrite(A, HIGH);   
  digitalWrite(B, LOW);   
  digitalWrite(C, LOW);   
  digitalWrite(D, HIGH);   
}

void three(){
  digitalWrite(A, LOW);   
  digitalWrite(B, HIGH);   
  digitalWrite(C, LOW);   
  digitalWrite(D, HIGH);   
}

void four(){
  digitalWrite(A, LOW);   
  digitalWrite(B, HIGH);   
  digitalWrite(C, HIGH);   
  digitalWrite(D, LOW);   
}

void oneB(){
  digitalWrite(A, HIGH);   
  digitalWrite(B, LOW);   
  digitalWrite(C, LOW);   
  digitalWrite(D, LOW);   
}

void twoB(){
  digitalWrite(A, LOW);   
  digitalWrite(B, LOW);   
  digitalWrite(C, LOW);   
  digitalWrite(D, HIGH);   
}

void threeB(){
  digitalWrite(A, LOW);   
  digitalWrite(B, HIGH);   
  digitalWrite(C, LOW);   
  digitalWrite(D, LOW);   
}

void fourB(){
  digitalWrite(A, LOW);   
  digitalWrite(B, LOW);   
  digitalWrite(C, HIGH);   
  digitalWrite(D, LOW);   
}

// main routine to microstep
void doStep(int st){
  
  long dt1 = waitMicroSeconds * duty / 100;
  long dt2 = waitMicroSeconds * (100-duty) / 100;

  for (int j = 0; j < pulseCount; j++){
    switch (st){
    case 1: one();break;
    case 2: two();break;
    case 3: three();break;
    case 4: four();break;
    case 11: oneB();break;
    case 12: twoB();break;
    case 13: threeB();break;
    case 14: fourB();break;

    case 21: one();break;
    case 22: two();break;
    case 23: three();break;
    case 24: four();break;
    case 31: oneB();break;
    case 32: twoB();break;
    case 33: threeB();break;
    case 34: fourB();break;

    }

    delayMicroseconds(dt1);

    switch (st){
    case 1: one();break;
    case 2: two();break;
    case 3: three();break;
    case 4: four();break;
    case 11: oneB();break;
    case 12: twoB();break;
    case 13: threeB();break;
    case 14: fourB();break;

    case 21: oneB();break;
    case 22: twoB();break;
    case 23: threeB();break;
    case 24: fourB();break;
    case 31: two();break;
    case 32: three();break;
    case 33: four();break;
    case 34: one();break;
    }
    delayMicroseconds(dt2);   
  }
}

// disable motor

void motorOff(){
  /* Important note:
       Turning off the motor will make it go into a 'rest' state. 
       When using microsteps (or even full steps), this may not be the last active step. 
       So using this routine may change the position of the motor a bit.
  */
  
  digitalWrite(A, LOW);   
  digitalWrite(B, LOW);   
  digitalWrite(C, LOW);   
  digitalWrite(D, LOW);   
}

// microstepping 16 steps :
void do16Steps(int cnt, boolean forwards){

  const int list[] = {1,21,11,31,2,22,12,32,3,23,13,33,4,24,14,34};
  for (int i = 0; i < cnt; i++){
    duty = 50;
    if (forwards)
      {for (int j = 0; j <= 15; j++){doStep(list[j]);}}
    else
      {for (int j = 15; j >= 0; j--){doStep(list[j]);}}
  }  
}
  
void loop() {
 
 // Set the display brightness (0-7):
 display.setBrightness(0);
 
 // uncomment this to disable motor  
//  motorOff();return;

/* control the speed of the motor with a waitMicroseconds/pulseCount pair
   e.g. waitMicroSeconds / pulseCount
        500 / 5 --> one step takes 2500 microseconds
        50 / 50 --> one step also takes 2500 microseconds
        but in second pair the fequency of the wave is 20kHz, not audible..
        in 500 / 5 you may hear a high tone in the motor in microsteps  
        some motors may not respond well on higher frequencies 
   note: these parameters also control speed in normal stepping (full or half) although there's no pulses in those cases, 
            setting pulseCount = 1 might be more readable
*/
  waitMicroSeconds -= stateMotorSpeed; // Actual calculated is 279052.328
  waitMicroSeconds = (waitMicroSeconds < 0)? 0 : waitMicroSeconds;
  pulseCount = 1000;      // (gear ratio is 3.44:1)


  

 //Button L procedure
  stateButtonL = digitalRead(pinButtonL);    
  if(stateButtonL == LOW  && millis() - time > debounce) 
  {
    stateMotorSpeed = stateMotorSpeed-10;  
    time = millis();
  }

 //Button R procedure
  stateButtonR = digitalRead(pinButtonR);    
  if(stateButtonR == LOW  && millis() - time > debounce)
  {
    stateMotorSpeed = stateMotorSpeed+10;  
    time = millis();
  }

  
     int motorspeeddisplay = stateMotorSpeed*10;
    display.showNumberDec(motorspeeddisplay, false, 4, 0);

/*     
  two parameters:
    1. number of steps
    2. forwards = true --> move forwards   /  forwards = false --> move backwards
    
  note: there's no speed correction for different modes, so do4Steps makes the motor go twice as fast as do8Steps and so on... 
        use waitMicroseconds and pulseCount to adapt speed when changing modes   
*/

//  do16Steps(24, true);//Anti-Clockwise
 do16Steps(24, false);//Clokwise

//   motorOff(); // give it a rest (see note in motorOff about losing steps)
 // delay(1000);

}

So, when I comment out this:

do16Steps(24, false);//Clokwise

The speed control is great, but together it doesn't respond. I initially thought its a timing issue as I don't really understand how the waitMicroSeconds + Pulse combo works and if it affects the loop digitalread somehow.

Any help to steer me in the right direction will be highly appreciated.

Thanks!

Sorry I've pasted the wrong code of one of the tries to debug...:frowning:

Here is the correct one:

#include <TM1637Display.h>

// Module connection pins (Digital Pins)
#define CLK 7
#define DIO 6


int A = 8;
int B = 9;
int C = 10;
int D = 11;
long duty = 50;

int waitMicroSeconds = 279.052328; // Actual calculated is 279052.328;
int pulseCount = 1000;

int pinButtonL = 2;
int pinButtonR = 3;
int stateMotorSpeed = waitMicroSeconds;
int stateButtonL;
int stateButtonR;

long time = 0;
long debounce = 200;

// Create display object of type TM1637Display:
TM1637Display display(CLK, DIO);

void setup() {  

 pinMode(pinButtonL, INPUT_PULLUP);
 pinMode(pinButtonR, INPUT_PULLUP);
  
  pinMode(A, OUTPUT);     
  pinMode(B, OUTPUT);     
  pinMode(C, OUTPUT);     
  pinMode(D, OUTPUT);
    
  
}

void one(){
  digitalWrite(A, HIGH);   
  digitalWrite(B, LOW);   
  digitalWrite(C, HIGH);   
  digitalWrite(D, LOW);   
}

void two(){
  digitalWrite(A, HIGH);   
  digitalWrite(B, LOW);   
  digitalWrite(C, LOW);   
  digitalWrite(D, HIGH);   
}

void three(){
  digitalWrite(A, LOW);   
  digitalWrite(B, HIGH);   
  digitalWrite(C, LOW);   
  digitalWrite(D, HIGH);   
}

void four(){
  digitalWrite(A, LOW);   
  digitalWrite(B, HIGH);   
  digitalWrite(C, HIGH);   
  digitalWrite(D, LOW);   
}


void oneB(){
  digitalWrite(A, HIGH);   
  digitalWrite(B, LOW);   
  digitalWrite(C, LOW);   
  digitalWrite(D, LOW);   
}

void twoB(){
  digitalWrite(A, LOW);   
  digitalWrite(B, LOW);   
  digitalWrite(C, LOW);   
  digitalWrite(D, HIGH);   
}

void threeB(){
  digitalWrite(A, LOW);   
  digitalWrite(B, HIGH);   
  digitalWrite(C, LOW);   
  digitalWrite(D, LOW);   
}

void fourB(){
  digitalWrite(A, LOW);   
  digitalWrite(B, LOW);   
  digitalWrite(C, HIGH);   
  digitalWrite(D, LOW);   
}


// main routine to microstep
void doStep(int st){
  
  long dt1 = waitMicroSeconds * duty / 100;
  long dt2 = waitMicroSeconds * (100-duty) / 100;

  for (int j = 0; j < pulseCount; j++){
    switch (st){
    case 1: one();break;
    case 2: two();break;
    case 3: three();break;
    case 4: four();break;
    case 11: oneB();break;
    case 12: twoB();break;
    case 13: threeB();break;
    case 14: fourB();break;

    case 21: one();break;
    case 22: two();break;
    case 23: three();break;
    case 24: four();break;
    case 31: oneB();break;
    case 32: twoB();break;
    case 33: threeB();break;
    case 34: fourB();break;

    }

    delayMicroseconds(dt1);

    switch (st){
    case 1: one();break;
    case 2: two();break;
    case 3: three();break;
    case 4: four();break;
    case 11: oneB();break;
    case 12: twoB();break;
    case 13: threeB();break;
    case 14: fourB();break;

    case 21: oneB();break;
    case 22: twoB();break;
    case 23: threeB();break;
    case 24: fourB();break;
    case 31: two();break;
    case 32: three();break;
    case 33: four();break;
    case 34: one();break;
    }
    delayMicroseconds(dt2);
    
  }
}

// disable motor

void motorOff(){
  /* Important note:
       Turning off the motor will make it go into a 'rest' state. 
       When using microsteps (or even full steps), this may not be the last active step. 
       So using this routine may change the position of the motor a bit.
  */
  
  digitalWrite(A, LOW);   
  digitalWrite(B, LOW);   
  digitalWrite(C, LOW);   
  digitalWrite(D, LOW);   
}

// full stepping 4 steps :
void do4Steps(int cnt, boolean forwards){
  for (int i = 0; i < cnt; i++){
    duty = 50;
    if (forwards)
      {for (int j = 1; j <= 4; j++){doStep(j);}}
    else
      {for (int j = 4; j >= 1; j--){doStep(j);}}

  }
}

// half stepping 8 steps :
void do8Steps(int cnt, boolean forwards){
  const int list[] = {1,11,2,12,3,13,4,14};
  for (int i = 0; i < cnt; i++){
    duty = 50;
    if (forwards)
      {for (int j = 0; j <= 7; j++){doStep(list[j]);}}
    else
      {for (int j = 7; j >= 0; j--){doStep(list[j]);}}
  }
}


// microstepping 16 steps :
void do16Steps(int cnt, boolean forwards){

  const int list[] = {1,21,11,31,2,22,12,32,3,23,13,33,4,24,14,34};
  for (int i = 0; i < cnt; i++){
    duty = 50;
    if (forwards)
      {for (int j = 0; j <= 15; j++){doStep(list[j]);}}
    else
      {for (int j = 15; j >= 0; j--){doStep(list[j]);}}
  }  
}
  
// microstepping >16 steps :
void doMoreSteps(int cnt, boolean forwards){
  const int list1[] = {1,11,2,12,3,13,4,14};
  const int list2[] = {21,31,22,32,23,33,24,34};
  
  for (int i = 0; i < cnt; i++){

    duty = 50;
    if (forwards)
      {for (int j = 0; j <= 7; j++){doStep(list1[j]); doSteps(list2[j], forwards);}}
    else
      {for (int j = 7; j >= 0; j--){doSteps(list2[j], forwards); doStep(list1[j]);}}
  }
}  
// this routine handles >16 microsteps 
// uncomment sections to choose # steps
void doSteps(int st, boolean forwards){
  
// *********************** 24 steps 
/*
  if (forwards){
    duty = 66;    doStep(st);
    duty = 33;    doStep(st);
  }
  else{
    duty = 33;    doStep(st);
    duty = 66;    doStep(st);
  }
     
*/

// *********************** 32 steps 
/*
  if (forwards){
    duty = 75;    doStep(st);
    duty = 50;    doStep(st);
    duty = 25;    doStep(st);
  }
  else{
    duty = 25;    doStep(st);
    duty = 50;    doStep(st);
    duty = 75;    doStep(st);
  }
*/     

// *********************** 48 steps 

/*
if (forwards){
    for (int i = 5; i >= 1; i--){duty = 17 * i; doStep(st);}
  }
  else{
    for (int i = 1; i <= 5; i++){duty = 17 * i; doStep(st);}
  }
*/     


// *********************** 64 steps 
/*
  if (forwards){
    for (int i = 7; i >= 1; i--){duty = 12 * i; doStep(st);}
  }
  else{
    for (int i = 1; i <= 7; i++){duty = 12 * i; doStep(st);}
  }
*/  
     
// *********************** 96 steps 
/*
  if (forwards){
    for (int i = 9; i >= 1; i--){duty = 10 * i; doStep(st);}
  }
  else{
    for (int i = 1; i <= 9; i++){duty = 10 * i; doStep(st);}
  }
*/

}


void loop() {
 

 // Set the display brightness (0-7):
 display.setBrightness(0);
 
 // uncomment this to disable motor  
//  motorOff();return;

/* control the speed of the motor with a waitMicroseconds/pulseCount pair
   e.g. waitMicroSeconds / pulseCount
        500 / 5 --> one step takes 2500 microseconds
        50 / 50 --> one step also takes 2500 microseconds
        but in second pair the fequency of the wave is 20kHz, not audible..
        in 500 / 5 you may hear a high tone in the motor in microsteps  
        some motors may not respond well on higher frequencies 
   note: these parameters also control speed in normal stepping (full or half) although there's no pulses in those cases, 
            setting pulseCount = 1 might be more readable
*/
  waitMicroSeconds = stateMotorSpeed; // Actual calculated is 279052.328
  pulseCount = 1000;      // (gear ratio is 3.44:1)

   int motorspeeddisplay = stateMotorSpeed*10;
    display.showNumberDec(motorspeeddisplay, false, 4, 0);
 //Button L procedure
  stateButtonL = digitalRead(pinButtonL);    
  if(stateButtonL == LOW  && millis() - time > debounce) 
  {
    stateMotorSpeed = stateMotorSpeed-10;  
    time = millis();
  }

 //Button R procedure
  stateButtonR = digitalRead(pinButtonR);    
  if(stateButtonR == LOW  && millis() - time > debounce)
  {
    stateMotorSpeed = stateMotorSpeed+10;  
    time = millis();
  }


 
 
//  uncomment one of the next routines to choose stepping mode
//  do4Steps : full stepping
//  do8Steps : half stepping
//  do16Steps : microstepping with 16 steps
//  doMoreSteps : microstepping with more than 16 steps
    // --> check routine 'doSteps' for extra uncomments      
/*     
  two parameters:
    1. number of steps
    2. forwards = true --> move forwards   /  forwards = false --> move backwards
    
  note: there's no speed correction for different modes, so do4Steps makes the motor go twice as fast as do8Steps and so on... 
        use waitMicroseconds and pulseCount to adapt speed when changing modes   
*/
//  do4Steps(24, true);
//  do8Steps(24, true);
//  do16Steps(24, true);//Anti-Clockwise
//  doMoreSteps(24, true);
 
//  motorOff(); // give it a rest (see note in motorOff about losing steps)
//  delay(1000);

//  do4Steps(24, false);
//  do8Steps(24, false);
  do16Steps(24, false);//Clokwise
//  doMoreSteps(24, false);


 motorOff(); // give it a rest (see note in motorOff about losing steps)
 // delay(1000);



}

Using only the "microstepping 16 steps " parts.

As far as I can see there is a lot of blocking code in your program - for example it does several steps in succession and there are also various delay()s to get the step timing correct.

That means that the buttons are not checked until whatever happens to be going on finishes.

What sort of stepper motor and stepper motor driver are you using?

The AccelStepper library has the non-blocking run() and runSpeed() functions but using it would require a complete re-write of your program.

...R
Stepper Motor Basics
Simple Stepper Code

a

Thanks.
I am using Neema 17 and a couple of L293D stacked one on the other with some heat dissipation in between.

I have tried with the AccelStepper library and was able to run the motor, but couldn't find the way to do it with 16 micro-steps which works just great with the mount and gears I have placed.

I saw many examples of how to do it with the easy driver type drivers (only 2 pins are used), but cant wait for it 2-6 weeks until it gets here..( peak of the Perseid shower is tomorrow:))

Any other way of how to control the speed so I can do small corrections will also work great.

"That means that the buttons are not checked until whatever happens to be going on finishes."

-can you give an example of something that needs to finish and is blocking the reading of the buttons?

because I dont understand how the stepping sequence is made/run I cant find how to fix or re-write.

I thought that the program is going one command at a time (within the loop) and even with delays it will eventually get to the reading command within each cycle.

mich44:
but cant wait for it 2-6 weeks until it gets here..( peak of the Perseid shower is tomorrow:))

If you need a solution that quickly I think you are probably out of luck. The real solution is a specialised stepper driver that includes the micro-stepping capability.

Following are some ideas that may help in the short term.

"That means that the buttons are not checked until whatever happens to be going on finishes."

-can you give an example of something that needs to finish and is blocking the reading of the buttons?

The main thing that seems to me to cause blocking is the motor moving 24 steps every time. I don't know how long that takes. Have you tried holding down the button long enough for it to get noticed?

Maybe change this

//Button L procedure
  stateButtonL = digitalRead(pinButtonL);    
  if(stateButtonL == LOW  && millis() - time > debounce) 
  {
    stateMotorSpeed = stateMotorSpeed-10;  
    time = millis();
  }

 //Button R procedure
  stateButtonR = digitalRead(pinButtonR);    
  if(stateButtonR == LOW  && millis() - time > debounce)
  {
    stateMotorSpeed = stateMotorSpeed+10;  
    time = millis();
  }

to this

//Button L procedure
  stateButtonL = digitalRead(pinButtonL);    
  if(stateButtonL == LOW
  {
    stateMotorSpeed = stateMotorSpeed-10;  
  }

 //Button R procedure
  stateButtonR = digitalRead(pinButtonR);    
  if(stateButtonR == LOW)
  {
    stateMotorSpeed = stateMotorSpeed+10;  
  }

The time taken by the motor may be sufficient for debouncing.

What happens if you change this line

do16Steps(24, false);//Clokwise

to (for example)

do16Steps(12, false);//Clockwise

...R

Robin2:
If you need a solution that quickly I think you are probably out of luck.

  • Couldn't agree more. Just trying to make something for the now..its part of the fun.

Robin2:
Have you tried holding down the button long enough for it to get noticed?

Yes, tried holding for 5 seconds. doesn't read.
Also tried to remove the debounce part with no avail.

Robin2:
What happens if you change this line

I like this direction - yes why is this 24? trying it now.

So the motor behaves the same with both 12, 24 , 48 or even 192 in that place. it doesnt affect the speed or the stepping in any perceivable way.

The motor is a 1.8 degree per step, so 200 steps. it is running 16 microsteps per step so 3200 steps per revolution.

it is supposed to wait 279052.328 microseconds or 279 mS between each of the 3200 steps thus making one revolution every roughly 892 seconds.

mich44:
So the motor behaves the same with both 12, 24 , 48 or even 192 in that place. it doesnt affect the speed or the stepping in any perceivable way.

Interesting.

When I suggested 12 instead of 24 I expected your further explorations to involve smaller numbers, not larger.

Changing the number won't affect the speed but I thought it might affect the responsiveness to the button press

Another thing to try ...

Move this line

waitMicroSeconds = stateMotorSpeed;

so it comes after the Button R procedure

...R

Thank you Robin2!!

Robin2:
When I suggested 12 instead of 24 I expected your further explorations to involve smaller numbers, not larger.

I went back to test lower numbers, and when placing the number 1, I can get it to respond very slowly - I need to press for 2-3 seconds and the change occurs after about 7-8 more seconds!

So it is definitely the right direction.

Moving the waitMicroSeconds line did not have an effect.