Need help to disableing a stepper motor's driver after a set period of time.

Hello, I'm Sebastian and this is my first time posting on the forum.
I need some help to solve a problem I'm currently facing while trying to develop my project.

My problem:

Can't find the proper way to disable the stepper Driver after a set period of time since the moving tray activated the rear sensor.
More specific: Rear sensor is activated - tray is stopped - wait 30 seconds - if between this 30 seconds the operator doesn't push a button to move the stepper - Driver should disable power to the motor.
Power enables automatically when the operator press a button that starts the motor in the needed direction CW or CCW

My project relates to the following:
I have build an X axis moving platform that is driven by this setup:

  • Arduino UNO R3
  • Hybrid Bipolar Stepper Motor (200 steps ;1.8 degrees; 1.4 Nm; 3.0Amp )
  • DM542A stepper Driver
  • 24V Power suply.
  • 2 HIWIN liniar guides with 4 cariages
  • ballscrew
  • pulleys and belt for the motor and ballscrew.

Attached picture of my build:

https://drive.google.com/open?id=0BwN-RXLbjBc_dDlNeExWSzJqWUE

To better understand my code here are some clarifications:

FrontSwitch - represents the Push Button that commands the tray to move to the Front Sensor
BackSwitch - represent the Push Button that returns the tray to the home position.
FrontSensor- is actually a normal Limit switch that is also used to set a flag.
RearSensor - is actually a normal Limit Switch also used for homing the tray (stepper) when the device is powered in case there was a power failure and the moving tray is not currently in it's place.
running is a boolean var that is set to true or false if motor is moving or not.

If FrontSensor is activated this also sets a flag allowing a third parity device to control the motor.

The whole thing should work by the following rule:
.Power on

  1. Check the tray to see if it is in the home position (BackSensorWasActivated = true or not).
    If not step the stepper until BackSensor activates.

  2. If BackSensor is activated (tray is in home position) begin to count for 30 seconds.
    if the operator doens't push the FrontSwitch button is this amount of 30 seconds - Arduino should disable the Driver for the stepper.

  3. If Driver is disabled and operator pushes the FrontSwitch button - Arduino enables the driver - stepper steps in the set direct direction moving the tray.

  4. Once the tray returns to the home position (BackSensor activated) driven by the third party device or by direct instruction of the operator by pushing the BackSwitch button, the counter begins to count again for 30 seconds and disable the driver.

By using the code bellow it works good only when the tray it's in home position at power on.
once the tray travels to the FrontSensor and then returns to the BackSensor - once the BackSensor gets activated the driver disables instantly. It does not wait 30 seconds.

#include <SimpleTimer.h>
// variables declared here
const byte SensorActivated = LOW;

void setup() {
  pinMode (FrontSwitch, INPUT_PULLUP);
  pinMode (BackSwitch, INPUT_PULLUP);
  pinMode (BackSensor, INPUT_PULLUP);
  pinMode (FrontSensor, INPUT_PULLUP);
  pinMode (StepPin, OUTPUT);
  pinMode (DirPin, OUTPUT);
  pinMode (EnablePin, OUTPUT);
  digitalWrite (EnablePin, LOW);
 timer1.enable(1);
}


void disableDriver(){
  digitalWrite(EnablePin, HIGH);
 
}

void loop() {
timer1.disable(1);
  BackSensorReading = digitalRead(BackSensor);
if (BackSensorReading == SensorActivated)
{
    timer1.enable(1);
  BackSensorWasActivated=true;
  FrontSensorWasActivated=false;
  TrayStopped=true;
  encoder=0;
  
 if (TrayStopped)if (!running){
    timer1.setTimeout(30000, disableDriver); // wait 30 seconds to disable timer
    timer1.run();   //start the thread.
 }
  }

FrontSensorReading = digitalRead(FrontSensor);
if (FrontSensorReading == SensorActivated)
{
  FrontSensorWasActivated=true;
  BackSensorWasActivated=false;
}
 
 
if (FrontSensorWasActivated){
      motor_position=0;

// here is the function that allows the third party device to take over control 
}

int FrontSwitchReading = digitalRead(FrontSwitch);

  // check to see if you just pressed the FrontSwitch button
  // (i.e. the input went from HIGH to LOW),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (FrontSwitchReading != LastFrontSwitchState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    // if the button state has changed:
    if (FrontSwitchReading != FrontSwitchState) {
      FrontSwitchState = FrontSwitchReading;
      
      if (FrontSwitchState == LOW){// if Front Push button was pushed and we waited long enough.
        timer1.disable(1); // stop counting, we only need to count when the moving tray stops at the back sensor
        digitalWrite(EnablePin, LOW);
      if (!FrontSensorWasActivated)
      if(running == false) {
      // digitalWrite(EnablePin, LOW);
       digitalWrite(DirPin, HIGH); // choose the right direction for the stepper to turn CW 
       driveStepper (nSteps);
      }
      }
      else return;
    }
  }

   // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastFrontSwitchState = FrontSwitchReading;

int BackSwitchReading = digitalRead(BackSwitch);

  // check to see if you just pressed the FrontSwitch button
  // (i.e. the input went from HIGH to LOW),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (BackSwitchReading != LastBackSwitchState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (BackSwitchReading != BackSwitchState) {
      BackSwitchState = BackSwitchReading;

      // only start moving the motor if the state is LOW
      if (BackSwitchState == LOW){
      if (!BackSensorWasActivated)
      if(running==false) {
     digitalWrite(DirPin, LOW);
     driveStepper(nSteps);
      }
      }
    }
  }

   // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastBackSwitchState = BackSwitchReading;
  // }

}

void driveStepper(long lnSteps){
// function to drive the stepper here
TrayStopped=false;
}

As you can see currently I'm trying to make this work by using the SimpleTimer.h library yet it doesn't works as I wanted since. It looks to me like the counter timer1 doens;t stop counting at all.

For example if I remove if (! running) in this part of code:

if (TrayStopped)if (!running){
    timer1.setTimeout(30000, disableDriver); // wait 30 seconds to disable timer
    timer1.run();   //start the thread.
 }

and make it like this:

if (TrayStopped){
    timer1.setTimeout(30000, disableDriver); // wait 30 seconds to disable timer
    timer1.run();   //start the thread.
}

the driver disable after 30 seconds even though the motor is still moving.

I have tried using milis() function comparing it to a set interval inside a while loop with no success also.
something likein this online found example:

unsigned long previousMillis = 0; // last time update
long interval = 30000; // interval at which to do something (milliseconds)

void setup(){
}

void loop(){
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
     previousMillis = currentMillis;  

     // do something
  }
}

my version looked something like this

if (TrayStopped){
while(currentMillis - previousMillis < interval) return;// do nothing
else disableDriver();

Yet this somehow freezes the microcontroller I think, as it won't take input from pushed buttons.

So if you can please help me solve this.

Regards!

The demo Several Things at a Time illustrates the use of millis() for timing.

In the last snippet of code you posted the effect is no different from using delay().

To use millis() you need to set a variable (trayWaitingTimeout = true) and record the time when the tray gets to the end. Then in each subsquent iteration of loop() the tray will stay where it is (because it is waiting for the timeout) and the code will check to see if the interval has expired. If it has it wil deactivate the motor and set trayWaitingTimeout to false.

Given your system it might be useful to have a mor complex list of states - of which 'W' (meaning "waiting timeout") is just one.

...R

Robin thank you very much for your reply.
I gave a look at the demo you provided and I got a better understanding of the millis() behaviour.
On Monday I will try to integrate your suggestion on my code and I will return and share my results.
Once I get everything working I will try to learn how to optimize the code.
As it is right now probably looks like "chopped" for the skills of a coder with great experience :slight_smile:

It's my first project on Arduino and not an easy one - it took me some time to learn how to wire things and get to understand about how a microcontroler interacts with all that hardware (butons, driver, stepper motor, etc)

My only leverage was that I studied C++ back in high school so I was kind of familiar with C++ syntax.

Kind regards!

Robin I took your advice and reorganized my code a little and also looked over the examples you provided
Yet still I'm having trouble getting the driver disabled - on my current version of code it just won't disable at all.
Yet I think I may have took a better approach this time.

My pseudo code is something like this:

I have a LastReadBackSensor variable that is declared to HIGH - sensor deactivated.

when the loop starts.

  1. check the current time by using millis() function
  2. read BackSensor
  3. If BackSensor just activated (signal went from HIGH to LOW)- the tray is stopped - I set a flag that allows to start counting in order to compare this time to the set interval.
    this flag is set only when the transition from HIGH to LOW takes place.
    In the next loop if BackSensor is still activated LastReadBackSensor will be LOW so the function to set the start time won't execute again.
  4. read FrontSensor
    5.if front sensor activated allow the third party device to take control.
    6.read buttons.
    if tray has moved BackSensor became HIGH so I record this new value into LastReadBackSensor so that in the next loop the function to disable the driver is allowed to perform once the signal goes from HIGH to LOW inside the BackSensor when the tray will stop again.

As for the actual code have a look below:

void loop() {                   // start loop
  
  currentTime=millis();         // record time in each iteration of the loop 

   currentReadBackSensor();    // read BackSensor - should return LOW if sensor is activated 
                               // the value is stored inside LastCurrentBackSensorState
  
   if (TrayInLoadPosition ){           // if moving tray is stopped in the Loading Position - rear sensor is activated
    if ((LastReadBackSensor==HIGH)&(LastCurrentBackSensorState==LOW)){  // if last read of BackSensor in the previous loop was HIGH and current read is LOW 
                                     // sensor just switched from deactivated to activated
          trayWaitingTimeout=true;  // set a flag to true in order for the checkDriverTimeout functio to be executed 
                              // flag stays true until the set interval of time has expired 
    checkDriver();            // records the start of the time needed to be compared vs the expire Interval
    }
   }
 Serial.print(startTimer);
 if (trayWaitingTimeout){     // if the flag is true checkDriverTimeout function will execute
  checkDriverTimeout();       // function checkDriverTimeout checks to see if set interval of time has expired
                              // if interval has expired the driver will be disabled and te flag is set to false
                              //  so that in the next loop the checkDriverTimeout function won't execute     
 }
 
  FrontSensorReading = digitalRead(FrontSensor);
  if (FrontSensorReading == SensorActivated)
  {
    FrontSensorWasActivated = true; // set a flag that needs to be true in order to let the program know that the tray reached the front position
                                    // from now on either the operator or the encoder will drive the motor
       }


  if (FrontSensorWasActivated)
    thirdPartyTakeOver();

  
  readForwardButton(); // function to read button to send tray to FrontSensor
  
  readLoadButton(); // function to read back button to call the tray to LoadPosition
  
  currentReadBackSensor();// read BackSensor again in order to save it's state in the LastCurrentBackSensorState variable
  
  LastReadBackSensor=LastCurrentBackSensorState; // save the result of curent BackSensor state as LastReadBackSensor 
                                                 // so that in the next loop state is LOW if tray is still in the load position - BackSensor activated
                                                 // or state is HIGH if the tray has moved and BackSensor is deactivated

} // end loop

void disableDriver() {            // start disableDriver function
  digitalWrite(EnablePin, HIGH);
  disabled = true;
}                                 // end disableDriver function

void enableDriver() {            // start enableDriver function
  digitalWrite (EnablePin, LOW);
  disabled = false;
}                               // end enableDriver function

void checkDriver() {           // start checkDriver function
   if (!disabled) {           // start if
      startTimer = millis();
      
    }                        // end if
}                            // end checkDriver function

void checkDriverTimeout() { // start checkDriverTimeout function
  if ((currentTime - startTimer) >= interval) { // if the set time interval expired
    disableDriver();           // disable the driver
    trayWaitingTimeout=false; // because driver is already disabled in the next loop skip checking the trayWaitingTimeout 
                              //eventhoug the tray will still be stoped and the BackSensor will still be activated
  }
}                             // end checkDriverTimeout function

void currentReadBackSensor() { // start readBackSensor function
  int BackSensorReading = digitalRead(BackSensor);
  if (BackSensorReading != LastCurrentBackSensorState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    // if the button state has changed:
    if (BackSensorReading != BackSensorState) {
      BackSensorState = BackSensorReading;
      if (BackSensorState == LOW){
        TrayInLoadPosition =true; 
        FrontSensorWasActivated=false;
      }
     
         }
  }

  // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastCurrentBackSensorState = BackSensorReading;
} // end readBackSensor function


void readLoadButton() { // start readLoadButton function
  int BackSwitchReading = digitalRead(BackSwitch);
  if (BackSwitchReading != LastBackSwitchState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    // if the button state has changed:
    if (BackSwitchReading != BackSwitchState) {
      BackSwitchState = BackSwitchReading;
      // only start moving the motor if the state is LOW
      if ((BackSwitchState == LOW)){
      if((digitalRead(BackSensor)!= (SensorActivated))) 
          if (running == false) {
            if(disabled) enableDriver();
            digitalWrite(DirPin, LOW);
            driveStepper(nSteps);
          }
      }
      else return;
    }
  }
  // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastBackSwitchState = BackSwitchReading;
} // end readLoadButton function

void readForwardButton() { // start readForwardButton function
  int FrontSwitchReading = digitalRead(FrontSwitch);
  if (FrontSwitchReading != LastFrontSwitchState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    // if the button state has changed:
    if (FrontSwitchReading != FrontSwitchState) {
      FrontSwitchState = FrontSwitchReading;
      // only toggle the LED if the new button state is HIGH
      if (FrontSwitchState == LOW) {
        if (digitalRead(FrontSensor)!=(SensorActivated))
           if (running == false) {
             if (disabled) enableDriver(); // if necesary enable driver
            digitalWrite(DirPin, HIGH); // Set the proper direction for the motor to turn
            driveStepper (nSteps);
          }
      }
      else return;
    }
  }
  // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastFrontSwitchState = FrontSwitchReading;
} // end readForwardButton function

I'm missing something yet I don't understand what is wrong, so I'm kindly ask you to take a look over my code and provide some help again.

Looking forward for your reply.

What about something like this

void loop() {
    readButtons();
    readSwitches();
    moveMotor();
    disableMotor();
    clearTimer();
}

void moveMotor() {
    if (motorMove == 'F') {
        // move one step forward
    }
    if (motorMove == 'R') {
        // move one step in reverse
    }
}

void readSwitches() {
    rearSwitchState = digitalRead(rearSwitch);
    frontSwitchState = digitalRead(frontSwitch);
    if (rearSwitchState == LOW) { // assumes LOW = pressed
        if (timerStarted = false) {
            disableStartMillis = millis();
            timerStarted = true;
        }
        motorMove = 'B'; // motor at Back
    }
    if (frontSwitchState == LOW) {
        motorMove = 'N'; // motor at froNt
    }
}

void disableMotor() {
    if (millis() - disableStartMillis <= disableInterval) {
        // disable Motor
        motorDisabled = true;
    }
}

void readButtons() {
    rearButtonState = digitalRead(rearButton;
    frontButtonState = digitalRead(frontButton);
    if (rearButtonState == LOW && motorMove != 'B') {
        motorMove = 'R';
    }
    if (frontButtonState == LOW && motorMove != 'N') {
        if (motorDisabled == true) {
            // enable motor
            motordisabled = false;
        }
        motorMove = 'F';
}

void clearTimer() {
        // to allow motor time to move away from the back
    if (moveMoter == 'F' && rearSwitchState == HIGH) {
        timerStarted = false;
    }
}

...R

Robin thank you very much for writing this piece of code for.
It's a lot more easy to learn from a ready made example.
It looks kind of magic to me how you swapped those variables. It's clean and simple yet I had to go over it several times to fully understand it.
It helped me a lot to better understand how I should approach my problem.

I'm really greatful that you dedicated some time to help me out.

I have tried to implement the exact code that you provided yet I run into some trouble when using the function to move the motor.
The motor moved a lot more slower then it should be.

For moving the motor I use some advanced piece of code that somebody kind enough pointed out to me.
I modified this code to suit my motors specifications and adapted to my needs

This code is using Arduino hardware timers to move the stepper motor.
It also features a liniar acceleration profile by using a trapezoidal speed ramp.
I followed approach because I need the motor to move faster and also start and stop smoother.
In case others might find it useful.
Here is the link to code for driving a stepper motor using Arduino hardware timers also featuring a trapezoidal speed ramp.

code for driving a stepper motor using Arduino hardware timers

Currently I managed to get my problem sorted, and I share my code bellow.
Yet it works only 99%.
I don't know yet what is wrong.

Is it the code itself, the backswitch (Backsensor) or how Arduino understands the code, because sometimes the driver does not disable?

I added some serial.println lines inside the code to see the values for debuging
Some times the timer just doesn't start.

Anyway here is my code it's still looking like a mess, yet I try to find some info regarding how to better optimize it.

byte LastReadBackSensor=HIGH;

void setup() {
homingstepper(); // in case of power failure step stepper back until BackSensor activates

}


void loop() {                   // start loop
  
 
   currentReadBackSensor();    // read BackSensor - should return LOW if sensor is activated 
                                         // the value is stored inside LastCurrentBackSensorState
  
  if (LastCurrentBackSensorState==LOW) Serial.println("BackSensor is activated");

  if ((LastReadBackSensor==HIGH)&&(LastCurrentBackSensorState==LOW))
    {
     if ((!disabled)&&(!timerStarted)){
      disableStartMillis = millis();
            timerStarted = true;
            }
       
    }
        if(timerStarted)
  checkDriverTimeout();
        //
    if (timerStarted) Serial.println("timer has started");
    else Serial.println("timer not started");
    
    
    
  FrontSensorReading = digitalRead(FrontSensor);
  if (FrontSensorReading == SensorActivated)
  {
    FrontSensorWasActivated = true; // set a flag that needs to be true in order to let the program know that the tray reached the front position
                                    // from now on either the operator or the encoder will drive the motor
       }


  if (FrontSensorWasActivated)
    takeControl();

  
  readForwardButton(); // function to read button to send tray to FrontSensor
  
  readLoadButton(); // function to read back button to call the tray to LoadPosition
  
  currentReadBackSensor();// read BackSensor again in order to save it's state in the LastCurrentBackSensorState variable
  
 LastReadBackSensor=LastCurrentBackSensorState; // save the result of curent BackSensor state as LastReadBackSensor 
                                                 // so that in the next loop state is LOW if tray is still in the load position - BackSensor activated
                                                 // or state is HIGH if the tray has moved and BackSensor is deactivated
if ( LastReadBackSensor== HIGH) Serial.println("BackSensor deactivated");

//clearTimer();

} // end loop

//void clearTimer() {
        // to allow motor time to move away from the back
  //  if ((running) & LastReadBackSensor == HIGH) {
    //    timerStarted = false;
    //}
//}

void currentReadBackSensor() { // start readBackSensor function
  int BackSensorReading = digitalRead(BackSensor);
  if (BackSensorReading != LastCurrentBackSensorState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    // if the button state has changed:
    if (BackSensorReading != BackSensorState) {
      BackSensorState = BackSensorReading;
      if (BackSensorState == LOW){
        FrontSensorWasActivated=false;
      }
     
         }
  }

  // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastCurrentBackSensorState = BackSensorReading;
} // end readBackSensor function


void readLoadButton() { // start readLoadButton function
  int BackSwitchReading = digitalRead(BackSwitch);
  if (BackSwitchReading != LastBackSwitchState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    // if the button state has changed:
    if (BackSwitchReading != BackSwitchState) {
      BackSwitchState = BackSwitchReading;
      // only start moving the motor if the state is LOW
      if ((BackSwitchState == LOW)){
      if((digitalRead(BackSensor)!= (SensorActivated))) 
          if (running == false) {
            if(disabled) enableDriver();
            digitalWrite(DirPin, LOW);
            driveStepper(nSteps);
          }
      }
      else return;
    }
  }
  // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastBackSwitchState = BackSwitchReading;
} // end readLoadButton function

void readForwardButton() { // start readForwardButton function
  int FrontSwitchReading = digitalRead(FrontSwitch);
  if (FrontSwitchReading != LastFrontSwitchState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    // if the button state has changed:
    if (FrontSwitchReading != FrontSwitchState) {
      FrontSwitchState = FrontSwitchReading;
      // only toggle the LED if the new button state is HIGH
      if (FrontSwitchState == LOW) {
        if (digitalRead(FrontSensor)!=(SensorActivated))
           if (running == false) {
             if (disabled) enableDriver(); // if necesary enable driver
            digitalWrite(DirPin, HIGH); // Set the proper direction for the motor to turn
            driveStepper (nSteps);
          }
      }
      else return;
    }
  }
  // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastFrontSwitchState = FrontSwitchReading;
} // end readForwardButton function

void disableDriver() {            // start disableDriver function
  digitalWrite(EnablePin, HIGH);
  disabled = true;
}                                 // end disableDriver function

void enableDriver() {            // start enableDriver function
  digitalWrite (EnablePin, LOW);
  disabled = false;
}                               // end enableDriver function


void checkDriverTimeout() { // start checkDriverTimeout function
  if (millis() - disableStartMillis >= interval) { // if the set time interval expired
    disableDriver();           // disable the driver
     // because driver is already disabled in the next loop skip checking the trayWaitingTimeout 
                              //eventhoug the tray will still be stoped and the BackSensor will still be activated
  }
  if(disabled) timerStarted=false;
}                             // end checkDriverTimeout function

Once again thank you very much for your kind support.

If you think you can help me further by finding a better approach let me know.

for example one of early variants for the code was like this:

 if ((LastReadBackSensor==HIGH)&(LastCurrentBackSensorState==LOW))
    {
     if ((!disabled)if(!timerStarted)){
      disableStartMillis = millis();
            timerStarted = true;
            }
       
    }

Yet this variant doesn't work if I use only "&" instead of "&&" in the first line of code
or "if" instead of "&&" in the second line it doesn't work.
I got lucky by trying to modify those condition because I just could not understand why the code would not work even though the logic (pseudo code ) looked fine to me.

If you post your complete program I will look at it. It is too difficult to try to join the dots between my suggestion in Reply #4 and the various comments you have in Reply #5.

...R

Hello again Robin, here is my code:

part1:

#define sbi(sfr,bit)  ( sfr |=   _BV(bit)  )         // a l'antiga manera. cbi() i sbi() son funcions obsoletes
#define cbi(sfr,bit)  ( sfr &= ~(_BV(bit)) )
const byte EnablePin = 4; // Driver enable/disable pin
const byte StepPin = 6;  // Step pin
const byte DirPin = 7; // Direction for stepper pin
const byte SensorActivated = LOW;  // Limit switch grounds pin
const byte FrontSensor = 10; // FrontSensor Pin 
const byte FrontSwitch = 12;    // FrontButton pin - pressing it will move the tray forward
const byte BackSensor = 11; //  BackSensor Pin 
const byte BackSwitch = 9; // RearButton pin - pressing it will move the tray backward to load position
int BackSwitchState;
byte LastBackSwitchState = HIGH;
byte FrontSwitchState;
byte LastReadBackSensor=HIGH;
int FrontSensorState;// the current reading from the input pin
int LastFrontSwitchState = HIGH;
int LastFrontSensorState = HIGH;// the previous reading from the input pin
int a = 0;
int b = 0; // all this added to bypass id.exe compiler error
int c = 0;
int d = 0;
int FirstBackSensorReading;
int LastFirstBackSensorReading = HIGH;
boolean FrontSensorWasActivated = false;
boolean BackSensorWasActivated = false;
boolean timerStarted = false;
unsigned long startTimer;
unsigned long disableStartMillis;
unsigned long interval = 10000;
byte LastBackSensorReading = HIGH;
byte LastCurrentBackSensorState;
byte LastBackSensorState;
byte BackSensorState;
boolean disabled = false;
int BackSensorReading;
int FrontSensorReading;
// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers
float microStepping = 8;                             // Driver setup 1/8  1600 microsteps
long stepsPerRev = 200;                              // Stepper motor type 200 rot x 1.8 degrees
float l = 2.4;                                        //  motor's inductance as resulted from the datasheet
float v = 24;                                        // motor's power supply voltage
float iMax = 1.5;                                  // 1 bobine amps (3A /2bobines = 1.5 A / bobin)
// amb la EasyDriver podem controlar iMax abm el potenciòmetre

float ocr2a;                                         // valor de OCR2A ( que depèn de la velocitat màxima del Stepper )
int ocr2aIni;                                        // valor inicial de OCR2A donada l'acceleració

int accelDuring = 16800;                                // Steps for accelerating/decelerating

int downCounter = accelDuring;                       // el nombre d'Steps que falten fins acabar la desacceleració
int upCounter = accelDuring;                         // el nombre d'Steps que falten fins acabar l'acceleració
int accelDelta;                                      // valor en que varia OCR2A durant l'acceleració
// ( p.e. si ha de pasar de 255 a 19 en 10 steps decremeta de 23 en 23 i começa a 249 )

long stepsLeft = 0;                                  
boolean running = false;
long nSteps = 114000;                                 // total number of steps between BackSensor and FrontSensor
volatile long motor_position;

void setup() { // start setup
  pinMode (FrontSwitch, INPUT_PULLUP);
  pinMode (BackSwitch, INPUT_PULLUP);
  pinMode (BackSensor, INPUT_PULLUP);
  pinMode (FrontSensor, INPUT_PULLUP);
  pinMode (StepPin, OUTPUT);
  pinMode (DirPin, OUTPUT);
  pinMode (EnablePin, OUTPUT);
  digitalWrite (EnablePin, LOW);
  unsigned int usDelay;                              // temps d'espera entre Steps en us

  Serial.begin(9600);
  usDelay = l * 2000 * iMax / v / microStepping;     // temps d'espera entre steps en microsegons  ( T= L*Imax*2/V (T miliSegons/step) )
  //ocr2a = ceil((float)usDelay / 8.0);                // l'enter mes proper donat l'interval del Timer2 ( 8 us )
  ocr2a = 11;                                     // maximum pulse width between steps that my motor can use


  if (accelDuring > 0) {
    accelDelta = (255 - int(ocr2a) ) / accelDuring;  // OCR2A pasarà del enter mes proper a 255 fins a ocr2a
    // el valor que hem calculat per la velocitat màxima
    //Serial.println(accelDelta);

    if (accelDelta <= 0) {
      if (ocr2a < 255) {                             // la durada de l'acceleració no pot ser tan gran com esperem
        accelDelta = 1;
        ocr2aIni = 255;
        accelDuring = 255 - ocr2a;                   // durada màxima de l'acceleració permesa

      } else {                                        // ocr2a = 255, no hi pot haver acceleració
        accelDelta = 0;
        accelDuring = 0;
        ocr2aIni = ocr2a;
      }

    } else                                            // acceleració segons la definició
      ocr2aIni = ocr2a + accelDelta * accelDuring;   // calcula el OCR2A inicial donada l'acceleració

  } else                                              // no hi ha acceleració
    ocr2aIni = ocr2a;

  setTimer2(ocr2aIni);

  long nVoltes = 1;
 
  do                               // start homing the stepper only if BackSensor is not activated 
                                   // tray is not stopped in LoadPosition at system startup
  {
    FirstBackSensorReading = digitalRead(BackSensor);
    if ((FirstBackSensorReading == LOW) && (LastFirstBackSensorReading == HIGH))
    {
      BackSensorWasActivated = true;
      return;
    }
    else {
      if ((FirstBackSensorReading == HIGH) && (LastFirstBackSensorReading == HIGH)) {
        digitalWrite(DirPin, LOW);
        digitalWrite(StepPin, HIGH);
        digitalWrite(StepPin, LOW);
        delayMicroseconds(200); // delay between pulses, alter to modify speed --- need to modify this not to use delay anymore
      }
      LastFirstBackSensorReading = FirstBackSensorReading;

    }
  }
  while (digitalRead(BackSensor) != SensorActivated);

} // end setup

second part of my code:

void loop() {                   // start loop
  
  //currentTime=millis();         // record time in each iteration of the loop 

   currentReadBackSensor();    // read BackSensor - should return LOW if sensor is activated 
                               // the value is stored inside LastCurrentBackSensorState
  
  if (LastCurrentBackSensorState==LOW) Serial.println("timer has started");
//   if (TrayInLoadPosition ){           // if moving tray is stopped in the Loading Position - rear sensor is activated
    if ((LastReadBackSensor==HIGH)&&(LastCurrentBackSensorState==LOW))
    {
     if ((!disabled)&&(!timerStarted)){
      disableStartMillis = millis();
            timerStarted = true;
            }
       
    }
        if(timerStarted)
  checkDriverTimeout();
        //
    if (timerStarted) Serial.println("timer has started");
    else Serial.println("timer not started");
    
      

  FrontSensorReading = digitalRead(FrontSensor);
  if (FrontSensorReading == SensorActivated)
  {
    FrontSensorWasActivated = true; // set a flag that needs to be true in order to let the program know that the tray reached the front position
                                    // from now on either the operator or the encoder will drive the motor
       }


  if (FrontSensorWasActivated)
  takeControl();

  
  readForwardButton(); // function to read button to send tray to FrontSensor
  
  readLoadButton(); // function to read back button to call the tray to LoadPosition
  
  currentReadBackSensor();// read BackSensor again in order to save it's state in the LastCurrentBackSensorState variable
  
 LastReadBackSensor=LastCurrentBackSensorState; // save the result of curent BackSensor state as LastReadBackSensor 
                                                 // so that in the next loop state is LOW if tray is still in the load position - BackSensor activated
                                                 // or state is HIGH if the tray has moved and BackSensor is deactivated
if ( LastReadBackSensor== HIGH) Serial.println("BackSensor deactivated");

} // end loop


void currentReadBackSensor() { // start readBackSensor function
  int BackSensorReading = digitalRead(BackSensor);
  if (BackSensorReading != LastCurrentBackSensorState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (BackSensorReading != BackSensorState) {
      BackSensorState = BackSensorReading;
      if (BackSensorState == LOW){
        FrontSensorWasActivated=false;
      }
     
         }
  }

  // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastCurrentBackSensorState = BackSensorReading;
} // end readBackSensor function


void readLoadButton() { // start readLoadButton function
  int BackSwitchReading = digitalRead(BackSwitch);
  if (BackSwitchReading != LastBackSwitchState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (BackSwitchReading != BackSwitchState) {
      BackSwitchState = BackSwitchReading;
      // only start moving the motor if the state is LOW
      if ((BackSwitchState == LOW)){
      if((digitalRead(BackSensor)!= (SensorActivated))) 
          if (running == false) {
            if(disabled) enableDriver();
            digitalWrite(DirPin, LOW);
            driveStepper(nSteps);
          }
      }
      else return;
    }
  }
  // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastBackSwitchState = BackSwitchReading;
} // end readLoadButton function

void readForwardButton() { // start readForwardButton function
  int FrontSwitchReading = digitalRead(FrontSwitch);
  if (FrontSwitchReading != LastFrontSwitchState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
     if (FrontSwitchReading != FrontSwitchState) {
      FrontSwitchState = FrontSwitchReading;
      // only toggle the LED if the new button state is HIGH
      if (FrontSwitchState == LOW) {
        if (digitalRead(FrontSensor)!=(SensorActivated))
           if (running == false) {
             if (disabled) enableDriver(); // if necesary enable driver
            digitalWrite(DirPin, HIGH); // Set the proper direction for the motor to turn
            driveStepper (nSteps);
          }
      }
      else return;
    }
  }
  // save the reading.  Next time through the loop,
  // it'll be the LastSwitchButtonState:
  LastFrontSwitchState = FrontSwitchReading;
} // end readForwardButton function

void disableDriver() {            // start disableDriver function
  digitalWrite(EnablePin, HIGH);
  disabled = true;
}                                 // end disableDriver function

void enableDriver() {            // start enableDriver function
  digitalWrite (EnablePin, LOW);
  disabled = false;
}                               // end enableDriver function


void checkDriverTimeout() { // start checkDriverTimeout function
  if (millis() - disableStartMillis >= interval) { // if the set time interval expired
    disableDriver();           // disable the driver
     // because driver is already disabled in the next loop skip checking the trayWaitingTimeout 
                              //eventhoug the tray will still be stoped and the BackSensor will still be activated
  }
  if(disabled) timerStarted=false;
}                             // end checkDriverTimeout function

void takeControl(){
  // to be coded
}

void driveStepper(long lnSteps) { // start of driveStepper function
  lnSteps = abs(lnSteps); // number of steps no longer need to use abs as we won't use negative values, just chage direction for the motor
  OCR2A = ocr2aIni;                // reinicialitza el contador (permet acceleració)
  upCounter = accelDuring;
  downCounter = accelDuring;
  running = true;
  stepsLeft = lnSteps;
  motor_position = lnSteps - stepsLeft;
}// end of driveStepper function

void setTimer2(int lusDelay) {

  cli();                           // plana 10. Bit 7 Clear interrupts

  cbi(TCCR2A, COM2A0 );            // plana 158. Table 17-2. Normal port operation, OC0A disconnected.
  cbi(TCCR2A, COM2A1 );            // 00 deconecta el pin A del timer2

  cbi(TCCR2A, WGM20  );            // TCCR2A Regitre A de control del timer 2
  sbi(TCCR2A, WGM21  );       // plana 160 i 149. Clear Timer on Compare
  cbi(TCCR2B, WGM22  );            // WGM2 = 010 ==> mode of operation Clear Timer on Compare (CTC)
  sbi(TCCR2B, CS22   );            // TCCR2B Regitre B de control del timer 2
  cbi(TCCR2B, CS21   );       // Plana 162
  sbi(TCCR2B, CS20   );            // CS2 = 101 prescaler = 128 ==> 128/16.000.000 = 0.000008 s-1 = 8us-1
  // màxim temps que es pot contar = 8 * 255 = 2040 us

  sbi(TIMSK2, OCIE2A  );           // Timer2 Output Compare Match A Interrupt Enable. plana 163

  cbi(ASSR, AS2);              // AS2 = 0 clocked from the I/O clock
  
  OCR2A = lusDelay;                //  si p.e. OCR2A = 21 --> 21*0.000008 = 168us-1  . cridem la funcio un cop cada 168 us. plana 162

  TCNT2 = 0;                       // reset Timer2 counter

  sei();                           // Enable Interrupts
}////


void stopTimer2() {
  cbi(TIMSK2, OCIE2A  );           // Timer2 Output Compare Match A Interrupt Disable. plana 163
}////

ISR(TIMER2_COMPA_vect) {           // Timer2 Output Compare Match A Interrupt
  // definició dels vectors a Arduino\hardware\tools\avr\avr\include\iom328p.h
  // definitions for ATmega328P
  if (stepsLeft > 0) {
    if (stepsLeft == downCounter) { // ha de desaccelerar
      downCounter--;
      OCR2A += accelDelta;         // incrementa el temps entre Steps en CS22:0 us (el proper Step es produirà 8 us mes tard)
    }
    else if (upCounter > 0) {      // ha d'accelerar
      upCounter--;
      OCR2A -= accelDelta;         // decrementa el temps entre Steps en CS22:0 us (el proper Step es produirà 8 us abans)
    }
    digitalWrite(StepPin, HIGH);  // envia el pols a la EasyDriver per avançar 1 Step
    digitalWrite(StepPin, LOW);   // A low-to-high transition on the STEP input sequences the translator
    stepsLeft--;
  }
  else                             // para el motor
    running = false;

}////

n00b007:
I have tried to implement the exact code that you provided yet I run into some trouble when using the function to move the motor.
The motor moved a lot more slower then it should be.

If the code in Replies #7 and #8 represents your attempt to implement "the exact code that you provided" all I can say is I'm glad you were not trying to make your code really different.

When something is not behaving the first thing to do is simplify. I can't think of anything in my suggested code that would affect the speed of the motor.

I presume you did try a version of my code. If so post that and let's see if we can get it to work as you require.

...R

Hello again Robin.

I rebuild my code by using your example, as I did not save the trial build before (the one that was moving a lot slower).

I have rebuilt all again but now but this version doesn't work at all.
The only thing that works is the driver that will disable after the set period of time.
Yet nothing happens when I press the buttons.
The buttons works as if I add Serial.println to monitor if a butonState is High or LOW is will display correctly.
Yet it seems that the moveMotor variable doesn't store F or R.

If a add direct instruction to move the motor here it will move the motor

void readFrontButton() {// start reading frontButton 
  int FrontButtonReading = digitalRead(frontButton);
  if (FrontButtonReading != LastFrontButtonState) {
     lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
        if (FrontButtonReading != FrontButtonState) {
      FrontButtonState = FrontButtonReading;
      if (FrontButtonState == LOW ) 
      {
        digitalWrite(DirPin, HIGH); // this works
        driveStepper(nSteps);
                      
        }
       
} 
               }
  }
   LastFrontButtonState = FrontButtonReading;
   // end reading frontButton 
}

Anyway in case you still want to be bothered by my problem and still have time to help me out here is the code.
I like your code very much and I would like to integrate as it is a lot more simple and logic, yet I'm having difficulties as I'm just a noob.

// start loop
void loop() {
   readFrontButton();
    readRearButton();
    readSwitches();
    moveMotor();
    disableMotor();
    clearTimer();
}
// end loop

void driveStepper(long lnSteps) { // start of driveStepper function move tray to front
  lnSteps = abs(lnSteps);
  OCR2A = ocr2aIni;                // reinicialitza el contador (permet acceleració)
  upCounter = accelDuring;
  downCounter = accelDuring;
  running = true;
  stepsLeft = lnSteps;
  motor_position = lnSteps - stepsLeft;
}// end of driveStepper function

void moveMotor() {
    if (motorMove == 'F') {
      digitalWrite(DirPin,HIGH);
        driveStepper(nSteps);// move motor to front the required number of steps
    }
    if (motorMove == 'R') {
       digitalWrite(DirPin,LOW);
        driveStepper(nSteps);// move motor to back the required number of steps
    }
}

void readSwitches() {
    rearSwitchState = digitalRead(rearSwitch);
    frontSwitchState = digitalRead(frontSwitch);
    if (rearSwitchState == LOW) { // assumes LOW = pressed
        if (timerStarted = false) {
            disableStartMillis = millis();
            timerStarted = true;
        }
        motorMove = 'B'; // motor at Back
    }
    if (frontSwitchState == LOW) {
        motorMove = 'N'; // motor at froNt
    }
}

void disableMotor() {
    if (millis() - disableStartMillis >= disableInterval) {
        digitalWrite(EnablePin, HIGH);// disable Motor
        motorDisabled = true;
    }
}


void readFrontButton() {// start reading frontButton 
  int FrontButtonReading = digitalRead(frontButton);
  if (FrontButtonReading != LastFrontButtonState) {
     lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
        if (FrontButtonReading != FrontButtonState) {
      FrontButtonState = FrontButtonReading;
      if (FrontButtonState == LOW && motorMove != 'N') 
      {
        if (motorDisabled == true) {
            digitalWrite(EnablePin, LOW);// enable motor
            motorDisabled = false;
                      
        }
        motorMove = 'F';
} 
               }
  }
   LastFrontButtonState = FrontButtonReading;
   // end reading frontButton 
}

 void readRearButton(){  // start reading rearButton 
int RearButtonReading = digitalRead(rearButton);
  if (RearButtonReading != LastRearButtonState) {
      lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
        if (RearButtonReading != RearButtonState) {
      RearButtonState = RearButtonReading ;
      if (RearButtonState == LOW && motorMove != 'B') {
        motorMove = 'R';
    }
          }
  }
    LastRearButtonState = RearButtonReading;
   //end reading rearButton
 }
   

//}
void clearTimer() {
        // to allow motor time to move away from the back
    if (motorMove == 'F' && rearSwitchState == HIGH) {
        timerStarted = false;
    }
}

@n00b007, please provide a complete program so I can try and compile it myself. Snippets are just a waste of time - the problem is usually elsewhere.

...R

Hey Robin here I attach the .ino file.

ocr2a = 11; 11us is the maximum delay between pulses that my motor can support.

nSteps is the variable for the number of steps that motor should execute = the actual distance between front and rearsensor

Once again thank you very much.

Robin2_test.ino (11.4 KB)

n00b007:
Hey Robin here I attach the .ino file.

Thanks. I will look at your program later today.

Please do not use my name for the name of your program - use your own name!

ocr2a = 11; 11us is the maximum delay between pulses that my motor can support.

This is nonsense (I am being polite). You could have a delay between pulses running to months or years.

...R

Thank you again Robin, please do not feel offended in anyway, be sure that my words truly express my gratitude regarding your help

I write and usually understand very well in English yet sometimes I express myself wrong, as English is not my native language.

That ocr2a variable if is set to a lower value then 11 (ex.10 or 9 or lower) will make my motor to produce a high noise and stall.

n00b007:
That ocr2a variable if is set to a lower value then 11 (ex.10 or 9 or lower) will make my motor to produce a high noise and stall.

Then I think you meant to say

11us is the maximum minimum delay between pulses that my motor can support

I have now had a chance to look at your Program in Reply #12. I am having great difficulty relating your 307 lines of code to my 60 lines - even acknowldeging that my code was not complete.

If you look at the motorMove() function in my code you will see that it is intended to move the motor a single step. Your code, on the other hand moves it 114000 steps.

Everytime (without exception, I believe) that I have had a problem with a program the solution involved significant simplification. I have a strong feeling that you need to simplify.

What interval (in millsecs or microsecs) do you wish to have between your steps?

From what others have said I believe the code in the second example in Simple Stepper Code is capable of very high step rates.

...R

Hello Robin, I wanted to use acceleration and deceleration for my motor, this is way I can't step a single step at a time or I don't know how to integrate this in the moveMotor() function.
I also tried the accelStepper library yet the speed is limited.

If I set my motor pulses interval to as low as 11 us then it's like I'm driving a car that starts at let's say 100km/h and also stops instantly at that speed, this will shake the internal of the motor, or it won't start at all that speed.

Here are some explinations that do not belong to me, yet I found online:

The truth is that stepper-motor motion needs to be actuated through acceleration and deceleration profiles
more than any other motor topology. Trying to start at any speed may have dire effects.

Figure 1 shows a motor manufacturer’s conventional stepping rate/torque curve with an important parameter, fs , called the starting frequency. It must be understood that, for this particular motor to start properly, a stepping rate smaller than fs must be employed. To start the motor with a stepping rate larger than fs may induce the motor to stall and lose synchronization. Once this happens, motion control is severely compromised. This appears to be a major problem but actually can be solved quite easily. All that is
needed is to start the motor at a stepping rate below fs and then increase the speed until the target speed is reached. Following this guideline, the stepper motor can be actuated with stepping rates far exceeding fs
—as long as the speed is kept below the shown torque/speed curve.Equally important, one should not ttempt to stop the motor simply by halting the STEP pulses. Instead, the stepping rate should be decreased from the target speed to a lower rate at which the motor can stop without the shaft inertia inducing extra and unwanted steps. Remember that if the stepper is being utilized in a positioning applica-tion, the motor shaft can lose position if it keeps on moving after it should have stopped.

Anyway here is the whole article:

Thank you for taking your time to help. If it wasn't for you I don't know if I would have managed to get it work even my complicated and scrambled way.
Kind regards!

n00b007:
Hello Robin, I wanted to use acceleration and deceleration for my motor, this is way I can't step a single step at a time or I don't know how to integrate this in the moveMotor() function.
I also tried the accelStepper library yet the speed is limited.

If I set my motor pulses interval to as low as 11 us then it's like I'm driving a car that starts at let's say 100km/h and also stops instantly at that speed, this will shake the internal of the motor, or it won't start at all that speed.

I understand that.

But the question you have posed here is different. Deal with the problem you have posed here using slow stepper speeds. When that works reliably you can add the extra stuff for acceleration and expect the whole to work.

Nobody deals with a complex computer program as a single thing. It is a collection of pieces (functions) that are designed to work together and are also capable of being developed and tested in isolation. This is illustrated in Planning and Implementing a Program

...R

Thanks Robin, I will follow your tutorial to get a better understanding of programing.
Once I get it all sorted will post again here.