Electronic – arduino – Using a function within a function

arduinocncstepper motor

Hi I am a novice at using stepper motors, and I am learning as I go on.

However, I was wondering if there was a way to delay the steps between each step in my stepper motor without using the delay, because I understand that using the delay puts the whole program on hold. In the future, I would like to be able for the user to input different number of steps for the each stepper. Or have ps2 thumbstick hooked up so that the steppers can simultaneously move in the x and y axis (since I am making a cnc), resulting in a diagonal line.

Even though with the delay the steppers do run at the same time, they vibrate really badly. However, indivdually they are smooth, so I suspect it may be because of the delay.

So, any thoughts? Here is the code.

     int IN1 = 5; 
     int IN2 = 4; 
     int IN3 = 3; 
     int IN4 = 2;  
     int IN1_1 = 9; 
     int IN2_1 = 8; 
     int IN3_1 = 7; 
     int IN4_1 = 6;  
     int delay_time= 5;  
     int count = 0; 
     int i = 1;
     void setup(){ 
     pinMode(IN1, OUTPUT); 
     pinMode(IN2, OUTPUT); 
     pinMode(IN3, OUTPUT); 
     pinMode(IN4,OUTPUT);   
     pinMode(IN1_1, OUTPUT); 
     pinMode(IN2_1, OUTPUT); 
     pinMode(IN3_1, OUTPUT); 
     pinMode(IN4_1,OUTPUT);
     Serial.begin(9600);
   } 
   void loop(){   
   int s = 200; 
   int x = 0; 
   //Function that rotates the first stepper motor
   step_one();
  // Fucntion that rotates the second stepper motor
   step_two();
   }


 //definition of these functions  
 void step_one(){
 digitalWrite(IN1, LOW); 
 digitalWrite(IN2, HIGH); 
 digitalWrite(IN3, HIGH); 
 digitalWrite(IN4, LOW); 
 delay(delay_time);
 digitalWrite(IN1, LOW); 
 digitalWrite(IN2, HIGH); 
 digitalWrite(IN3, LOW); 
 digitalWrite(IN4, HIGH); 
 delay(delay_time); 
 //I want something else to be able to replace these delays
 digitalWrite(IN1, HIGH); 
 digitalWrite(IN2, LOW); 
 digitalWrite(IN3, LOW); 
 digitalWrite(IN4, HIGH);  
 delay(delay_time); 
 digitalWrite(IN1, HIGH); 
 digitalWrite(IN2, LOW); 
digitalWrite(IN3, HIGH); 
digitalWrite(IN4, LOW);  
delay(delay_time); 
}

void step_two(){
digitalWrite(IN1_1, LOW); 
digitalWrite(IN2_1, HIGH); 
digitalWrite(IN3_1, HIGH); 
digitalWrite(IN4_1, LOW); 
delay(delay_time);
digitalWrite(IN1_1, LOW); 
digitalWrite(IN2_1, HIGH); 
digitalWrite(IN3_1, LOW); 
digitalWrite(IN4_1, HIGH); 
delay(delay_time);
digitalWrite(IN1_1, HIGH); 
digitalWrite(IN2_1, LOW); 
digitalWrite(IN3_1, LOW); 
digitalWrite(IN4_1, HIGH);  
delay(delay_time); 
digitalWrite(IN1_1, HIGH); 
digitalWrite(IN2_1, LOW); 
digitalWrite(IN3_1, HIGH); 
digitalWrite(IN4_1, LOW);  
delay(delay_time); 
}

Best Answer

You've hit upon one of the most important issues in embedded programming - something that separates novices from more advanced programmers: blocking vs. non-blocking.

Basic Arduino programs are like scripts that just repeat over and over: do step 1, do step 2, do step three, go back to 1, etc. With script-style thinking, to generate any timing you have to insert it as a step: Do step 1, wait 10ms, do Step 2, etc. The issue that you've seen is that while the Arduino is waiting nothing else can happen - this is called a blocking delay. Blocking is used in other situations as well. If, for example, you're waiting for a a serial byte to arrive, many libraries will just sit and watch the UART receive register until something arrives - and do nothing else until it does. Generally, libraries like this will have a timeout feature - if no data arrives in X milliseconds they'll stop and report no data. Blocking is used often on larger computers with operating systems but it's less of an issue. In that situation you can have multiple threads such that when one thread is waiting on UART data, the operating system will suspend that task and let another run while it waits. Embedded systems without an operating system (like the Arduino) need a library or other code to generate a non-blocking delay in a different fashion. Sadly, the Arduino doesn't have this ability built-in - you have to develop it yourself or find a library that implements it (as mpflaga suggested).

Implementing a non-blocking delay yourself is not a one-step process. It's not a matter of switching out one function call for another or changing a setting in the GUI. The entire architecture of your program needs to be changed to support it.

Generally you'll use a timer which will interrupt at a predefined rate - usually 1ms is good for most applications. There will be a global integer that keeps track of elapsed time - how many milliseconds have passed since your program starts up (i.e., how many times the timer interrupt has been executed). Whenever you want a function to execute periodically instead of a delay you'll have a variable that keeps track of the last time index that it happened at and you'll query the current elapsed time. If the difference between is equal to the period you want the function to be called then you call it. Otherwise, you do nothing. In this paradigm you can't use any delay statements in your program. Any delay statements will throw off your timing.

For your application, it looks like you want to step your motors every 5ms, so that would be your time period. You'll have to keep track of what state each of the motors is in so you know what inputs to apply to them next. You can keep track of this in your step_one and step_two functions with function static variables and you can use a switch case to handle each state. In each state you'll set the inputs to the stepper motor and then assign the state variable to the next state: 0->1, 1->2, 2->3, 3->0

Eventually, you can modify the step_one and step_two functions to take a direction argument so you can move the motors in both directions or hold them still.