Stepper speed control okay in simple program

I want speed control for my stepper motors and found a great little sketch by Ground Fungus that works very well. Here it is, with my numbers:

include <AccelStepper.h>

// change pins to match your setup.  enable pin just for my CNC shield
const byte stepPin = 10;
const byte dirPin = 11;
const byte potPin = A0;  

AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);

void setup()
{
   Serial.begin(115200);
 //  pinMode(enablePin, OUTPUT); // for CNC shield
 //  digitalWrite(enablePin, LOW);  // enable stepper(s)
   stepper.setMaxSpeed(2000);
   stepper.setAcceleration(1000);
   stepper.setSpeed(0);
}

void loop()
{
   int potValue = analogRead(potPin);
   Serial.println(potValue);
   //if (potValue >= 487 && potValue <= 537) // ±25 hysteresis for center (0 speed)
   if (potValue >= 450 && potValue <= 500) // ±25 hysteresis for center (0 speed)
   
   {      
      stepper.setSpeed(0);     
   }
   else if (potValue < 450)//487
   {       
      stepper.setSpeed((450- potValue) * 10); // your choice of multiplier     
   }
   else if(potValue > 500)//537
   {
      stepper.setSpeed((500 - potValue) * 10); // your choice of multiplier      
   }
   stepper.runSpeed();
}

When I put the exact same code in MY program the stepper jitters and shakes and has no speed control whatsover and even reverses. The motor runs very smooth and stops at center of the pot as it should in the SIMPLE program. I commented out much of the code that I thought may be interfering, but it still doesn't work. Any ideas? Timing issue? It's running in an UNO. The rotary encoder stuff works when it's not commented out. (I'm using interrupts and rotary encoders for another function.) MY code is here:

//#include <XP_Button.h>  //this library controls state logic, debounce, pullup resistor use
#include <Wire.h>
//#include <Stepper.h>
#include <AccelStepper.h>
#include <LiquidCrystal_I2C.h>
//*******************DisplayNoDelay defs
long previousLCDMillis = 0;  // for LCD screen update
long lcdInterval = 2000;
int screen = 0;
int screenMax = 3;
bool screenChanged = true;

//*********************
const int stepPin1 = 10;  // All these pins for FE V2.0 Stepper driver shield, arranged for simple PCB layout
const int dirPin1 = 11;   //low is one direction, high is other direction
const int stepPin2 = 8;   //all pins are constant: they do not change
const int dirPin2 = 9;
const int stepsPerRevolution = 200;
#define STEPS 200             //may not need
#define motorInterfaceType 1  //may not need
int Pot1 = 0;                 //variable, not constant
int Pot2 = 0;
int x = 0;
int speedlcd1, speedlcd2, speedDelay1, speedDelay2;
volatile boolean TurnDetected1;  // need volatile for Interrupts
volatile boolean TurnDetected2;
volatile boolean rotationdirection;  // CW or CCW rotation

// Rotary Encoder Module connections
const int
  CLK1(2),  // Generating interrupts using CLK signal from rotary encoder Interrupt 0
  CLK2(3),  // Generating interrupts using CLK signal from rotary encoder Interrupt 1
  DT1(4),   // Reading DT signal  data from rotary encoder 1
  DT2(6);   // Reading DT signal

const byte
  RotaryPB1(5),  //not used at this time. This is rotary encoder PB  Not used for jog which is controlled by interrupts
  RotaryPB2(7),  //rotary encoder PB
  LED1(12),
  LED2(13);
//Button RPB1(RotaryPB1);
//Button RPB2(RotaryPB2);

bool tog1 = 0;  // Jog/Continuous switch H=continuous, L=default jog
bool tog2 = 0;

int StepperPosition = 0;  // To store Stepper Motor Position
int StepsToTake = 25;     // Controls the step taken when turning encoder  50/200*360=90 degrees 25/200*360=45 degrees
int direction;            // Variable to set Rotation (CW-CCW) of stepper

LiquidCrystal_I2C lcd(0x27, 16, 2);  //default for 2x16 LCD
AccelStepper stepper1(AccelStepper::DRIVER, stepPin1, dirPin1);

/************************ Interrupt detection for both encoders *************/
void rotarydetect1() {
  delay(4);  // delay for Debouncing
  if (digitalRead(CLK1))
    rotationdirection = digitalRead(DT1);
  else
    rotationdirection = !digitalRead(DT1);
  TurnDetected1 = true;  // this is the flag that is set if there was an interrupt.  Flag is tested in Loop function.
}  //END isr0

void rotarydetect2() {
  delay(4);  // delay for Debouncing
  if (digitalRead(CLK2))
    rotationdirection = digitalRead(DT2);
  else
    rotationdirection = !digitalRead(DT2);
  TurnDetected2 = true;
}  //end ISR1

/*************************SETUP*****************************/
void setup() {
  stepper1.setMaxSpeed(2000);
  stepper1.setAcceleration(1000);
  stepper1.setSpeed(0);
  //RPB1.begin();  //initialize pushbuttons, in XP_button library function
  //RPB2.begin();
  Serial.begin(19200);
  Wire.begin();
  lcd.begin(16, 2);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  //pinMode(RotaryPB1, INPUT);
  // pinMode(RotaryPB2, INPUT);


  //A4988 stepper driver
  pinMode(stepPin1, OUTPUT);
  pinMode(dirPin1, OUTPUT);
  pinMode(stepPin2, OUTPUT);
  pinMode(dirPin2, OUTPUT);
  pinMode(tog1, INPUT);
  pinMode(tog2, INPUT);

  //************rotary encoder***********
  pinMode(CLK1, INPUT);
  pinMode(DT1, INPUT);
  pinMode(CLK2, INPUT);
  pinMode(DT2, INPUT);

  showWelcome();  //Display Welcome (FE)  message
// attachInterrupt(0, rotarydetect1, FALLING);  // interrupt 0 always connected to pin 2 on Arduino UNO
// attachInterrupt(1, rotarydetect2, FALLING);  // interrupt 1 connected to pin 3
}  //end Setup function

/***********************Loop Function***********************************/
void loop() {
  /* unsigned long currentLCDMillis = millis();
  if (currentLCDMillis - previousLCDMillis > lcdInterval)  // save the last time you changed the display
  {
    previousLCDMillis = currentLCDMillis;
    screen++;
    if (screen > screenMax) screen = 0;  // all screens done? => start over
    screenChanged = true;
    if (screenChanged)  // -- only update the screen if the screen is changed.
    {
      screenChanged = false;  // reset for next iteration
      switch (screen) {
        //     case Speed:
        lcdSpeed();
        break;

        //     case DirFor:
        lcdDirFor();
        break;

        //  case DirRev:
        lcdDirRev();
        break;

        default:
          // cannot happen -> showError() ?
          break;
      }
    }
  }
  */
  /*static bool ledState1;
  static bool ledState2;
  RPB1.read();  //read state of rotary pushbutton
  RPB2.read();
  */
  Pot1 = analogRead(A0);  //read value of pot for motor 1
  Pot2 = analogRead(A1);
  tog1 = digitalRead(17);  //read switch to determine mode
  tog2 = digitalRead(16);

  /*if (tog1) {
    digitalWrite(LED1, HIGH);
    // backforth1();
   SpeedM1();
  } else if (!tog1) {
    digitalWrite(LED1, LOW);
  }

  if (tog2) {
    digitalWrite(LED2, HIGH);
    //backforth2();//works when switched
   SpeedM2();
  } else if (!tog2) {
    digitalWrite(LED2, LOW);
  }
*/
  // Midpoint pot control from Forum
  int potValue1 = analogRead(Pot1);
  Serial.print("Pot1=  ");
  Serial.println(potValue1);
  if (potValue1 >= 450 && potValue1 <= 500)  // ±25 hysteresis for center (0 speed)
  {
    stepper1.setSpeed(0);
  } else if (potValue1 < 450) {
    stepper1.setSpeed((450 - potValue1) * 10);  // your choice of multiplier
  } else if (potValue1 > 500) {
    stepper1.setSpeed((500 - potValue1) * 10);  // your choice of multiplier
  }
  stepper1.runSpeed();
  /*
  //If rotation detected the ISR reads the switch and sets the TurnDetected1 flag to TRUE
  // and also sets rotation direction.  Was controlled turned?  Which one? What direction?
  if (TurnDetected1) {
    TurnDetected1 = false;  // do NOT repeat IF loop until new rotation detected
    // Which direction to move Stepper motor
    if (rotationdirection) {        // Move motor CCW
      digitalWrite(dirPin1, HIGH);  // (HIGH = anti-clockwise / LOW = clockwise)
      for (int x = 1; x < StepsToTake; x++) {
        digitalWrite(stepPin1, HIGH);
        delay(1);
        digitalWrite(stepPin1, LOW);
        delay(1);
      }  //end for
      StepperPosition = StepperPosition - StepsToTake;
    }  //end if

    if (!rotationdirection) {      // Move motor CW
      digitalWrite(dirPin1, LOW);  // (HIGH = anti-clockwise / LOW = clockwise)
      for (int x = 1; x < StepsToTake; x++) {
        digitalWrite(stepPin1, HIGH);
        delay(1);
        digitalWrite(stepPin1, LOW);
        delay(1);
      }  //end for
      StepperPosition = StepperPosition + StepsToTake;
    }  //end if
  }    //end if TurnDetected1

  //Runs if rotation was detected which triggers the interrupt TUNEDETECTED2
  if (TurnDetected2) {
    TurnDetected2 = false;  // do NOT repeat IF loop until new rotation detected
    // Which direction to move Stepper motor
    if (rotationdirection) {        // Move motor CCW
      digitalWrite(dirPin2, HIGH);  // (HIGH = anti-clockwise / LOW = clockwise)
      for (int x = 1; x < StepsToTake; x++) {
        digitalWrite(stepPin2, HIGH);
        delay(1);
        digitalWrite(stepPin2, LOW);
        delay(1);
      }  //end for
      StepperPosition = StepperPosition - StepsToTake;
    }  //end if

    if (!rotationdirection) {      // Move motor CW
      digitalWrite(dirPin2, LOW);  // (HIGH = anti-clockwise / LOW = clockwise)
      for (int x = 1; x < StepsToTake; x++) {
        digitalWrite(stepPin2, HIGH);
        delay(1);
        digitalWrite(stepPin2, LOW);
        delay(1);
      }  //end for
      StepperPosition = StepperPosition + StepsToTake;
    }  //end if
  }    //end if TurnDetected2
  */
}  //end of loop function

/***********************M1 and M2 Variable Speed******************************************/
void SpeedM1() {
  speedDelay1 = map(Pot1, 0, 1023, 0, 800);  //higher value for speed delay= faster
  digitalWrite(stepPin1, HIGH);
  delayMicroseconds(speedDelay1);
  digitalWrite(stepPin1, LOW);
  delayMicroseconds(speedDelay1);
}

void SpeedM2() {
  speedDelay2 = map(Pot2, 0, 1023, 0, 800);
  digitalWrite(stepPin2, HIGH);
  delayMicroseconds(speedDelay2);
  digitalWrite(stepPin2, LOW);
  delayMicroseconds(speedDelay2);
}
/**********************LCD functions*******************/
void showWelcome() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("FoundEngineering");
  lcd.setCursor(0, 1);
  lcd.print("IndianHarbour NS");
  delay(3000);
  lcd.setCursor(0, 0);
  lcd.print("Starting Up     ");
  lcd.setCursor(0, 1);
  lcd.print("  Running       ");
  // delay(1000);
  //lcd.clear();
}

void lcdSpeed() {
  lcd.clear();
  speedlcd1 = map(analogRead(Pot1), 0, 1023, 0, 100);
  lcd.setCursor(0, 0);
  lcd.print("Speed M1 =    ");
  lcd.print(speedlcd1);  // convert to RPM
  speedlcd2 = map(analogRead(Pot2), 0, 1023, 0, 100);
  lcd.setCursor(0, 1);
  lcd.print("Speed M2 =    ");
  lcd.print(speedlcd2);
}

void lcdPosDeg() {
  lcd.clear();  //from Dejan
  lcd.print("Position: ");
  //   lcd.print(int(angle*(-1.8)));
  lcd.print("deg");
  lcd.setCursor(0, 0);
}
void lcdDirFor() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Forward");
}

void lcdDirRev() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Forward ");
}

/*******************M1 Forward/Reverse***********************/
void backforth1() {
  digitalWrite(dirPin1, HIGH);
  lcdDirFor();
  for (int x = 0; x < 1600; x++) {
    digitalWrite(stepPin1, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin1, LOW);
    delayMicroseconds(500);
  }             //end for loop
  delay(1000);  //delay to turnaround and go the other direction
  digitalWrite(dirPin1, LOW);

  lcdDirRev();
  for (int x = 0; x < 1600; x++) {
    digitalWrite(stepPin1, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin1, LOW);
    delayMicroseconds(500);
  }  //end of for loop
  digitalWrite(LED1, LOW);
  delay(1000);
}  //end backforth1 function

/*******************M2 Forward/Reverse***********************/
void backforth2() {
  digitalWrite(dirPin2, HIGH);
  lcdDirFor();
  for (int x = 0; x < 1600; x++) {
    digitalWrite(stepPin2, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin2, LOW);
    lcdDirRev();
    delayMicroseconds(500);
  }  //end for loop
  delay(1000);
  digitalWrite(dirPin2, LOW);

  lcdDirRev();
  for (int x = 0; x < 1600; x++) {
    digitalWrite(stepPin2, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin2, LOW);
    delayMicroseconds(500);
  }  //end of for loop
  digitalWrite(LED2, LOW);
  delay(1000);
}  //end backforth2 function

An excellent approach to get where you want to go is to start with a well-tested, working program like the first you showed, then add features to it, one at a time, testing and correcting as you proceed.

Stepper misbehavior can be due to many problems other than bad code, but you haven't posted nearly enough information to guess if that might the case.

2 Likes

Post an annotated schematic showing exactly how you have wired it. Be sure to show all power sources and links to technical information on the hardware.

I think the point is being missed that all the hardware is the same and never changed from the simple sketch to the more complicated sketch, in other words a substution of one sketch for the other.

The "more complicated" sketch was heavily edited (commented out), to eliminate some obvious areas where I thought there could be problems.

Here's the thing too...If I run the complicated sketch WITHOUT the simpler sketch included, the motors run fine with my speed control (which is commented out). Here's a snippet of the area I'm talking about. My code, commented out here, calls the function SpeedM1 and controls the speed of the motor well. Below the commented code is the Forum code which runs well ALONE in a sketch, but NOT here. What's the difference? I tried to put the Forum code into a function but I get the same result. The next thing for me to try is comment out ALL my code except for the Forum part and then add pieces until it fails.
...
/*if (tog1) {
digitalWrite(LED1, HIGH);
// backforth1();
SpeedM1();
} else if (!tog1) {
digitalWrite(LED1, LOW);
}

if (tog2) {
digitalWrite(LED2, HIGH);
//backforth2();//works when switched
SpeedM2();
} else if (!tog2) {
digitalWrite(LED2, LOW);
}
*/
// Midpoint pot control from Forum
int potValue1 = analogRead(Pot1);
Serial.print("Pot1= ");
Serial.println(potValue1);
if (potValue1 >= 450 && potValue1 <= 500) // ±25 hysteresis for center (0 speed)
{
stepper1.setSpeed(0);
} else if (potValue1 < 450) {
stepper1.setSpeed((450 - potValue1) * 10); // your choice of multiplier
} else if (potValue1 > 500) {
stepper1.setSpeed((500 - potValue1) * 10); // your choice of multiplier
}
stepper1.runSpeed();

![SchematicV20|648x500](upload://72rik2q0S2Two0VL5ZOk3LuCacl.jpeg)

This is impossible. A sketch never runs inside a sketch.

Your hardware consists of:

  1. Power supply
  2. Arduino
  3. Stepper driver
  4. Stepper motor

AccelStepper has examples. Build your sketch from one... AccelStepper/examples/Random/Random.pde at master · waspinator/AccelStepper · GitHub

Okay I used wrong words...I run the simple CODE inside the "complicated" sketch.

Since my last post, I commented out EVERYTHING in my sketch, including all the functions, ran the sketch and the stepper works fine, as it should. So one or two of my variables, constants, declarations or whatever is affecting the operation. I will now add one or two of these back in and see what makes it fail.

Stay tuned.

Okay, I found the problem.

I confused the Pot1 variable with the Pot1 constant, the latter being the pin number, A0.

I need this : const byte Pot1=A0;
and this: int potValue1 = analogRead(Pot1);

In my code I never once had Pot1 as a const byte, in fact, I had it as "int Pot1=0"

anyway, I won't make that mistake again. I put all the code back, uncommented, with the Forum code right where I want it and everything works fine.

Thanks for your inputs.

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