Stepper motor control with I2C-LCD display

OK. I see from the video and it looks like the loop() isn't running.

I can't quite make it out, but the display appears to have 0.00 in it for speed. I put a guard on it to ensure that that the value didn't get too low because what it looks is that the frequency of the timer is so high that the the interrupt service routine is using all the resources. Therefore, the loop() does not run. Maybe this is not working.

  static int speedControlUsLast = -1 ;
  int speedControlUs = speedControl() ;
  if ( speedControlUs < 500 ) speedControlUs = 500 ; // can't be too low
  if ( speedControlUs != speedControlUsLast ) {
    Timer1.setPeriod(  speedControl() ) ;  // microseconds
    speedControlUsLast = speedControlUs ;
  }

maybe change this line:

if ( speedControlUs < 500 ) speedControlUs = 500 ; // can't be too low

to

if ( speedControlUs < 1000 ) speedControlUs = 1000 ; // can't be too low

just as a test to see if that is the problem.

You could also temporarily uncomment these two line to see if you get anything in the serial monitor.

//Serial.println("in loop") ;
//delay(1000) ;

The code now works 95% perfectly. It displays the potentiometer value and the status of the motor. But the original speed of the motor is reduced to about half. The minimum speed is good, but i'd like the max speed a bit higher. What value should i tweak?

Also, on the LCD it is displayed a value from 0.00 to 5.11. Can it be made to display 0% - 100%?

i am keeping the following commands commented because it works if i keep them like that

//Serial.println("in loop") ;
//delay(1000) ;

I can't thank you enough for your help!

You can try experimenting here:

if ( speedControlUs < 500 ) speedControlUs = 500 ; // can't be too low
Change the 500 to say 250 and see if the loop still works (I.e. it does not freeze).

You may be able to get a % speed value by changing this:

lcd1.print(float(float(customDelay) / float(200)), 2 ) ;

To:

lcd1.print( (4000 - customDelay) / 40 ) ;

If that doesn’t work, the next thing to look at is the interrupt service routine.

All you recommendations work amazing. Thanks again for your support!

Alltough, a final problem would be still related to the lcd.

First, the potentiometer minimum value is 74, and the max 100. but the weird thing is that it goes from 74 to 100, but when coming back down, that last "0" from 100 remains frozen on the screen, making the number 740 for minimum and 100 for maximum.

Second, if i turn the potentiometer just a bit too quickly, everything freezes.

And the last thing, on startup, if the potentiometer is not at minimum value, everything freeses, and the stepper starts twitching.

I’m surprised that the potentiometer range starts at 74. I’d have expected something nearer 0. Maybe the 4 is also a relic of a previous value in the same way as 0 of 740. Maybe the simplest solution is to write say 3 spaces to the lcd, then reposition the cursor before writing the speed value.

Does the strange startup behavior occur in all switch positions?

Anyway, post the latest version of your code.

I've tried to move the value 1,2 and 3 spaces, but the same thing keeps happening. After it hits the 100 value, the last 0 stays frozen in place. I gave you a link below so you can understand better what's going on. The value starts at 74, so if you can somehow fix this problem, you can set the max value to be 99, so it never goes to 100 (I am using a 10K ohm potentiometer).

If i turn the pot a bit too fast, EVERYTHING glitches out - the LCD freezes, the stepper stops rotating and starts twitching, and the pot does not work. The same thing happens if on startup the pot is not at minimum value.
Can this problem be fixed?

// -------------- Include the following Librarys -------------- //
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>

#include <TimerOne.h>


// -------------- Connect to LCD via I2C -------------- //
//Define the LCD  Being used and its settings
hd44780_I2Cexp lcd1(0x27);


// -------------- Defines pins numbers -------------- //
const int stepPin = 3;
const int dirPin = 4;
const int switchPinA = A1;
const int switchPinB = A2;
int customDelay, customDelayMapped; // Defines variables
const int ms1 = 8;
const int ms2 = 9;
const int ms3 = 10;
int switchPinAVal = 0;
int switchPinBVal = 0;

enum class MotorControl { CLOCKWISE, ANTICLOCKWISE, STOP } ;  //MD1
volatile MotorControl motorControl = MotorControl::STOP ;    //initial state  //MD1


//--------------------------MIN & MAX Potentiometer  Settings-------------------------------//
// Define our maximum and minimum speed in steps per second (scale pot to these) //

void setup() {

  Serial.begin( 115200 ) ;    //MD1
  Serial.println(F("Motor Controller")) ; //MD1



  // -------------- Initiate the LCD --------------  //
  lcd1.init();                    // initialize the lcd
  lcd1.init();                    // initialize the lcd
  lcd1.backlight();               // turn on backlight
  lcd1.begin(16, 2);              

  // -------------- On power up display on the LCD intro -------------- //
  lcd1.print("Speed:");           
  lcd1.setCursor(11, 0);          
  lcd1.print("n/min");            
  lcd1.setCursor(0, 1);           
  lcd1.print("Direction:");       

  pinMode(switchPinA, INPUT_PULLUP);
  pinMode(switchPinB, INPUT_PULLUP);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(ms1, OUTPUT);
  pinMode(ms2, OUTPUT);
  pinMode(ms3, OUTPUT);

  Timer1.initialize( 5000 ); //start 5mS
  Timer1.attachInterrupt( motorController ) ;  //MD1
}


// -------------- Begin Loop , Begin Operating Machine -------------- //
void loop()
{

  switchPinAVal = digitalRead(switchPinA);
  switchPinBVal = digitalRead(switchPinB);


  if (switchPinAVal == HIGH && switchPinBVal == LOW)
  {
    // motorRunClockwise(); //MD1
    motorControl = MotorControl::CLOCKWISE ;  //MD1


    // -------------- Update LCD to ">>>>>>" -------------- //
    lcd1.setCursor(10, 1);             
    lcd1.print(">>>>>>");              
  }
  
  if (switchPinAVal == LOW && switchPinBVal == HIGH)
  {
    // motorRunAntiClockwise();
    motorControl = MotorControl::ANTICLOCKWISE ;  //MD1


    // -------------- Update LCD to "<<<<<<" -------------- //
    lcd1.setCursor(10, 1);           
    lcd1.print("<<<<<<");            
  }
  
  //else
  if (switchPinAVal == HIGH && switchPinBVal == HIGH || switchPinAVal == LOW && switchPinBVal == LOW)     
  {
    motorControl = MotorControl::STOP ;  //MD1
    digitalWrite(stepPin, LOW); // stop the motor


    // -------------- Update LCD to "STOP" -------------- //
    lcd1.setCursor(10, 1);           
    lcd1.print(" STOP ");            
  }


  static int speedControlUsLast = -1 ;
  int speedControlUs = speedControl() ;
  if ( speedControlUs < 50 ) speedControlUs = 50 ; // can't be too low
  if ( speedControlUs != speedControlUsLast ) {
    Timer1.setPeriod(  speedControl() ) ;  // microseconds
    speedControlUsLast = speedControlUs ;
  }
}


void motorController() {

  static bool toggle = false ; // we make two entries here per cycle

  if ( motorControl == MotorControl::STOP ) {
    // handle stop here
  }
  else {
    if ( toggle == false ) {
      digitalWrite(stepPin, HIGH);
    }
    else {
      if ( motorControl == MotorControl::CLOCKWISE ) {
        // clockwise
        digitalWrite(dirPin, LOW);
      }
      else if ( motorControl == MotorControl::ANTICLOCKWISE ) {
        digitalWrite(dirPin, HIGH);
      }
      else {
        // should not happen
      }
      digitalWrite(ms1, HIGH);
      digitalWrite(ms2, HIGH);
      digitalWrite(ms3, HIGH);
      digitalWrite(stepPin, LOW);
    }
    toggle = ! toggle ;
  }
}


// -------------- Function for reading the Potentiometer -------------- //
  int speedControl() {
  int customDelay = analogRead(A0); // Reads the potentiometer
  int newCustom = map(customDelay, 0, 1023, 0, 4000); // Converts the read values of the potentiometer from 0 to 1023 into desireded delay values (0 to 4000)

  // -------------- Update LCD to "Potentiometer value" -------------- //
  lcd1.setCursor(6, 0);
  lcd1.print( (4000 - customDelay) / 40 ) ;    

  return newCustom;
}

/////////////////////////////////////////////////////////////////////////
void motorRunClockwise() {
  //NOT USED
  customDelayMapped = speedControl();
  digitalWrite(stepPin, LOW);
  delayMicroseconds(customDelayMapped);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(customDelayMapped);
  digitalWrite(dirPin, LOW);
  digitalWrite(ms1, HIGH);
  digitalWrite(ms2, HIGH);
  digitalWrite(ms3, HIGH);
}

////////////////////////////////////////////////////////////////////////
void motorRunAntiClockwise() {
  //NOT USED
  customDelayMapped = speedControl();
  digitalWrite(stepPin, LOW);
  delayMicroseconds(customDelayMapped);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(customDelayMapped);
  digitalWrite(dirPin, HIGH);
  digitalWrite(ms1, HIGH);
  digitalWrite(ms2, HIGH);
  digitalWrite(ms3, HIGH);
}
lcd1.setCursor(6, 0);
lcd1.print("   "); //three blank spaces
lcd1.setCursor(6, 0);
lcd1.print( (4000 - customDelay) / 40 ) ;

p_cipri:
I've tried to move the value 1,2 and 3 spaces, but the same thing keeps happening. After it hits the 100 value, the last 0 stays frozen in place.

This will be because you are just over writing new data into the same digit locations on the LCD.
When you go from 3 to 2 digits, the 3rd digit is no longer updated, so keeps the digit it had when a 3digit number was displayed.
The solution is to place 3 blanks in the 3 digit positions before you update the value that is going into them.
Tom... :slight_smile:
Edit. yes just like @cattledog has shown, missed by 1 minute... :slight_smile:

Yes, cattledog and now tomgeorge have already done what l would suggest. I made a mistake earlier with the variable name though.

The :

4000 - customDelay

Should be :

4000 - newCustom

Edit
——

I found this description of the controller you are using: https://lastminuteengineers.com/a4988-stepper-motor-driver-arduino-tutorial/

It appears you are using the maximum resolution of 1/16 steps. Is this necessary? The frequency of the timer is getting quite high ( 20Khz with a 50us period) so the ISR is getting quite heavy. I see also there is some unnecessary activity there such as setting pins ms1, ms2 and ms3 which could be moved to setup().

Thank you all so much! You've helped me A LOT! Sorry if i gave you too much troubble. Everything works perfectly now!

I’m glad that all worked out. If you discover further problems, then post your updated sketch.

Hello again guys! I am back with a small bug, and i need your help. I wanted to use this project for a fishing rod building set, but the hospitals in my country need breathing aids/ventilators! I am currently 3d printing one i've made, but in the code, there is a small bug:

Everything glitches out and stops working if the potentiometer is not at zero on startup. I need everyone's help to make this as reliable and safe as possibble!

This is my code:

// -------------- Include the following Librarys -------------- //
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>

#include <TimerOne.h>


// -------------- Connect to LCD via I2C -------------- //
//Define the LCD  Being used and its settings
hd44780_I2Cexp lcd1(0x27);


// -------------- Defines pins numbers -------------- //
const int stepPin = 3;
const int dirPin = 4;
const int switchPinA = A1;
const int switchPinB = A2;
int customDelay, customDelayMapped; // Defines variables
const int ms1 = 8;
const int ms2 = 9;
const int ms3 = 10;
int switchPinAVal = 0;
int switchPinBVal = 0;

enum class MotorControl { CLOCKWISE, ANTICLOCKWISE, STOP } ;  //MD1
volatile MotorControl motorControl = MotorControl::STOP ;    //initial state  //MD1


//--------------------------MIN & MAX Potentiometer  Settings-------------------------------//
// Define our maximum and minimum speed in steps per second (scale pot to these) //

void setup() {

  Serial.begin( 115200 ) ;    //MD1
  Serial.println(F("Motor Controller")) ; //MD1



  // -------------- Initiate the LCD --------------  //
  lcd1.init();                    // initialize the lcd
  lcd1.init();                    // initialize the lcd
  lcd1.backlight();               // turn on backlight
  lcd1.begin(16, 2);

  // -------------- On power up display on the LCD intro -------------- //
  lcd1.print("Speed:");
  lcd1.setCursor(12, 0);
  lcd1.print("RPM");
  lcd1.setCursor(0, 1);
  lcd1.print("Direction:");

  pinMode(switchPinA, INPUT_PULLUP);
  pinMode(switchPinB, INPUT_PULLUP);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(ms1, OUTPUT);
  pinMode(ms2, OUTPUT);
  pinMode(ms3, OUTPUT);

  Timer1.initialize( 5000 ); //start 5mS
  Timer1.attachInterrupt( motorController ) ;  //MD1
}


// -------------- Begin Loop , Begin Operating Machine -------------- //
void loop()
{

  switchPinAVal = digitalRead(switchPinA);
  switchPinBVal = digitalRead(switchPinB);


  if (switchPinAVal == HIGH && switchPinBVal == LOW)
  {
    // motorRunClockwise(); //MD1
    motorControl = MotorControl::CLOCKWISE ;  //MD1


    // -------------- Update LCD to ">>>>>>" -------------- //
    lcd1.setCursor(10, 1);
    lcd1.print(">>>>>>");
  }

  if (switchPinAVal == LOW && switchPinBVal == HIGH)
  {
    // motorRunAntiClockwise();
    motorControl = MotorControl::ANTICLOCKWISE ;  //MD1


    // -------------- Update LCD to "<<<<<<" -------------- //
    lcd1.setCursor(10, 1);
    lcd1.print("<<<<<<");
  }

  //else
  if (switchPinAVal == HIGH && switchPinBVal == HIGH || switchPinAVal == LOW && switchPinBVal == LOW)
  {
    motorControl = MotorControl::STOP ;  //MD1
    digitalWrite(stepPin, LOW); // stop the motor


    // -------------- Update LCD to "STOP" -------------- //
    lcd1.setCursor(10, 1);
    lcd1.print(" STOP ");
  }


  static int speedControlUsLast = -1 ;
  int speedControlUs = speedControl() ;
  if ( speedControlUs < 50 ) speedControlUs = 50 ; // can't be too low
  if ( speedControlUs != speedControlUsLast ) {
    Timer1.setPeriod(  speedControl() ) ;  // microseconds
    speedControlUsLast = speedControlUs ;
  }
}


void motorController() {

  static bool toggle = false ; // we make two entries here per cycle

  if ( motorControl == MotorControl::STOP ) {
    // handle stop here
  }
  else {
    if ( toggle == false ) {
      digitalWrite(stepPin, HIGH);
    }
    else {
      if ( motorControl == MotorControl::CLOCKWISE ) {
        // clockwise
        digitalWrite(dirPin, LOW);
      }
      else if ( motorControl == MotorControl::ANTICLOCKWISE ) {
        digitalWrite(dirPin, HIGH);
      }
      else {
        // should not happen
      }
      digitalWrite(ms1, LOW);
      digitalWrite(ms2, HIGH);
      digitalWrite(ms3, HIGH);
      digitalWrite(stepPin, LOW);
    }
    toggle = ! toggle ;
  }
}


// -------------- Function for reading the Potentiometer -------------- //
int speedControl() {
  int customDelay = analogRead(A0); // Reads the potentiometer
  int newCustom = map(customDelay, 0, 1023, 0, 4000); // Converts the read values of the potentiometer from 0 to 1023 into desireded delay values (0 to 4000)

  // -------------- Update LCD to "Potentiometer value" -------------- //
  //lcd1.setCursor(7, 0);;
  lcd1.print("   "); //three blank spaces
  lcd1.setCursor(7, 0);;
  lcd1.print( (4000 - newCustom) / 40 ) ;

  return newCustom;
}

/////////////////////////////////////////////////////////////////////////
void motorRunClockwise() {
  //NOT USED
  customDelayMapped = speedControl();
  digitalWrite(stepPin, LOW);
  delayMicroseconds(customDelayMapped);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(customDelayMapped);
  digitalWrite(dirPin, LOW);
  digitalWrite(ms1, HIGH);
  digitalWrite(ms2, HIGH);
  digitalWrite(ms3, HIGH);
}

////////////////////////////////////////////////////////////////////////
void motorRunAntiClockwise() {
  //NOT USED
  customDelayMapped = speedControl();
  digitalWrite(stepPin, LOW);
  delayMicroseconds(customDelayMapped);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(customDelayMapped);
  digitalWrite(dirPin, HIGH);
  digitalWrite(ms1, HIGH);
  digitalWrite(ms2, HIGH);
  digitalWrite(ms3, HIGH);
}

Did the original sketch show this behaviour ? I see some attempts to limit the minimum delay between operations of the step pin.

   int newCustom = map(customDelay, 0, 1023, 0, 4000); // Converts the read values of the potentiometer from 0 to 1023 into desireded delay values (0 to 150)
 //int newCustom = map(customDelay, 0, 1023, 300, 4000); // Convrests the read values of the potentiometer from 0 to 1023 into desireded delay values (300 to 4000)

What does microstep resolution is this ?:

      digitalWrite(ms1, LOW);
      digitalWrite(ms2, HIGH);
      digitalWrite(ms3, HIGH);

Did you get this value 50 by experimenting ?

if ( speedControlUs < 50 ) speedControlUs = 50 ; // can't be too low

@6v6gt Yes, i have tried to tweak some values by experimenting XD. But that glitch was there from the begining. I noticed that if i take out the ms1 pin(not conect it), the stepper spins much faster. But i do not need that anymore. I need slow, variable speed(with the pot). I will insert back that pin.

The only thing i need desperately right now is that glitch to be fixed so it is safe for doctors and patients.

OK. I've restructured the code so it should handle the initial start more cleanly. I haven't tested it though.
I've also added my disclaimer that it is untested hobby work, since you have now said that you have repurposed the project
If that still doesn't work, I'll look more carefully at the motor and controller documentation.

// *** Disclaimer: This is an untested hobby development.


// -------------- Include the following Librarys -------------- //
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>

#include <TimerOne.h>


// -------------- Connect to LCD via I2C -------------- //
//Define the LCD  Being used and its settings
hd44780_I2Cexp lcd1(0x27);


// -------------- Defines pins numbers -------------- //
const int stepPin = 3;
const int dirPin = 4;
const int switchPinA = A1;
const int switchPinB = A2;
int customDelay, customDelayMapped; // Defines variables
const int ms1 = 8;
const int ms2 = 9;
const int ms3 = 10;
int switchPinAVal = 0;
int switchPinBVal = 0;

enum class MotorControl { CLOCKWISE, ANTICLOCKWISE, STOP } ;  //MD1
volatile MotorControl motorControl = MotorControl::STOP ;    //initial state  //MD1


//--------------------------MIN & MAX Potentiometer  Settings-------------------------------//
// Define our maximum and minimum speed in steps per second (scale pot to these) //

void setup() {

  Serial.begin( 115200 ) ;    //MD1
  Serial.println(F("Motor Controller")) ; //MD1



  // -------------- Initiate the LCD --------------  //
  lcd1.init();                    // initialize the lcd
  lcd1.init();                    // initialize the lcd
  lcd1.backlight();               // turn on backlight
  lcd1.begin(16, 2);

  // -------------- On power up display on the LCD intro -------------- //
  lcd1.print("Speed:");
  lcd1.setCursor(12, 0);
  lcd1.print("RPM");
  lcd1.setCursor(0, 1);
  lcd1.print("Direction:");

  pinMode(switchPinA, INPUT_PULLUP);
  pinMode(switchPinB, INPUT_PULLUP);
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(ms1, OUTPUT);
  pinMode(ms2, OUTPUT);
  pinMode(ms3, OUTPUT);

  digitalWrite(ms1, LOW);
  digitalWrite(ms2, HIGH);
  digitalWrite(ms3, HIGH);

  motorDirection() ;

  Timer1.initialize( 1000 ); //start 1mS but may be better read the required sped here
  Timer1.attachInterrupt( motorController ) ;  //MD1
}


// -------------- Begin Loop , Begin Operating Machine -------------- //
void loop()
{
  motorDirection() ;

  static int speedControlUsLast = -1 ;
  int speedControlUs = speedControl() ;
  if ( speedControlUs < 50 ) speedControlUs = 50 ; // can't be too low
  if ( speedControlUs != speedControlUsLast ) {
    Timer1.setPeriod(  speedControl() ) ;  // microseconds
    speedControlUsLast = speedControlUs ;
  }
}

void motorDirection() {
  // handles motor direction switches
  
  switchPinAVal = digitalRead(switchPinA);
  switchPinBVal = digitalRead(switchPinB);

  if (switchPinAVal == HIGH && switchPinBVal == LOW)
  {
    // motorRunClockwise(); //MD1
    motorControl = MotorControl::CLOCKWISE ;  //MD1

    // -------------- Update LCD to ">>>>>>" -------------- //
    lcd1.setCursor(10, 1);
    lcd1.print(">>>>>>");
  }

  if (switchPinAVal == LOW && switchPinBVal == HIGH)
  {
    // motorRunAntiClockwise();
    motorControl = MotorControl::ANTICLOCKWISE ;  //MD1

    // -------------- Update LCD to "<<<<<<" -------------- //
    lcd1.setCursor(10, 1);
    lcd1.print("<<<<<<");
  }

  //else
  if ( (switchPinAVal == HIGH && switchPinBVal == HIGH)  || (switchPinAVal == LOW && switchPinBVal == LOW) )
  {
    motorControl = MotorControl::STOP ;  //MD1
    digitalWrite(stepPin, LOW); // stop the motor

    // -------------- Update LCD to "STOP" -------------- //
    lcd1.setCursor(10, 1);
    lcd1.print(" STOP ");
  }
}


void motorController() {

  static bool toggle = false ; // we make two entries here per cycle

  if ( motorControl == MotorControl::STOP ) {
    // handle stop here
  }
  else {
    if ( toggle == false ) {
      digitalWrite(stepPin, HIGH);
    }
    else {
      if ( motorControl == MotorControl::CLOCKWISE ) {
        // clockwise
        digitalWrite(dirPin, LOW);
      }
      else if ( motorControl == MotorControl::ANTICLOCKWISE ) {
        digitalWrite(dirPin, HIGH);
      }
      else {
        // should not happen
      }
      // digitalWrite(ms1, LOW);   // now in setup()
      // digitalWrite(ms2, HIGH);  // now in setup()
      // digitalWrite(ms3, HIGH);  // now in setup()
      digitalWrite(stepPin, LOW);
    }
    toggle = ! toggle ;
  }
}


// -------------- Function for reading the Potentiometer -------------- //
int speedControl() {
  int customDelay = analogRead(A0); // Reads the potentiometer
  int newCustom = map(customDelay, 0, 1023, 0, 4000); // Converts the read values of the potentiometer from 0 to 1023 into desireded delay values (0 to 4000)

  // -------------- Update LCD to "Potentiometer value" -------------- //
  //lcd1.setCursor(7, 0);;
  lcd1.print("   "); //three blank spaces
  lcd1.setCursor(7, 0);;
  lcd1.print( (4000 - newCustom) / 40 ) ;

  return newCustom;
}

/////////////////////////////////////////////////////////////////////////
void motorRunClockwise() {
  //NOT USED
  customDelayMapped = speedControl();
  digitalWrite(stepPin, LOW);
  delayMicroseconds(customDelayMapped);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(customDelayMapped);
  digitalWrite(dirPin, LOW);
  digitalWrite(ms1, HIGH);
  digitalWrite(ms2, HIGH);
  digitalWrite(ms3, HIGH);
}

////////////////////////////////////////////////////////////////////////
void motorRunAntiClockwise() {
  //NOT USED
  customDelayMapped = speedControl();
  digitalWrite(stepPin, LOW);
  delayMicroseconds(customDelayMapped);
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(customDelayMapped);
  digitalWrite(dirPin, HIGH);
  digitalWrite(ms1, HIGH);
  digitalWrite(ms2, HIGH);
  digitalWrite(ms3, HIGH);
}

I don't understand this

int speedControlUs = speedControl() ;
  if ( speedControlUs < 50 ) speedControlUs = 50 ; // can't be too low
  if ( speedControlUs != speedControlUsLast ) {
    Timer1.setPeriod(  speedControl() ) ;  // microseconds
    speedControlUsLast = speedControlUs ;

You appear to make an attempt to keep speedControlUs >=50 which makes sense for keeping the step speed slow enough to not stall the motor.
But then when it comes time to actually set the timer interrupt period you use the raw value of speedControl() with no lower end limitation.

I think you want

int speedControlUs = speedControl() ;
  if ( speedControlUs < 50 ) speedControlUs = 50 ; // can't be too low
  if ( speedControlUs != speedControlUsLast ) {
    Timer1.setPeriod( speedControlUs ) ;  // microseconds
    speedControlUsLast = speedControlUs ;

cattledog:
I don't understand this

int speedControlUs = speedControl() ;

if ( speedControlUs < 50 ) speedControlUs = 50 ; // can't be too low
  if ( speedControlUs != speedControlUsLast ) {
    Timer1.setPeriod(  speedControl() ) ;  // microseconds
    speedControlUsLast = speedControlUs ;




You appear to make an attempt to keep speedControlUs >=50 which makes sense for keeping the step speed slow enough to not stall the motor.
But then when it comes time to actually set the timer interrupt period you use the raw value of speedControl() with no lower end limitation.

I think you want



int speedControlUs = speedControl() ;
  if ( speedControlUs < 50 ) speedControlUs = 50 ; // can't be too low
  if ( speedControlUs != speedControlUsLast ) {
    Timer1.setPeriod( speedControlUs ) ;  // microseconds
    speedControlUsLast = speedControlUs ;

Oops. Yes. You are quite correct. The OP should undo that typo..
It was intended to constrain the lower value to prevent the interval being too short. If it is too short, the interrupt service routine is constantly active and the loop() doesn't run.

.