0

I'm working to develop a code for the stepper motor to use it in a project. And since using delay() isn't as efficient as millis(). So I first developed the code that use delay with 1ms delay between the steps which is the fastest I could do with this stepper motor.

Then I developed similar code using millis() with same 1ms delay but it didn't feel as smooth/fast as the one with delay() function.

So what's the reason for that?

These are the code:

  1. With delay():

        void clockwise(void){
            digitalWrite(in4, HIGH);
            digitalWrite(in3, LOW);
            digitalWrite(in2, LOW);
            digitalWrite(in1, LOW);
        delay(1);
            digitalWrite(in4, HIGH);
            digitalWrite(in3, HIGH);
            digitalWrite(in2, LOW);
            digitalWrite(in1, LOW);
        delay(1);  
            digitalWrite(in4, LOW);
            digitalWrite(in3, HIGH);
            digitalWrite(in2, LOW);
            digitalWrite(in1, LOW);
        delay(1);    
            digitalWrite(in4, LOW);
            digitalWrite(in3, HIGH);
            digitalWrite(in2, HIGH);
            digitalWrite(in1, LOW);
        delay(1);
            digitalWrite(in4, LOW);
            digitalWrite(in3, LOW);
            digitalWrite(in2, HIGH);
            digitalWrite(in1, LOW);
        delay(1);    
            digitalWrite(in4, LOW);
            digitalWrite(in3, LOW);
            digitalWrite(in2, HIGH);
            digitalWrite(in1, HIGH);
        delay(1);      
            digitalWrite(in4, LOW);
            digitalWrite(in3, LOW);
            digitalWrite(in2, LOW);
            digitalWrite(in1, HIGH);
        delay(1);        
            digitalWrite(in4, HIGH);
            digitalWrite(in3, LOW);
            digitalWrite(in2, LOW);
            digitalWrite(in1, HIGH);
        delay(1);   
    }
    
  2. With millis():

      void stepper_run_cw(void){
      stepper_step_cw(1,0,0,0,1);
      stepper_step_cw(1,1,0,0,1);
      stepper_step_cw(0,1,0,0,1);
      stepper_step_cw(0,1,1,0,1);
      stepper_step_cw(0,0,1,0,1);
      stepper_step_cw(0,0,1,1,1);
      stepper_step_cw(0,0,0,1,1);
      stepper_step_cw(1,0,0,1,1);  
    }
    
    
    void stepper_step_cw(uint8_t m_in1, uint8_t m_in2, uint8_t m_in3, uint8_t m_in4, uint8_t delay_time){
      if (!stepper_run){
        digitalWrite(in1, m_in1);
        digitalWrite(in2, m_in2);
        digitalWrite(in3, m_in3);
        digitalWrite(in4, m_in4);
        stepper_start = millis();
        stepper_run = 1;
      }
    
      if(stepper_run){
        stepper_current = millis();
        if(stepper_current - stepper_start >= delay_time){
          stepper_run = 0;
        }    
      }
    }
    
  • why would you repeat digitalWrite(in1, LOW); five times in a row? .... you only need to run it one time .... same for the other pins ........... also, the if(stepper_run){ should be an else instead – jsotola Feb 14 at 6:09
  • @jsotola 1. How to run it one time? And in which function? The 1st or 2nd posted codes? 2. Got the tip about using else thanks. – R1S8K Feb 14 at 6:30
  • 1
    How can the second function work at all? What if you enter in stepper_run_cw with stepper_run = 0 and millis not changing , nothing? stepper_step_cw call that does something is purely random, the one where millis changed form the last call to stepper_step_cw. – Dorian Feb 14 at 8:19
  • try using micros() instead of millis() – jsotola Feb 14 at 17:22
  • i just had a thought ..... i wonder if the order of the digitalWrite commands has anything to do with the speed difference .... one is 4321 and the other is 1234 ................ change the order in one of them ....... also put stepper_start = millis(); at the top of the if block – jsotola Feb 14 at 17:27
1

Maybe for the second function you want something like this:

 void stepper_run_cw(void){
  stepper_step_cw(1,0,0,0,1);
  stepper_step_cw(1,1,0,0,1);
  stepper_step_cw(0,1,0,0,1);
  stepper_step_cw(0,1,1,0,1);
  stepper_step_cw(0,0,1,0,1);
  stepper_step_cw(0,0,1,1,1);
  stepper_step_cw(0,0,0,1,1);
  stepper_step_cw(1,0,0,1,1);  
}


void stepper_step_cw(uint8_t m_in1, uint8_t m_in2, uint8_t m_in3, uint8_t m_in4, uint8_t delay_time){
  unsigned long temp, i;
  for (i=0;i<delay_time;i++){
    temp = millis();
    while (temp == millis){};//wait for millis to change 
  }
    digitalWrite(in1, m_in1);
    digitalWrite(in2, m_in2);
    digitalWrite(in3, m_in3);
    digitalWrite(in4, m_in4);
}

This code is also avoiding the millis overflow issue if you run your board for a long time.

Still, apart for a improved timing, there is no gain in using millis(), you still have to wait for millis to change, you might want to use a timer interrupt to do the job in background.

  • The real gain when using millis() is that you aren't blocked in delay() and can react to inputs changing without needing to resort to interrupts. – ratchet freak Feb 14 at 10:42
  • Yes, that's my aim. Is not to use delay. Hmm I'm still considering to improve the function which uses millis(), it's working anyway, it just give a different result like littttle slower that's all. Otherwise it's works like a charm :) – R1S8K Feb 14 at 17:02
0

After working on developing the function couple times, I got a way with this function and runs smoothly too :)

Hope anyone find it useful.

// this library is for the 28BYJ stepper motor

  #define in1 6
  #define in2 7
  #define in3 8
  #define in4 9

  // blink
  unsigned long blink_start_millis;
  unsigned long blink_current_millis;
  unsigned long blink_period = 100;

  uint8_t stepper_masks[] = {0x80,0xc0,0x40,0x60,0x20,0x30,0x10,0x90};
  int8_t s=0;
  uint32_t stepper_start;
  uint32_t stepper_current;
  uint32_t stepper_period;
  byte stepper_run;

  void blink_pin13(void);
  void stepper_step(uint8_t *mask, uint8_t delay_time, uint8_t dir);

  void setup() {
    Serial.begin(9600);// put your setup code here, to run once:
    for(byte i=in1;i<=in4;i++){
      pinMode(i,OUTPUT);}

    pinMode(13,OUTPUT); 

  }

  void loop() {
   stepper_step(stepper_masks,1,0);
    blink_pin13();  

  }

  void blink_pin13(void){
      blink_current_millis = millis();
      if(blink_current_millis - blink_start_millis >= blink_period){
      digitalWrite(13, !digitalRead(13)); 
      blink_start_millis = blink_current_millis;
    }
  }

  void stepper_step(uint8_t *mask, uint8_t delay_time, uint8_t dir){
    if (!stepper_run){
      for(byte i=6;i<10;i++){
        digitalWrite(i, 0<(mask[s]&0x80>>i-6));
      }
      if(!dir){s++;if(s>7)s=0;}
      else {s--;if(s<0)s=7;}
      stepper_start = millis();
      stepper_run = 1;
    }

    if(stepper_run){
      stepper_current = millis();
      if(stepper_current - stepper_start >= delay_time){
        stepper_run = 0;
      }    
    }
  }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.