Generating a variable frequency square wave with fixed on time

So I'm trying to drive a stepper motor with step and direction signals. The direction signal is just a high or low state and the step signal is a pulse stream with a fixed on time of 10us. Now I wanted to vary the motor speed using a potentiometer.

I've defined a high and low frequency limits in the code. Since the on time is fixed, what needs to vary is the off time. I first read the pot value and then map its range to the low and high frequency range. Since this range is fixed between 5000 steps/sec to 50000 steps/sec, this led to an off time ranging between 190us (5K steps/s) to 10us (50K steps/s).

Now I came up with the following code but when I actually measure the pulses on a scope I see the frequency ranging between 800 Hz to 833 Hz. Also the actual ton is about 15us and the toff for 5K steps/s is something like 1.37ms when it should be 190us.

What am I missing?

void loop()
{
  while (digitalRead(xplus) == HIGH || digitalRead(xminus) == HIGH)
  {
    digitalWrite(en, HIGH); // enable motor drivers

    while (digitalRead(xplus) == HIGH)
    {
      digitalWrite(dx, HIGH); // LOW: CW, HIGH: CCW

      digitalWrite(sx, HIGH);
      delayMicroseconds(ton);
      digitalWrite(sx, LOW);
      toff = offTime();
      delayMicroseconds(toff);
    }

    while (digitalRead(xminus) == HIGH)
    {
      digitalWrite(dx, LOW); // LOW: CW, HIGH: CCW

      digitalWrite(sx, HIGH);
      delayMicroseconds(ton);
      digitalWrite(sx, LOW);
      toff = offTime();
      delayMicroseconds(toff);
    }

    digitalWrite(en, LOW); // disable motor drivers
  }
}

// function that calculates the off time.
int offTime(void)
{
  int offtime;
  feedrate = map(analogRead(fr), 0, 1023, lowfreq, highfreq);
  offtime = (1000000 / feedrate) - ton; // convert 'us' to a whole number to be used by the delay function
  //Serial.print("offtime = "); Serial.println(offtime);
  return offtime;
}

xplus and xminus are two tactile switches and the pulses are generated only when these switches are pressed (connected to 5V).

I suspect the problem arises from calling offTime() in your loops.

Since this range is fixed between 5000 steps/sec to 50000 steps/sec,

That's very fast for a stepper motor. I'd be surprised if your motor can really step that fast. And, to get the maximum speed out of it you'll probably have to start slower and accelerate it.

There is a [u]stepper library[/u] for the Arduino. (I've never used it.)

DVDdoug:
That's very fast for a stepper motor. I'd be surprised if your motor can really step that fast. And, to get the maximum speed out of it you'll probably have to start slower and accelerate it.

There is a [u]stepper library[/u] for the Arduino. (I've never used it.)

Now that you mention it it does sound fast.

I still suspect the call to offTime() as being responsible for the unexpected timing. An easy way to test is to comment out the calls and just use a constant to see what the effect is.

electrophile:
Now I came up with the following code but when I actually measure the pulses on a scope I see the frequency ranging between 800 Hz to 833 Hz. Also the actual ton is about 15us and the toff for 5K steps/s is something like 1.37ms when it should be 190us.

Which makes me wonder: how did you measure this? The function offTime() looks fine to me, that really shouldn't take 1.37 ms to complete. Just a simple calculation, all integer math (not sure about the map() function but it, too, should be pretty efficient). Then I noticed that commented-out line:

  //Serial.print("offtime = "); Serial.println(offtime);

Total 13 or 14 characters (10 for the string, 2 or 3 for offtime, one newline), at 115200 baud that takes 1.13-1.22 ms to transmit. That perfectly matches your frequency of 800-833 Hz. So did you measure the frequency while you were printing out the time as well?

DVDdoug:
That's very fast for a stepper motor. I'd be surprised if your motor can really step that fast. And, to get the maximum speed out of it you'll probably have to start slower and accelerate it.

There is a [u]stepper library[/u] for the Arduino. (I've never used it.)

Thanks! Yes I did some basic stepping in another sketch and realised that was too fast for the motor. It stalls at around 20KHz. The new lower and upper limits are now 2KHz and 15KHz.

ardly:
Now that you mention it it does sound fast.

I still suspect the call to offTime() as being responsible for the unexpected timing. An easy way to test is to comment out the calls and just use a constant to see what the effect is.

Thanks. I'll try it.

wvmarle:
Which makes me wonder: how did you measure this? The function offTime() looks fine to me, that really shouldn't take 1.37 ms to complete. Just a simple calculation, all integer math (not sure about the map() function but it, too, should be pretty efficient). Then I noticed that commented-out line:

Total 13 or 14 characters (10 for the string, 2 or 3 for offtime, one newline), at 115200 baud that takes 1.13-1.22 ms to transmit. That perfectly matches your frequency of 800-833 Hz. So did you measure the frequency while you were printing out the time as well?

Not too sure. I will try the code after commenting the serial print.

An update: After a few more hours of tinkering, I realised that there is an excellent Tone library which generates a 50% duty cycle variable frequency square wave. I tried this and it worked great! I also realised that I did not have to have a 10us on time pulse. As long as the frequency changes, the stepper accelerates or slows down.

Thanks again for looking my code over :slight_smile: