Stepmotor how to break a loop

Hi there,
I am trying to make a roller blind using arduino nano and 28byj stepmotor with accelstepper library and ir remote.
Ir remote will use 4 buttons that will function as ;

  • roll the blind up
  • roll the blind down
  • stop the roll up or down functions
  • save the max and min positions and save the data to eeprom.

When i push the roll the blind up button, I also want to stop the motor while pressing the stop button. But it does not work. I need help on this.

Below is the code.

// Include the AccelStepper Library
#include <AccelStepper.h>
#include <EEPROM.h>
#include <IRremote.hpp>

// define constants for IR remote control buttons
#define DECODE_NEC
#define IR_RECEIVE_PIN 11
#define BUTTON_UP   0x7 //0xFFA857
#define BUTTON_DOWN 0x15 //0xFFE01F
#define BUTTON_SET  0x46 //0xFF629D
#define BUTTON_STOP 0x9 //0xFF906F
#define BUTTON_RESET 0x52 //0xFF4AB5

// Define IR sensor pins
#define IR_RECEIVE_PIN 11

// Define step constant
// Creates an instance
// Pins entered in sequence IN1-IN3-IN2-IN4 for proper step sequence
#define FULLSTEP 4
AccelStepper stepper(FULLSTEP, 2, 4, 3, 5);
bool moving = false;

// Define EEPROM addresses for storing maximum and minimum positions
#define EEPROM_ADDR_MAX_POSITION 50
#define EEPROM_ADDR_MIN_POSITION 0

    
  // define variables for saving the maximum and minimum positions
  unsigned long maxPos;
  unsigned long minPos;  
  long testPos;

void(* resetFunc) (void) = 0;

void setup() {
  Serial.begin(115200);
  delay(100);

  // set the maximum speed, acceleration factor,
	// initial speed and the target position
	stepper.setMaxSpeed(500.0);
	stepper.setAcceleration(50.0);
	stepper.setSpeed(200.0);  

  // Start the IR receiver
    IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
    Serial.print(F("Ready to receive IR signals of protocols: "));
    printActiveIRProtocols(&Serial);


  maxPos = EEPROM_readlong(EEPROM_ADDR_MAX_POSITION);
  minPos = EEPROM_readlong(EEPROM_ADDR_MIN_POSITION);  
  Serial.println("maxPos EEPROM: " + String(maxPos));
  Serial.println("minPos EEPROM: " + String((minPos)));
  testPos = -minPos;
  Serial.println("testPos EEPROM: " + String((testPos)));

// check if the maximum position has been set
if (isnan(maxPos) | (maxPos == 0)) {  
  Serial.println("maxPos 0 ya da bilgi yok");
  maxPos = 99999;  
  EEPROM_writelong(EEPROM_ADDR_MAX_POSITION, maxPos);
  Serial.println("maxPos:" + String(maxPos));
}

// check if the minimum position has been set
if (isnan(minPos) | (minPos == 0)) { 
  Serial.println("minPos 0 ya da bilgi yok");
  minPos = 99999;
  EEPROM_writelong(EEPROM_ADDR_MIN_POSITION, minPos);
  Serial.println("minPos:" + String(minPos));
}


}
void loop() {

receive_ir_data();

}

void receive_ir_data() {
    // check if there is an IR code available
  if (IrReceiver.decode()) {
    
        /*
      * Print a short summary of received data
      */
    IrReceiver.printIRResultShort(&Serial);
    IrReceiver.printIRSendUsage(&Serial);
    if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
        Serial.println(F("Received noise or an unknown (or not yet enabled) protocol"));
        // We have an unknown protocol here, print more info
        IrReceiver.printIRResultRawFormatted(&Serial, true);
    }
    Serial.println();
    
    //IrReceiver.resume(); // Enable receiving of the next value

    //Serial.println(stepper.currentPosition());
    //Serial.println(minPos);
    //Serial.println(maxPos);
    
    // check which button was pressed on the remote    
    switch(IrReceiver.decodedIRData.command) {
            
      case BUTTON_UP:
      // move the roller blind up
      
      if (stepper.currentPosition() < maxPos ) {               
        stepper.moveTo(maxPos);   
        while (stepper.distanceToGo() != 0) {
        IrReceiver.resume();
       
        Serial.println(String(IrReceiver.decodedIRData.command));
        if (IrReceiver.decodedIRData.command == BUTTON_STOP) {
        // Stop the stepper motor
        stepper.stop();
        break;
        }
        stepper.run();
        } 
        stopPowerToCoils();
      }

        break;
      case BUTTON_DOWN:
        // move the roller blind down
        if (stepper.currentPosition() > (testPos)) { 
          
         while (stepper.currentPosition() > (testPos)) {    
           
          Serial.println(stepper.currentPosition());   
          stepper.moveTo((testPos));   
          stepper.run();
          }
          stopPowerToCoils();
        }
        break;
      case BUTTON_SET:
        // set the maximum or minimum position
        if (stepper.currentPosition() > (testPos)) {
          maxPos = stepper.currentPosition();
          EEPROM_writelong(EEPROM_ADDR_MAX_POSITION, maxPos);          
          
        } else {
          minPos = stepper.currentPosition();
          EEPROM_writelong(EEPROM_ADDR_MIN_POSITION, minPos);          
        }
        stopPowerToCoils();
        break;
      case BUTTON_STOP:
        Serial.println("Şu an durdum. Konumum : " + stepper.currentPosition());        
        stepper.stop();
        stopPowerToCoils();
        break;
      case BUTTON_RESET:
          minPos = 0;
          maxPos = 0;
          EEPROM_writelong(EEPROM_ADDR_MAX_POSITION, maxPos);      
          EEPROM_writelong(EEPROM_ADDR_MIN_POSITION, minPos);
          Serial.println("Minpos " + String(minPos)+ "olarak ve MaxPos da " + String(maxPos) + "olarak ayarlandı.");
          delay(1000)  ;
          resetFunc();                      
        break;
    }
    // reset the IR receiver
    Serial.println("reset the IR receiver");
    IrReceiver.resume(); // Enable receiving of the next value
  }
}
/**
  Turn of power to coils whenever the blind
  is not moving
*/
void stopPowerToCoils() {
  Serial.println("stopPowerToCoils()");
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
}


// read double word from EEPROM, give starting address
unsigned long EEPROM_readlong(int address) {
//use word read function for reading upper part
unsigned long dword = EEPROM_readint(address);
//shift read word up
dword = dword << 16;
// read lower word from EEPROM and OR it into double word
dword = dword | EEPROM_readint(address+2);
return dword;
}

//write word to EEPROM
  void EEPROM_writeint(int address, int value) {
  EEPROM.write(address,highByte(value));
  EEPROM.write(address+1 ,lowByte(value));
}
  
  //write long integer into EEPROM
  void EEPROM_writelong(int address, unsigned long value) {
  //truncate upper part and write lower part into EEPROM
  EEPROM_writeint(address+2, word(value));
  //shift upper part down
  value = value >> 16;
  //truncate and write
  EEPROM_writeint(address, word(value));
}

unsigned int EEPROM_readint(int address) {
  unsigned int word = word(EEPROM.read(address), EEPROM.read(address+1));
  return word;
}



Please elaborate on this.

Note that the logical OR operator is "||" not "|".

"|" is a bitwise operator.

 case BUTTON_UP:
      // move the roller blind up
      
      if (stepper.currentPosition() < maxPos ) {               
        stepper.moveTo(maxPos);   
        while (stepper.distanceToGo() != 0) {
        IrReceiver.resume();
       
        Serial.println(String(IrReceiver.decodedIRData.command));
        if (IrReceiver.decodedIRData.command == BUTTON_STOP) {
        // Stop the stepper motor
        stepper.stop();
        break;
        }
        stepper.run();
        } 
        stopPowerToCoils();
      }

with this code, when I press the button_up key motor starts to move to its max position in a while statement, but I want to stop the motor by pressing the button_down key.

Thank you, i will look into it. But it is not my issue right now :frowning:

Then you must include that variable in the "while" statement.

Suggest you avoid using while( ) as it is blocking.

When up is detected, enter a new state where you check for arrival.

If you haven’t arrived, normal loop( ) code executes.

If the stop code is received when you are in the this new state, stop the motor . . .

The ugly way is to use while-loops and add in each and every while-loop the code that checks for the stop-buttonpress
requires time to add the code

The elegant way is to use a non-blocking state-machine.
requires time to learn it

best regards Stefan

You are calling IrReceiver.resume(); inside the 'while' loop and not calling 'IrReceiver.decode()' so your received data is never looked at. Maybe this has a chance of working:

      case BUTTON_UP:
        // move the roller blind up
        if (stepper.currentPosition() < maxPos) {
          stepper.moveTo(maxPos);
          // Look for further IR input
          IrReceiver.resume();
          // While we have not reached the target
          while (stepper.distanceToGo() != 0) {
            // check if there is an IR code available
            if (IrReceiver.decode()) {
              // We have received a button press
              Serial.println(String(IrReceiver.decodedIRData.command));
              if (IrReceiver.decodedIRData.command == BUTTON_STOP) {
                // Set the new target to the earliest possible stopping point
                stepper.stop();
              }
              // Keep looking for more input
              IrReceiver.resume();
            }
            // Continue moving toward target
            stepper.run();
          }
          // We have reached the target and stopped
          stopPowerToCoils();
        }
        break;

That's it :slight_smile: It is like a new year present from you!

@StefanL38 and @LarryD I know it is a dirty way, I will definitely learn state-machine.

Thank you all for your time.

Take a look into this tutorial

If you have questions how to adapt it to your project.
Just ask here in the forum
best regards Stefan

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