0

A Polulo A4988 driver board listens for a LOW -> HIGH pulse on a digital pin to step a stepper motor.

A simple way to pulse this with a delay of say 100μs, is to use the delayMicroseconds function:

#define STEP_PIN  3
#define DELAY     100

void setup(){
    pinMode(STEP_PIN, OUTPUT);
}

void loop(){
    //heavy computation taking time
    digitalWrite(STEP_PIN, LOW);
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(DELAY);
}

Although this works, the issue is that all the time that the processor spends in the delayMicroseconds function is wasted. This means that if I wanted to, for example, handle inputs from a serial line, I would have no time to do this. In addition, the time for these computations to complete would result in the pulse time increasing which is not ideal as the speed of the stepper would no longer be uniform.

How can I efficiently pulse the stepper at the correct time, whilst leaving my self room to run other tasks between pulses?


P.s. This is for this project: https://github.com/joeiddon/chess_robot.

4
  • Use a library that makes the pulses for you: airspayce.com/mikem/arduino/AccelStepper Which arduino board do you use?
    – Jot
    Commented Dec 30, 2018 at 13:39
  • @Jot I'm using an Arduino Nano. As for the library, I am more interested in understanding how stepper control works, rather than the final outcome. :)
    – Joe Iddon
    Commented Dec 30, 2018 at 13:51
  • I that case you could have a look at the source code of AccelStepper. Having a quick look, it seems that they are using the same method as Joe Iddon describes below, with some additions to make the speed of the motor ramp up and down. An entirely different solutions is to use a timer and timer-interrupt to run code at a set interval.
    – Gerben
    Commented Dec 30, 2018 at 14:01
  • 1
    @Gerben Thanks for the link, I'll take a look at the source. Also the interrupt driven system sounds interesting, I hadn't considered that. It is working well now though, so I doubt I will spend too much longer perfecting this. Thanks for the input though :)
    – Joe Iddon
    Commented Dec 30, 2018 at 14:45

1 Answer 1

1

Instead of delaying between pulses, loop around the main loop() function as fast as possible constantly checking the time to see if we should pulse the motor.

This means that computations can occur in the loop (so long as they are reasonably fast).

To implement this, the micros() function can be used to get an unsigned long representing the microseconds that have passed since the start of the program.

Then in each loop cycle, we need to check if the difference between the current time and the last time that we pulsed is >= the pulse delay. In which case, we send a pulse to the motor

However, instead of setting the last pulse time variable to the current time, we instead increment the last pulse variable by the delay time. This has the affect that even if we were slightly late in pulsing, we pretend that we did in fact pulse at the right time so that they do not drift over time.

This would look something like:

#define STEP_PIN  3
#define DELAY     100

uint32_t last_pulse;

void setup(){
    pinMode(STEP_PIN, OUTPUT);
    last_pulse = micros();
}

void loop(){
    //heavy computation taking time
    if (micros() - last_pulse >= DELAY){
        last_pulse += DELAY;
        digitalWrite(STEP_PIN, LOW);
        digitalWrite(STEP_PIN, HIGH);
    }
}

Note that there is a slight subtlety here in that the result from micros() and therefore the value of last_pulse will overflow after ~70 minutes. However, because we are taking a difference of two unsigned numbers, this method will still work, so long as micros() is never a whole cycle ahead of last_pulse which in practice will never be the case.

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.