1

I am trying to get a simple non-blocking replacement for:

digitalWrite(stepPinX, HIGH);
delayMicroseconds(500);
digitalWrite(stepPinX, LOW);
delayMicroseconds(500);

This is what I tried, and the stepper motor stays still:

const int dirPinX = 0;
const int stepPinX = 2;

unsigned long startMicros = micros();
unsigned long currentMicros;
const unsigned long period = 500;

void setup()
{
  pinMode(stepPinX, OUTPUT);
  pinMode(dirPinX, OUTPUT);

  digitalWrite(dirPinX, HIGH);
}

void loop()
{
  stepX();
}

void stepX()
{
  currentMicros = micros();  //get the current "time" (time since program start)

  if (currentMicros - startMicros >= period)  //test whether period elapsed
  {
    digitalWrite(stepPinX, HIGH);
  }
  if ((currentMicros - startMicros >= period) && (currentMicros - startMicros <= period*2))
  {
    digitalWrite(stepPinX, LOW);
  } 

  startMicros = currentMicros;
}

Any suggestions on how to correct this? (I do not want to use a library like Accelstepper. I want to use millis/micros.)

3
  • the second if statement will execute only very infrequently ... why have a separate if statement for the two output states?
    – jsotola
    Mar 9, 2023 at 20:32
  • edited question and program
    – adamaero
    Mar 9, 2023 at 20:48
  • do only one if (currentMicros - startMicros >= period) ... keep track of stepPinX state
    – jsotola
    Mar 10, 2023 at 0:11

2 Answers 2

1

Your stepX() function looks like this:

void stepX()
{
  currentMicros = micros();
  // conditionally do some stuff..
  startMicros = currentMicros;
}

Since there is nothing that can block it, it will always execute very fast. This means that, by the time the function returns, startMicros will be very close to the current time. Then, on the following call, currentMicros - startMicros will be very small, way smaller than period, and the conditional code will never execute.

The solution is to change the meaning of startMicros: instead of representing the time of the last call to stepX(), let it represent the time when the last step started. For this, you have to reset it only when finishing a step:

void stepX()
{
  currentMicros = micros();
  if (currentMicros - startMicros < period) {           // 1st phase
    digitalWrite(stepPinX, HIGH);
  } else if (currentMicros - startMicros < 2*period) {  // 2nd phase
    digitalWrite(stepPinX, LOW);
  } else {                                              // complete cycle
    startMicros = currentMicros;        
  }
}
2
  • if ((currentMicros - startMicros >= period) && (currentMicros - startMicros <= period*2)) { digitalWrite(stepPinX, LOW); startMicros = currentMicros; } Like that? Same result as before.
    – adamaero
    Mar 9, 2023 at 21:04
  • @adamaero: Oops! Indeed, I did not notice that the logic of the if conditions was wrong. Edited the answer. Mar 9, 2023 at 21:34
1

Looks like startMicros and currentMicros values always stay close to each other because of using micros() before and after the conditional block. Since the conditional block executes faster than 500 micros, resulting in never entering the conditional block.

From here you can take two approaches,

  • Approach 01: Play with your code variables and debug in realtime to see what's wrong and where. Then tweak,debug, repeat until you reach the desired result
  • Approach 02: Rethink w.r.t the code execution and simplify your code right from entry to exit in sequential steps.

Since your action can be simplified to a toggle operation every 500 microseconds, we can refactor code similar to what I have written,

bool toggle_flag = false;
unsigned long last_toggle;
const unsigned long period = 500;
  
void setup() {
    last_toggle = micros();
    pinMode(stepPinX, OUTPUT);
}

void loop() {
  // Check to see if time elapsed
  if (micros() - last_toggle >= period ) {
      
      // Step 01: reset the last_toggle with current time
      last_toggle = micros();

      // Step 02: check toggle flag and perform the toggle action
      (toggle_flag) ? digitalWrite(stepPinX, HIGH) : digitalWrite(stepPinX, LOW);

      // Step 03: toggle the toggle flag variable after our action
      toggle_flag = !toggle_flag;

  }

}

Hope this answer helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.