How to execute functions simultaneously in this case?

I am playing around with toggling components from a webpage. Now my problem is when I toggle my stepper, I have to wait for the whole for loop to end for something else to toggle.

is there a way to run functions simultaneously? Maybe multi threading?

function to toggle the stepper:

void toggleStepper(bool state)
{
  switch (state)
  {
  case true:
    for (int a = 0; a < 3000; a++)
    {
      OneStep(false); // forward
      delay(5);
    }
    break;

  case false:
    for (int a = 0; a < 3000; a++)
    {
      OneStep(true); // backward
      delay(5);
    }
    break;
  }
}

function to toggle a light:

void toggleLight(bool state)
{
  switch (state)
  {
  case true:
    digitalWrite(LIGHT_PIN_14, HIGH);
    break;
  case false:
    digitalWrite(LIGHT_PIN_14, LOW);
    break;
  }
}

why not have toggleStepper() perform just one step and have it and toggleLight() called repeatedly within loop().

toggleStepper() could be passed a "step" argument. it keeps track of the step it's on and move in the appropriate direction to step toward "step" not stepping at all if already at that step

https://forum.arduino.cc/index.php?topic=223286.0

Single core uController can only do one thing at a time!
However there is a trick to do pseudo multi tasking and that is to use an Interrupt driven from a timer. Then in you main loop you can control/read device A and in the interrupt function you can control/read device B. Or in the interrupt handler function you can have a flag that you toggle when you exit the interrupt function. Then when you enter the interrupt function you read the flag state/value and do which ever task control/read device you want. If you have never done this, start with small tests like Set Time at 100ms, then when in the interrupt handler toggle an LED (BUILTIN_LED) etc. And build up from this simple model... Do a google for arduino timer interrupt example :slight_smile: Enjoy the journey!

An ESP32 comes with freeROTOS a good state machine and multitasker and multiprocessor OS, as an FYI.

do you really mean simultaneously? do stepping the motor 3000 times really take as much time as toggling an LED?

what do you really need?

@gcjr, I said it in my first message. If I toggle the stepper, I have to wait for the for loop to end (which takes about 10 seconds)..

so what you really want is to be able to toggle the LED in between steps. right?

consider


enum { Off = HIGH, On = LOW };

byte pinsLed [] = { 10, 11, 12 };
#define N_LED   sizeof(pinsLed)

byte pinBut = A1;
byte stateBut = HIGH;

unsigned long msecLst;

// -----------------------------------------------------------------------------
void
seqLed (void)
{
    static int  idx = 0;

    digitalWrite (pinsLed [idx], Off);

    idx = (idx+1) % N_LED;
    digitalWrite (pinsLed [idx], On);
}

// -----------------------------------------------------------------------------
#define Timer   100
void loop () {
    // sequence leds every 100 msec
    unsigned long msec = millis ();
    if (msec > msecLst)  {
        msecLst = msec + Timer;
        seqLed ();
    }

    // toggle builtin-led on button press
    byte but = digitalRead (pinBut);
    if (stateBut != but)  {
        stateBut = but;
        delay (10);     // debounce

        if (LOW == but)  {
            Serial.println ("press");
            digitalWrite (LED_BUILTIN, ! digitalRead (LED_BUILTIN));
        }
    }
}

// -----------------------------------------------------------------------------
void setup () {
    Serial.begin (9600);

    pinMode (LED_BUILTIN, OUTPUT);

    for (unsigned n = 0; n < N_LED; n++)  {
        pinMode (pinsLed [n], OUTPUT);
        digitalWrite (pinsLed [n], Off);
    }

    pinMode (pinBut, INPUT_PULLUP);
}

@gcjr thank you for your feedback however that's not quite what I am after. After reading some documentation, I don't even think it's possible tbh.

Which motor and driver are you using? Which stepper library?
Post your COMPLETE code.

Of course it is. You just have to break down your tasks into small enough increments such that no one taks is late doing what it needs. If your code blocks when a new web request comes in, that won't work. If your stepper motor code blocks until it is completely done, that wont work.

Maybe post your complete code?

By that assessment, I’ve done six impossible things before lunch.

a7

tvoid toggle( bool state ) {
    switch( state ) {
        case true:
            digitalWrite( LIGH_PIN_14, HIGH );
            for( int a = 0; a < 3000; a++ ) {
                OneStep( false );                         // forward
                delay( 5 );
            }
            break;

        case false:
            digitalWrite( LIGH_PIN_14, LOW );
            for( int a = 0; a < 3000; a++ ) {
                OneStep( true );                        // backward
                delay( 5 );
            }
            break;
    }
}

@blh64 it is a simple question of executing another task while a for loop is running, which seems impossible here.

but a "for" loop doesn't need to be used to step the motor 3000 times

@gcjr thank you for your reply, I am not using any library for the stepper.

Here is the step function:

void OneStep(bool dir)
{
  if (dir)
  {
    switch (step_number)
    {
    case 0:
      digitalWrite(STEPPER_PIN_1, HIGH);
      digitalWrite(STEPPER_PIN_2, LOW);
      digitalWrite(STEPPER_PIN_3, LOW);
      digitalWrite(STEPPER_PIN_4, LOW);
      break;
    case 1:
      digitalWrite(STEPPER_PIN_1, LOW);
      digitalWrite(STEPPER_PIN_2, HIGH);
      digitalWrite(STEPPER_PIN_3, LOW);
      digitalWrite(STEPPER_PIN_4, LOW);
      break;
    case 2:
      digitalWrite(STEPPER_PIN_1, LOW);
      digitalWrite(STEPPER_PIN_2, LOW);
      digitalWrite(STEPPER_PIN_3, HIGH);
      digitalWrite(STEPPER_PIN_4, LOW);
      break;
    case 3:
      digitalWrite(STEPPER_PIN_1, LOW);
      digitalWrite(STEPPER_PIN_2, LOW);
      digitalWrite(STEPPER_PIN_3, LOW);
      digitalWrite(STEPPER_PIN_4, HIGH);
      break;
    }
  }
  else
  {
    switch (step_number)
    {
    case 0:
      digitalWrite(STEPPER_PIN_1, LOW);
      digitalWrite(STEPPER_PIN_2, LOW);
      digitalWrite(STEPPER_PIN_3, LOW);
      digitalWrite(STEPPER_PIN_4, HIGH);
      break;
    case 1:
      digitalWrite(STEPPER_PIN_1, LOW);
      digitalWrite(STEPPER_PIN_2, LOW);
      digitalWrite(STEPPER_PIN_3, HIGH);
      digitalWrite(STEPPER_PIN_4, LOW);
      break;
    case 2:
      digitalWrite(STEPPER_PIN_1, LOW);
      digitalWrite(STEPPER_PIN_2, HIGH);
      digitalWrite(STEPPER_PIN_3, LOW);
      digitalWrite(STEPPER_PIN_4, LOW);
      break;
    case 3:
      digitalWrite(STEPPER_PIN_1, HIGH);
      digitalWrite(STEPPER_PIN_2, LOW);
      digitalWrite(STEPPER_PIN_3, LOW);
      digitalWrite(STEPPER_PIN_4, LOW);
    }
  }
  step_number++;
  if (step_number > 3)
  {
    step_number = 0;
  }
}

and I basically loop it how many times I need it, which most likely isn't the best way of doing it. Is there a good library that could replace that?

your step function is fine

you just need to architect your code to meet your requirements. using a blocking for loop does not meet your requirements.

in post #9 i seqLed () demonstrated how a function can be repeatedly called to execute a sequence. in your case, you just need to keep track of the current step and whether to move or not move

Building off the example from @gcjr, this illustrates how you can do several things

  1. the LED blinking is totally contained without its own function. Just call it often and it updates as needed
  2. checking for a button press every time through loop so it is responsive and blinking the build-in LED as well as starting/stopping the motor and reversing direction.
  3. updating the motor every time through loop but using global variables since there are several functions involved with the motors

any or all of these techniques can by used
(untested)

#define LIGH_PIN_14 9
#define STEPPER_PIN_1 5
#define STEPPER_PIN_2 6
#define STEPPER_PIN_3 7
#define STEPPER_PIN_4 8


enum { Off = HIGH, On = LOW };

const byte pinsLed [] = { 10, 11, 12 };
const byte N_LED = sizeof(pinsLed) / sizeof(pinsLed[0]);

const byte pinBut = A1;
byte stateBut = HIGH;

bool isMotorRunning = false;
bool motorDir = false;
int motorStepIdx;
const int MAX_MOTOR_COUNT = 3000;

unsigned long currentTime;

/*
   Sequence the LEDs every 100 msec
*/

void seqLed (void) {
  static int  idx = 0;
  static unsigned long lastTime;
  const unsigned long interval = 100;

  if ( currentTime - lastTime >= interval ) {
    // time to do next action
    lastTime = currentTime;

    digitalWrite (pinsLed [idx], Off);
    idx = (idx + 1) % N_LED;
    digitalWrite (pinsLed [idx], On);
  }
}

void startMotor(bool state) {
  isMotorRunning = true;
  motorStepIdx = 0;
  motorDir = state;
  if (motorDir ) {
    digitalWrite( LIGH_PIN_14, HIGH );
  }
  else {
    digitalWrite( LIGH_PIN_14, HIGH );
  }
}

void stopMotor() {
  isMotorRunning = false;
}


void updateMotor() {

  static unsigned long lastTime;
  const unsigned long interval = 5;

  if ( currentTime - lastTime >= interval ) {
    lastTime = currentTime;
    OneStep(motorDir);
    motorStepIdx++;
    if ( motorStepIdx >= MAX_MOTOR_COUNT ) {
      stopMotor();
    }
  }
}

void OneStep(bool dir) {
  static byte step_number;

  if (dir)
  {
    switch (step_number)
    {
      case 0:
        digitalWrite(STEPPER_PIN_1, HIGH);
        digitalWrite(STEPPER_PIN_2, LOW);
        digitalWrite(STEPPER_PIN_3, LOW);
        digitalWrite(STEPPER_PIN_4, LOW);
        break;
      case 1:
        digitalWrite(STEPPER_PIN_1, LOW);
        digitalWrite(STEPPER_PIN_2, HIGH);
        digitalWrite(STEPPER_PIN_3, LOW);
        digitalWrite(STEPPER_PIN_4, LOW);
        break;
      case 2:
        digitalWrite(STEPPER_PIN_1, LOW);
        digitalWrite(STEPPER_PIN_2, LOW);
        digitalWrite(STEPPER_PIN_3, HIGH);
        digitalWrite(STEPPER_PIN_4, LOW);
        break;
      case 3:
        digitalWrite(STEPPER_PIN_1, LOW);
        digitalWrite(STEPPER_PIN_2, LOW);
        digitalWrite(STEPPER_PIN_3, LOW);
        digitalWrite(STEPPER_PIN_4, HIGH);
        break;
    }
  }
  else
  {
    switch (step_number)
    {
      case 0:
        digitalWrite(STEPPER_PIN_1, LOW);
        digitalWrite(STEPPER_PIN_2, LOW);
        digitalWrite(STEPPER_PIN_3, LOW);
        digitalWrite(STEPPER_PIN_4, HIGH);
        break;
      case 1:
        digitalWrite(STEPPER_PIN_1, LOW);
        digitalWrite(STEPPER_PIN_2, LOW);
        digitalWrite(STEPPER_PIN_3, HIGH);
        digitalWrite(STEPPER_PIN_4, LOW);
        break;
      case 2:
        digitalWrite(STEPPER_PIN_1, LOW);
        digitalWrite(STEPPER_PIN_2, HIGH);
        digitalWrite(STEPPER_PIN_3, LOW);
        digitalWrite(STEPPER_PIN_4, LOW);
        break;
      case 3:
        digitalWrite(STEPPER_PIN_1, HIGH);
        digitalWrite(STEPPER_PIN_2, LOW);
        digitalWrite(STEPPER_PIN_3, LOW);
        digitalWrite(STEPPER_PIN_4, LOW);
    }
  }
  step_number = (step_number + 1) % 4;
}

// -----------------------------------------------------------------------------


// -----------------------------------------------------------------------------
void setup () {
  Serial.begin (9600);

  pinMode (LED_BUILTIN, OUTPUT);

  for (unsigned n = 0; n < N_LED; n++)  {
    pinMode (pinsLed [n], OUTPUT);
    digitalWrite (pinsLed [n], Off);
  }

  pinMode (pinBut, INPUT_PULLUP);
}

void loop () {

  currentTime = millis();

  seqLed();

  // toggle builtin-led on button press
  byte but = digitalRead (pinBut);
  if (stateBut != but)  {
    stateBut = but;
    delay (10);     // debounce

    if (LOW == but)  {
      Serial.println ("press");
      digitalWrite (LED_BUILTIN, ! digitalRead (LED_BUILTIN));
      if (isMotorRunning) {
        stopMotor();
      }
      else {
        startMotor(!motorDir);  // begin in the other direction
      }
    }
  }

  updateMotor();
}

An ESP32 has 2 cores and 2 processors. Each core can be running its own program and the other processor can run its own program; not task switching but multiprocessing.