Serial.print() Changes Behavior of millis() and micros()

I am attempting to write a custom stepper motor control program to be implemented on a Sunfounder Arduino Uno. The idea is to simultaneously control two stepper motors (“feeder” and “conveyor”), each connected to its own L298N motor driver. The code is below:

/* 
 *  Step C0 C1 C2 C3
 *    1  1  0  1  0
 *    2  0  1  1  0
 *    3  0  1  0  1
 *    4  1  0  0  1
 */

// Number of steps per output rotation
int stepsPerRevolution = 200;

// array to hold pins
int feederPins[] = {10, 11, 12, 13};
int conveyorPins[] = {6, 7, 8, 9};

// speeds in RPM
const int feederSpeed = 8;
const int conveyorSpeed = 20;

// store direction
boolean feederDir = true;
boolean conveyorDir = false;

// step number for each motor
byte feederStepNum = 1;
byte conveyorStepNum = 1;

// store the previous time value
unsigned long t_prev = 0;
// store the current time value
unsigned long t_now = 0;

// calculate step time delay
int feederStepDelay = int(1.0/(feederSpeed * stepsPerRevolution / float(60000)));
int conveyorStepDelay = int(1.0/(conveyorSpeed * stepsPerRevolution / float(60000)));

void setup()
{
  for (int i = 0; i < 4; i++) {

    pinMode(feederPins[i], OUTPUT);
    pinMode(conveyorPins[i], OUTPUT);
    
  }

  t_prev = micros(); // only goes for 71min
  
}

void loop() 
{
    
  // get current time
  unsigned long t_now = micros();
  
  // check if this is bigger than either motor's delay
  if ((t_now - t_prev) > feederStepDelay) {
    // move the feeder
    moveFeeder();
  }

  if ((t_now - t_prev) > conveyorStepDelay) {
    // move the conveyor
    moveConveyor();
  }

  // set the previous time to the time jut used for calculation
  t_prev = t_now;
  
}

void moveFeeder() {

  switch (feederStepNum) {
    case 1: // 1010
      digitalWrite(feederPins[0], HIGH);
      digitalWrite(feederPins[1], LOW);
      digitalWrite(feederPins[2], HIGH);
      digitalWrite(feederPins[3], LOW);
    break;
    case 2: // 0110
      digitalWrite(feederPins[0], LOW);
      digitalWrite(feederPins[1], HIGH);
      digitalWrite(feederPins[2], HIGH);
      digitalWrite(feederPins[3], LOW);
    break;
    case 3: // 0101
      digitalWrite(feederPins[0], LOW);
      digitalWrite(feederPins[1], HIGH);
      digitalWrite(feederPins[2], LOW);
      digitalWrite(feederPins[3], HIGH);
    break;
    case 4: // 1001
      digitalWrite(feederPins[0], HIGH);
      digitalWrite(feederPins[1], LOW);
      digitalWrite(feederPins[2], LOW);
      digitalWrite(feederPins[3], HIGH);
    break;
  }
  
  if (!feederDir) { // increment step number
    feederStepNum++;
    if (feederStepNum == 5) feederStepNum = 1;
  } else { // decrement step number
    feederStepNum--;
    if (feederStepNum == 0) feederStepNum = 4;
  }
  
}

void moveConveyor() {

  switch (conveyorStepNum) {
    case 1: // 1010
      digitalWrite(conveyorPins[0], HIGH);
      digitalWrite(conveyorPins[1], LOW);
      digitalWrite(conveyorPins[2], HIGH);
      digitalWrite(conveyorPins[3], LOW);
    break;
    case 2: // 0110
      digitalWrite(conveyorPins[0], LOW);
      digitalWrite(conveyorPins[1], HIGH);
      digitalWrite(conveyorPins[2], HIGH);
      digitalWrite(conveyorPins[3], LOW);
    break;
    case 3: // 0101
      digitalWrite(conveyorPins[0], LOW);
      digitalWrite(conveyorPins[1], HIGH);
      digitalWrite(conveyorPins[2], LOW);
      digitalWrite(conveyorPins[3], HIGH);
    break;
    case 4: // 1001
      digitalWrite(conveyorPins[0], HIGH);
      digitalWrite(conveyorPins[1], LOW);
      digitalWrite(conveyorPins[2], LOW);
      digitalWrite(conveyorPins[3], HIGH);
    break;
  }
  
  if (!conveyorDir) { // increment step number
    conveyorStepNum++;
    if (conveyorStepNum == 5) conveyorStepNum = 1;
  } else { // decrement step number
    conveyorStepNum--;
    if (conveyorStepNum == 0) conveyorStepNum = 4;
  }
  
}

When I compile and run this program, absolutely nothing happens. I checked the wiring with the built-in Stepper library and everything worked as expected. I initially attempted to debug the program using the serial monitor and adding a several print statements throughout the program. When I did this, the program and motors suddenly worked; however, when I removed the print statements (without changing any other code), it didn’t. Through trial and error, I determined that printing out the value of t_now in the loop causes the program to work.

In response to this, I attempted to debug the code in Visual Studio in accordance with this article; however, I was unable to interpret what I was seeing (see attached screenshot).

After searching for similar issues, I found that this may have something to do with compiler optimization. Thus, I attempted to declare t_prev and t_now as volatile; however, this did not work. I then declared every global variable as volatile, and that didn’t work either. Interestingly, the program seems to use very little memory on the global variables:

Sketch uses 1294 bytes (4%) of program storage space. Maximum is 32256 bytes.
Global variables use 19 bytes (0%) of dynamic memory, leaving 2029 bytes for local variables. Maximum is 2048 bytes.

Thus, I’m wondering what the cause of this problem is, as well as if there are any solutions to it. Is it possible to disable the compiler optimization? Is there another way to force these variables to be included? Is there a different, simpler approach I can take to this problem that accomplishes the same goal? I would greatly appreciate any insight or solutions anyone is willing to provide!

Thank you!

Hello
Did you checked the calculated numbers for feederStepDelay
and conveyorStepDelay. They might be 0 and than nothing will be happens.

you need two t_prev variables, one for the feeder and one for the Conveyor and you need to update them ONLY when you have performed the move

// store the previous time value
unsigned long t_prevFeeder = 0;
unsigned long t_prevConveyor = 0;

and the loop becomes


void loop() {
  unsigned long t_now = micros();                         // get current time

  // check if this is bigger than either motor's delay
  if ((t_now - t_prevFeeder) > feederStepDelay) {       // move the feeder
    moveFeeder();
    t_prevFeeder = t_now;
  }

  if ((t_now - t_prevConveyor) > conveyorStepDelay) {    // move the conveyor
    moveConveyor();
    t_prevConveyor = t_now;
  }
}

and either you keep them at 0 and remove the t_prev initialisation at the end of the setup() or you replace it by
t_prevFeeder = t_prevConveyor = micros();
if you want to really take into account the setup time of the board and not start right away

PS: you have declared two unsigned long t_now , there is no need for the global variable, get rid of it

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.