Blink without delay, not getting 50% duty cycle [Solved]

I'm not blinking an LED, but I've learned to call this method blink without delay from the arduino ide example. I'm attempting to step a stepper motor. From trial and error I've found that the shortest pulse I can use the drive the motor without skipping is 50 microseconds. I've got my code written to deliver 100 microsecond pulses, but that's not the result I'm seeing. My oscilloscope shows the pin starting LOW, go HIGH for 16 microseconds, then LOW for 88 microseconds, then another 16 microsecond pulse. The frequency of these pulses are just about 10kHz, just as I would expect from a 100 microsecond cycle.

The issue is the duty cycle. The on and off times of 16 and 88 microseconds seems arbitrary to me and I can't figure out why it's not 50%. 16 microseconds it too short a pulse to reliably step the motor. What's wrong with my code and how do I fix it?

I have 2 motors hooked up and eventually I plan get the function working so I can tell each to turn to a specific angle. It doesn't do that yet, I want to work out the duty cycle first. I also have the duration limited because I'm driving an OLED display and I want to update it between groups of turns.

void turnTo(double angle1, double angle2) {    // move the motor to a specific position

// ********** Initialize **********

  unsigned long sMillis = millis();  // start time
  unsigned long pMicros;             // last check
  unsigned long pulse = 100;         // width of pulse (microseconds)
  unsigned long duration = 100;     // duration of turning (milliseconds) (100ms limits display to 6fps)
  unsigned long steps;               // number of steps taken
  unsigned adjust;                   // dont do more than half a rotation to get there
  double turn1, turn2;               // distance to reach angle from current position

// ********** Compensate **********
// Turn the input angle into a distance and direction to turn

  digitalWrite(Direction1, counterclockwise);   //default direction
  digitalWrite(Direction2, counterclockwise);

  turn1 = angle1 - pos1;
  if (turn1 > tau) {
    adjust = turn1 / tau; // rounded to lower int
    turn1 -= adjust * tau;// new turn
  }
  if (turn1 > pi) {       // go the other way around
    turn1 -= tau;
    turn1 *= -1;
    digitalWrite(Direction1, clockwise);
  }
  
  turn2 = angle2 - pos2;
  if (turn2 > tau) {
    adjust = turn2 / tau; // rounded to lower int
    turn2 -= adjust * tau;
  }
  if (turn2 > pi) {       // go the other way around
    turn2 -= tau;
    turn2 *= -1;
    digitalWrite(Direction2, clockwise);
  }

// ********** Turn **********
// doesn't use the rest of the function yet. Just turns the motor. Duty cycle issue here

  while (duration > millis() - sMillis) {  // finish later if not within time
    if (micros() - pMicros >= pulse) {   // on the interval given by the defined pulse time switch high/low low/high
      pMicros = micros();   // save time of state change
      
      if (state1 == LOW) {
        state1 = HIGH;
        steps++;            // count a step as a low to high change
      } else {
        state1 = LOW;
      }
      if (state2 == LOW) {
        state2 = HIGH;
        steps++;
      } else {
        state2 = LOW;
      }

      digitalWrite(Step1, state1);           // Step is the pin connected to the driver of each motor
      digitalWrite(Step2, state2);           // state is the state of that pin
    }
    digitalWrite(Step1, LOW); state1 = LOW; // finish in a LOW state
    digitalWrite(Step2, LOW); state2 = LOW;
  }
}

Instead of mixing millis() and micros(), do it all in micros.

Change this so you're not using three different times of micros:

  while (duration > millis() - sMillis) {  // finish later if not within time
    if (micros() - pMicros >= pulse) {   // on the interval given by the defined pulse time switch high/low low/high
      pMicros = micros();   // save time of state change

to

microsNow = micros();
  while (duration > microsNow - sMillis) {  // finish later if not within time
    if (microsNow - pMicros >= pulse) {   // on the interval given by the defined pulse time switch high/low low/high
      pMicros = microsNow;   // save time of state change

changing duration, sMillis, pMicros to the equivalent micros

CrossRoads: Instead of mixing millis() and micros(), do it all in micros.

Ok, I did that. Still no change in the duty cycle unfortunately

I do not think the logic of your function is correct. Every 100 microseconds you enter enter a conditional statement where you toggle the two outputs Step1 and Step2. As soon as you exit that if statement, you turn both outputs off. Everything is still within the 100 millisecond while loops so it all repeats.

I think the two digitalWrite() statements setting everything low needs to be outside of the while loop, and the value of pulse needs to be 50(not 100) to get a 50 microsecond high and low time for the toggle.

cattledog:
I think the two digitalWrite() statements setting everything low needs to be outside of the while loop, and the value of pulse needs to be 50(not 100) to get a 50 microsecond high and low time for the toggle.

That’s it! I now have 100uS highs and 100uS lows. I thought for sure those state resets wouldn’t be the problem because I thought I put them in after the problem occurred, but I guess I just misse it.

Thanks!