28 Шаговый двигатель BYJ работает быстрее при использовании задержки() и немного медленнее при использовании миллис(). Почему?

Я работаю над разработкой кода шагового двигателя, чтобы использовать его в проекте. И поскольку использование задержки() не так эффективно, как использование millis(). Поэтому я сначала разработал код, который использует задержку с задержкой в 1 мс между шагами, что является самым быстрым, что я мог сделать с этим шаговым двигателем.

Затем я разработал аналогичный код, используя millis() с той же задержкой в 1 мс, но он не был таким плавным/быстрым, как код с функцией задержки().

Так в чем же причина?

Это код:

  1. С задержкой():

        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. С помощью 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;
        }    
      }
    }
    

, 👍0

Обсуждение

зачем вам повторять digitalWrite(in1, LOW); пять раз подряд? .... вам нужно запустить его только один раз .... то же самое и с другими выводами .... кроме того, if(stepper_run){ вместо этого должно быть else, @jsotola

@jsotola 1. Как запустить его один раз? И в какой функции? 1-й или 2-й опубликованные коды? 2. Получил совет по использованию else, спасибо., @R1S8K

Как вообще может работать вторая функция? Что, если вы введете в Stepper_run_cw Stepper_run = 0, а миллис не изменится, ничего? Вызов Stepper_step_cw, который что-то делает, является чисто случайным, тот, в котором миллис изменился с момента последнего вызова Stepper_step_cw., @Dorian

попробуйте использовать micros() вместо millis(), @jsotola

у меня только что возникла мысль..... интересно, имеет ли порядок команд digitalWrite какое-либо отношение к разнице в скорости.... одна - 4321, а другая - 1234.... ....... измените порядок в одном из них ....... также поместите stepper_start = millis(); вверху блока if, @jsotola

@jsotola да, micros() тоже работает, я могу увеличить скорость еще быстрее :) спасибо за совет., @R1S8K


2 ответа


1

Возможно, для второй функции вам нужно что-то вроде этого:

 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){};//подождем, пока миллис изменится
  }
    digitalWrite(in1, m_in1);
    digitalWrite(in2, m_in2);
    digitalWrite(in3, m_in3);
    digitalWrite(in4, m_in4);
}

Этот код также позволяет избежать проблемы переполнения миллис, если вы используете плату в течение длительного времени.

Тем не менее, за исключением улучшения времени, использование millis() не дает никакой выгоды, вам все равно придется ждать изменения миллис, вы можете использовать прерывание таймера, чтобы выполнить работу в фоновом режиме.

>
,

Реальное преимущество использования millis() заключается в том, что вы не блокируетесь в delay() и можете реагировать на изменение входных данных, не прибегая к прерываниям., @ratchet freak

Да, это моя цель. Не следует использовать «задержку». Хм, я все еще подумываю об улучшении функции, которая использует millis(), она все равно работает, просто дает другой результат, например, немного медленнее, вот и все. В остальном это работает как шарм :), @R1S8K


0

Поработав несколько раз над разработкой функции, я научился работать с этой функцией, и она тоже работает гладко :)

Надеюсь, это кому-нибудь пригодится.

// эта библиотека для шагового двигателя 28BYJ

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

  // моргаем
  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);// поместите сюда свой установочный код для однократного запуска:
    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;
      }    
    }
  }
,