Need help in Interrupt function and AccelStepper

Hi Everyone,
I am doing a project based on stepper motor which works with AccelStepper. I have to reset it's last position to 0 using limit switch(motor moves backward until it reaches switch after power cut or reset in Arduino). So i used attachInterrupt() function to stop the motor when its reaches the limit switch.

First problem, i have to move my control flow from void motor_stop() to void loop() when motor reaches 0th position(limit switch==LOW). But IT STAYS IN void motor_stop() . Because the interrupt signal doesn't go until it becomes HIGH. The motor prevents switch from releasing because motor stops when limit switch is reached which results trigger in interrupt pin.

Second problem is , the motor runs slowly while moving backward by one step.

Kindly give some solution to this problem and Thanks in advance.

#include <AccelStepper.h>
#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>

#define DIR_PIN 4
#define STEP_PIN 3
const byte LIMIT_SWITCH=2;
#define RESET_SWITCH 8
#define CYCLE_SWITCH 9

const int STEPS_PER_REVOLUTION = 6400;

AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
LiquidCrystal_I2C lcd(0x27, 20, 4);

int val = 0;
int reposition = 0;

volatile int event=0;
void motor_stop();
void setup() {
  lcd.init();
  lcd.backlight();
  Serial.begin(9600);

  Serial.println("STARTED");
  stepper.setMaxSpeed(1000); // Increase the maximum speed here
  stepper.setAcceleration(500);

  
  pinMode(CYCLE_SWITCH, INPUT_PULLUP);
  pinMode(RESET_SWITCH, INPUT_PULLUP);
  pinMode(LIMIT_SWITCH, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(LIMIT_SWITCH), motor_stop, LOW);
//check the limit switch 
  if(event == 0){
    
     while (digitalRead(LIMIT_SWITCH) == HIGH && event!=1 ) {   
         Serial.print("\nwhile event:");
         Serial.println(event);
         moveBackward(1);
          if(event == 1){
             break;
          }
      }
      //event=0;
  }
  stepper.setCurrentPosition(0);
}

void loop() {
 
  val = digitalRead(CYCLE_SWITCH);
  reposition = digitalRead(RESET_SWITCH);

  

  Serial.println("WAITING");
  lcdPrint("STATIC", "STATUS: WAITING");

  
 if (val == LOW) {
    Serial.println("cycle");
    lcdPrint("****STARTING PROCESS****", "PROCESS STARTED");
    delay(2000);
   
    lcdPrint("MOVING TO 80.62 V", "DEGREE: 80.62");
    moveToDegree(-80.62);
    delay(2000);
    
    lcdPrint("MOVING TO 113.3 V", "DEGREE: 113.3");
    moveToDegree(-113.3);
    delay(2000);
    
    lcdPrint("MOVING TO 238.3 V", "DEGREE: 238.3");
    moveToDegree(-238.3);
    delay(2000);
    
    lcdPrint("MOVING TO 273.3 V", "DEGREE: 273.3");
    moveToDegree(-273.3);
    delay(2000);
    
    lcdPrint("MOVING TO 293.3 V", "DEGREE: 293.3");
    moveToDegree(-293.3);
    delay(2000);
    
    lcdPrint("MOVING TO 238.3 V", "DEGREE: 238.3");
    moveToDegree(-238.3);
    delay(2000);

    lcdPrint("****PROCESS COMPLETED****", "****CONGRATS****");
    delay(2000);
  } 

  else  if (reposition == LOW) {
    Serial.println("230");
    moveToDegree(-238.3);
    lcdPrint("MOVING TO 230 V", "VOLTAGE : 230");
    delay(2000);
  }
  
  else if (val == HIGH) {
    lcdPrint("Switch is OFF", "SWITCH STATE : OFF");
    delay(2000);
  }
}

void moveToDegree(float degree) {
  float gearRatio = 1.2;
  float steps = (degree / 360.0) * STEPS_PER_REVOLUTION * gearRatio;
  stepper.moveTo(steps);
  Serial.print("steps:");
  Serial.println(steps);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
  }
}

void moveBackward(float degreeChange) {
  float gearRatio = 1.2;
  float stepsBackward = (degreeChange / 360.0) * STEPS_PER_REVOLUTION * gearRatio;
  stepper.move(stepsBackward); // Note the negative sign to move backward
  Serial.print("stepsBackward:");
  Serial.println(stepsBackward);
  while (stepper.distanceToGo() != 0) {
    stepper.run();
  }
  Serial.print("backward event:");
  Serial.println(event);
}

void lcdPrint(String line1, String line2) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(line1);
  lcd.setCursor(0, 1);
  lcd.print(line2);
  delay(2000);
}

void motor_stop(){
  stepper.stop();
  event=1;
  Serial.print("stop event:");
  Serial.println(event);
}

Then the code is working EXACTLY right! And when you find the switch take ONE STEP in the opposite direction and that is the zero position and you regular code can begin.

Using LOW as the mode will cause the interrupt to repeatedly fire over and over again as long as the limit switch is closed. If you use FALLING then it will only fire once when the pin first changes.

Code is partially working.

  1. It moves in backward by one step but slowly. Approximately it takes 1-1.5 minutes to complete max-min distance.
    2)But when it reaches 0 it wont move until the switch release. when the switch was released only the regular code works.

Right, because the interrupt is firing every other line of code and stopping it. You should only let that interrupt fire once when the switch makes contact. You should make it so motor_stop only happens once. Not over and over again.

Yes sir, you're correct. So, I tried FALLING instead of LOW as you instructed. It sets event=1 after interrupt occurs and successfully moved to void loop(). Thank you so much for that.
But, when i press reset button in Arduino still the event = 1. That's not setting to event =0.

Is the limit switch making contact when you reset? FALLING will not create an interrupt if the level is already LOW when the code starts. You may want to add code in setup to test for that condition.

No sir, Limit switch is not in contact while resetting. But it works when i plug in and out the Arduino.

Are you saying that the power cycle works differently than the reset button in regards to the value of event on startup?

How have you determined this?

Sir I used the serial monitor to view the value of event. At start of code the event =0, If I interrupt the event becomes event =1. If I reset I get event =1 instead of event=0. But when I unplugged and plug in the event becomes event=0.

Why using an interrupt at all? You have a while loop where you step your motor towards the limit switch, and you check your limit switch within the while loop. That is totally sufficent. The interrupt is completely useless.
Beginners tend to see interrupts as the solution to many problems. However, they are only really necessary in rare cases. Used incorrectly, they cause more problems than they solve. E.g. you must not use Serial.print within an ISR.

Sir I already used within the while loop. But if I use step as 10, motor moves by 10,10 and so on. If my limit switch is at 5th step it checks the condition after finishing 10th step only. So only I've used interrupt. I am a beginner to Arduino to sir. So please guide me.

Hello dhanushtd

Welcome to the worldbest Arduino forum ever.

I´ve made a small code review.

If you expect a realtime behaiviour of the program you have to get rid of the delay() function. This function blocks the execution.

	Line  66:     delay(2000);
	Line  70:     delay(2000);
	Line  74:     delay(2000);
	Line  78:     delay(2000);
	Line  82:     delay(2000);
	Line  86:     delay(2000);
	Line  90:     delay(2000);
	Line  93:     delay(2000);
	Line 100:     delay(2000);
	Line 105:     delay(2000);
	Line 139:   delay(2000);

Design and code your own none-blocking timer function by using the BlinkWithoutOut example of the IDE.

All in all an interrupt call is´nt necessary to stop a motor.

Have a nice day and enjoy coding in C++.

That is exactly why you need to first test the switch and then move ONE! STEP closer and repeat.

Yes. I did not look closely at your code. Move a step, not a degree.

moveBackward(1);
void moveBackward(float degreeChange) {

As said, the interrupt is completely useless if you read the switch and move the one step in the while loop.

There may be some bounce in the limit switch and there may be a pending interrupt flag when you restart the program. Both reset and power cycle should reset the registers, so there is some sort of mystery. Don't use the interrupt and the issue will go away.

What are the changes have to make the code to work.

Did we not tell you the changes you need to make? This is not a code writing service.

Sir I sincerely appreciate your efforts to help others. But i didn't ask you to write complete code or the code. I just asked to where to make changes. I really don't know that much you know about Arduino. As a experienced person you have more knowledge than me. That's not mean that all of us have same knowledge like you. Not all are the same. Thanks for spending your precious time to think of my code. I will truly say I am not a pro, I am a beginner. I just wanna know how to work the code. In that way if I make you think i am bad, i am sorry. Once again, appreciate your work.

Did you get rid of the interrupt code, as suggested?

Learn by doing. Forum members have told you about some changes to be made, so make those changes and try the program.

If it does not do what you want and you don't know how to fix the code, post the revised code, using code tags, and explain the problem. People will be happy to help.

1 Like