Arduino: for loops in micros()

Viewed 295

I have effectively replicated the "no delay blink" example on my Arduino Mega2560 to send pulses to a stepper motor driver. I included a for loop to increment the number of "pulses" given to achieve a single rotation (800 pulses), then delay for a moment and repeat.

I find that the motor is only rotating a fraction of a revolution. It would seem that the micros() running faster than the for loop resulting in missed pulses. I would greatly appreciate if someone could point out why this may be, and how to work around it.

#include <Wire.h>

const int Pul_OUT = 9;
unsigned long previousMicros = 0;
unsigned long Pul_Interval = 100;
int setPosition = 800;

void setup()
{
  pinMode(Pul_OUT, OUTPUT);
  digitalWrite(Pul_OUT, LOW);
}

void loop()
{
  no_delay_Position();
  delay(100);
}

int no_delay_Position()
{
  for (int i = setPosition; i >= 0 ; i--)
  { 
    unsigned long currentMicros = micros();
    if (currentMicros - previousMicros > Pul_Interval) 
    {
      previousMicros = currentMicros;
      PulState = !PulState;
      digitalWrite(Pul_OUT, PulState);
    }
  }
}
2 Answers

Your for loop in no_delay_Position() will decrement i whether a pulse is sent or not (because that is determined by Pul_interval), so i will reach 0 before i pulses are sent.

Also, no_delay_Position() will not return until its for loop is done, and during that time, loop() is blocked.

Also, your Pul_Interval is only 100µs which is 0.1ms. You may want to replace micros() with millis() and see what happens.

BTW 100ms is still fairly quick for pulsing a stepper motor, you could try a larger Pul_Interval if the above is still too fast. There's nothing wrong with testing with a step every second or so, just to see if the algorithm works as expected.

delay() is measured in milliseconds, microseconds are just a fraction of this.

From the micros() reference:

There are 1,000 microseconds in a millisecond and 1,000,000 microseconds in a second.

Adding the delay(100) in your main loop will also stop the arduino from doing most things. If for some reason you need to use millis() in the outer loop and micros() in the set position loop you could do something like this

#include <Wire.h>

const int Pul_OUT = 9;
unsigned long previousMicros = 0;
unsigned long previousMillis = 0;
int Pul_Interval = 100;
int Main_Interval = 100;
int setPosition = 800;

void setup()
{
  pinMode(Pul_OUT, OUTPUT);
  digitalWrite(Pul_OUT, LOW);
}


void loop()
{
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis > Main_Interval) 
    {
      previousMillis = currentMillis;
      no_delay_Position();
    } 
}

void no_delay_Position()
{
  for(int i = setPosition; i >= 0 ; i--)
  { 
    unsigned long currentMicros = micros();
    if (currentMicros - previousMicros > Pul_Interval) 
    {
      previousMicros = currentMicros;
      PulState = !PulState;
      digitalWrite(Pul_OUT, PulState);
    }
  }
}

The call to no_delay_Position() looks to be set to return an int did you mean to be able to pass in an integer to set the position?

void loop()
{
  no_delay_Position(500);
}


void no_delay_Position(int setP)
{
  setPosition = setP;
  for(int i = setPosition; i >= 0 ; i--)
  { 
     //rest of your code
  }
}
Related