Speed loop execution time

I am running a voltage sensor and stepper motor. The motor moves a piece and I get a read from the voltage sensor. The code needs to accomplish 2 things:

  1. get a voltage from a sensor

  2. run a stepper motor at desired speed (using the millisBetweenSteps variable) for n number of cycles (using maxSteps).

I am using microstepping to smooth the motor vibrations.

The code that I have accomplishes the task. However, the time between loop iterations is around 3 ms (see Serial.println(curMillis - prevStepMillis); on singleStep()).

This means that any increment in speed will have to be by reducing multiples of 3 ms, and interval below 3 ms will be max velocity. The current movement is quite smooth but is not as fast as I would like (and the 3 ms increment is tricky). If possible, I would like to keep the microstepping (currently at 16) but be able to execute the step order faster (maybe every 0.1 ms) with a finer speed control (maybe 100 microsecond interval)

My question is:

Is 3 ms an acceptable time for this script? How can I know what’s taking it so long? Is there something to optimize ?

spinning_disk.ino (4.07 KB)

Please post your code.

// PINS //
int stepPin = 6;  //PUL -Pulse
int dirPin = 7; //DIR -Direction
int enPin = 8;  //ENA -Enable
int LED = 13;

// -----------------------------


float currentStep = 0.0; // placeholder for current step
int stepSpeed = 10;      // milliseconds that take to make a step // deprecated
int maxSteps = 1000;      // max numebr of steps (200 steps is 360 degree rotation). 
                        // Keep in mind microstepping adjustment might be needed
boolean rotation = 0;    // change here rotation == 1 is "HIGH", motor clockwise 
                        // rotation == 0 is counter clockwise (that's what we want)

// -- time variables -- //
unsigned long curMillis; 
unsigned long prevStepMillis = 0;
unsigned long millisBetweenSteps = 1; // milliseconds that take to make a step

// VOLTAGE ///

int voltagePin = A0; // Voltage reading 
int voltageRead = 0;  // variable to store the value read, needs to be remaped
float voltage = 0; // mapped voltage goes from 0 to 1

// --------------------------


// we are using R1 = 30KΩ and R2 = 7.5KΩ i.e. a 5 to 1 voltage divider (v_divider)

float R1 = 30000.0;
float R2 = 7500.0;

// This is the factor we need to divide
float factor = (R2/(R1+R2));
float realVoltage = 0; // initialize 

// -----------------------------

void setup(){
 Serial.begin(9600);           //  setup serial
 //Sets the pins as Outputs
 pinMode(stepPin, OUTPUT); 
 pinMode(dirPin, OUTPUT);
 pinMode(enPin, OUTPUT);
 // this engages the motor
 digitalWrite(enPin, LOW);
 pinMode(LED, OUTPUT);
 pinMode(voltagePin, INPUT);
 // Enables the motor direction to move
 // we can later add a changeDirection() if we believe it's useful

 // The real step is maxSteps * microstepping on the driver (currently at 16)
 maxSteps = maxSteps * 16;


void loop(){
 // voltage reading here

 // get time
 curMillis = millis();

// Actually move direction
 if(currentStep < maxSteps){
   // moveStepper();
   currentStep = currentStep + 1;
 } else { 
  // disengage motor
  digitalWrite(enPin, HIGH);
 // stop condition here



void setDirection(){
 if (rotation) {
   // do stuff if the condition is true
   digitalWrite(dirPin, HIGH);
 else {
   // do stuff if the condition is false
   digitalWrite(dirPin, LOW);

// -----------------------------
// This function is a bad idea because it uses delay()
// delay() stops the loop until it's finished, so we can't sample if we are using this
// kept for informative purposes

void moveStepper(){

// loop
for(int x = 0; x < maxSteps; x++){


void singleStep() {

   // check how often the steps are being called  
   // Serial.println(curMillis - prevStepMillis);
   if (curMillis - prevStepMillis >= millisBetweenSteps) {
       // replace old value with new time
       prevStepMillis = curMillis;
       // step on-off
       digitalWrite(stepPin, HIGH);
       digitalWrite(stepPin, LOW);

// -----------------------------

void getVoltage(){

 // read analog pin
 voltageRead = analogRead(voltagePin);  // read the input pin

 // The max value read will be 2V at the exit of the voltage sensor
 // This comes from the 10V max Novotechnick sensor output divided by 5 in our voltage sensor config

 // 2V equals to an analog read signal of 1023/2.5 = 409.2
 // We use this value to remap from 0 to 1
 // map(value, fromLow, fromHigh, toLow, toHigh) map not working as intended
 // voltage = map(voltageRead, 0, 409.2, 0, 1);
 realVoltage = (voltageRead /409.2) / factor;

 // realVoltage will have a max value of 5V ()
 // If we want to match this to the output from the magnetic field sensor (10V)
 // We just double that

 realVoltage = realVoltage * 2;
 Serial.println(realVoltage);          // debug value 
//  Serial.println("V");

// -----------------------------

This looks WRONG. You are calling singleStep(), which only steps if millisBetweenSteps has elapsed, and record that as a completed step. You seem to be counting steps that don’t occur. You will not reach the expected position if you count steps that don’t occur.

  if(currentStep < maxSteps){
    // moveStepper();
    currentStep = currentStep + 1;

You should get rid of the Serial.println() in singleStep(). That is probably what slows down you sketch.

Thank you! That's indeed a good catch, I hadn't realized because my time between steps was always to low. I was always below 3 ms and I added the print line to try to catch what was going on with it. I was trying to run it at 0.01 ms, 0.1 ms and 1 ms and everything went at the same speed. Your comment is useful, I am now updating the step inside singleStep().

For my purposes, I need to print voltage out via serial print so I would hope that printing command is not the problem.

matiasandina: For my purposes, I need to print voltage out via serial print so I would hope that printing command is not the problem.

How often do you print out the voltage and how many characters do you print? At 9600 baud you can print an average of about 1 character per millisecond. Try any faster than that and the output buffer will fill up and you will have to wait a full millisecond for each character you print. You could use a higher baud rate. My favorite is 115200.

Awesome! such a newbie that I didn’t realize the baud rate would mess with this, I’m so used to using the 9600 that I don’t normally thing about it. Now, it looping in the tens of microseconds :slight_smile: