Помогите. Часы на шаговом двигателе

Megawollt
Offline
Зарегистрирован: 06.12.2015

Господа. Скетч взят из этой темы. https://www.thingiverse.com/thing:2381829

Мотор вращается в полшага со скоростью один оборот в минуту.

Мне нужно получить один оборот в 6 минут, то есть в 6 раз медленнее, но любые попытки сделать delay больше или меньше заставляют двигатель вращаться быстрее. Что я делаю не так? Вот скетч


#define OUT1  3 // Connect pin A1 of the Arduino to pin IN4 of the stepper board
#define OUT2  1 // Connect pin A2 of the Arduino to pin IN3 of the stepper board
#define OUT3  0 // Connect pin A3 of the Arduino to pin IN2 of the stepper board
#define OUT4  2 // Connect pin A4 of the Arduino to pin IN1 of the stepper board

int countStep = 0; // Initialize countStep

void setup() // Handle setup
{
  pinMode(OUT1, OUTPUT); // Use A1 as a digital output
  pinMode(OUT2, OUTPUT); // Use A2 as a digital output
  pinMode(OUT3, OUTPUT); // Use A3 as a digital output
  pinMode(OUT4, OUTPUT); // Use A4 as a digital output
}

void loop() // Handle loop
{
  stepping(); // Call stepping
  delayMicroseconds(30943);  // Pause loop, use value of 30943 for timekeeping or 1000 for testing at high speed
}

void stepping() // Handle stepping
{
  switch(countStep) // Handle each step of countStep
  {
   case 0:
     digitalWrite(OUT1, LOW); 
     digitalWrite(OUT2, LOW);
     digitalWrite(OUT3, HIGH);
     digitalWrite(OUT4, HIGH);
   break; 
   case 1:
     digitalWrite(OUT1, LOW); 
     digitalWrite(OUT2, LOW);
     digitalWrite(OUT3, HIGH);
     digitalWrite(OUT4, LOW);
   break; 
   case 2:
     digitalWrite(OUT1, LOW); 
     digitalWrite(OUT2, HIGH);
     digitalWrite(OUT3, HIGH);
     digitalWrite(OUT4, LOW);
   break; 
   case 3:
     digitalWrite(OUT1, LOW); 
     digitalWrite(OUT2, HIGH);
     digitalWrite(OUT3, LOW);
     digitalWrite(OUT4, LOW);
   break; 
   case 4:
     digitalWrite(OUT1, HIGH); 
     digitalWrite(OUT2, HIGH);
     digitalWrite(OUT3, LOW);
     digitalWrite(OUT4, LOW);
   break; 
   case 5:
     digitalWrite(OUT1, HIGH); 
     digitalWrite(OUT2, LOW);
     digitalWrite(OUT3, LOW);
     digitalWrite(OUT4, LOW);
   break; 
     case 6:
     digitalWrite(OUT1, HIGH); 
     digitalWrite(OUT2, LOW);
     digitalWrite(OUT3, LOW);
     digitalWrite(OUT4, HIGH);
   break; 
   case 7:
     digitalWrite(OUT1, LOW); 
     digitalWrite(OUT2, LOW);
     digitalWrite(OUT3, LOW);
     digitalWrite(OUT4, HIGH);
   break; 
   default:
     digitalWrite(OUT1, LOW); 
     digitalWrite(OUT2, LOW);
     digitalWrite(OUT3, LOW);
     digitalWrite(OUT4, LOW);
   break; 
  }
   
   countStep=countStep+1; // After each cycle add 1 to countStep
   if(countStep==8)
     {countStep=0;} // Reset countStep on rollover
}

 

kalapanga
Offline
Зарегистрирован: 23.10.2016

Может причина тут: delayMicroseconds()

"В данной версии Ардуино максимальная пауза воспроизводимая корректно — 16383. Возможно это будет изменено в следующих версиях Arduino. Для остановки выполнения программы более чем на несколько тысяч микросекунд рекомендуется использовать функцию delay()."

Megawollt
Offline
Зарегистрирован: 06.12.2015

Ясно, но тогда пауза в миллисекундах получается 185.66. Точность потеряется

kalapanga
Offline
Зарегистрирован: 23.10.2016

Megawollt пишет:

Ясно, спасибо

Вроде аргумент у неё типа unsigned int, может уже устаревшая цитата. Потестируйте.

Megawollt
Offline
Зарегистрирован: 06.12.2015

Я думаю проще от делей отказаться и использовать таймер

andryn
Offline
Зарегистрирован: 08.06.2018

Можно сделать что-то вроде этого:

...
unsigned long timePrev;
...
void setup(){
...
    timePrev = micros();
...
}

void loop(){
    if (micros()-timePrev > 30943*6 || micros()-timePrev < 0) {
        stepping();
        timePrev = micros();
    }
}
...

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Для часов в любом случае лучше таймер и прямая запись в порт состояний сразу всех выходов из массива.

А еще лучше взять драйвер степпера и из точного генератора в него пульсировать.

PS. Извините, не посмотрел, что мотор униполярный. Тогда в силе только первый абзац.

nik182
Offline
Зарегистрирован: 04.05.2015

Да ладно? А кто мешает сначала delay(186), a потом delaymicrosecond(660)? И подобрать 660 поточнее?

sadman41
Offline
Зарегистрирован: 19.10.2016

Да по всякому можно. Вопрос только в том, насколько часто их подводить придется ))

Я за примерно такой вариант:

volatile uint8_t currentStep;

volatile uint8_t motorStep[] = {
  B00000011,
  B00000110,
  B00001100,
  B00001001,
...
};

ISR_...() {
  PORTB = motorStep[currentStep];
  if (sizeof(motorStep) >= currentStep) {
     currentStep = 0;
  } else {
     currentStep++;
  }
}

...

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Megawollt пишет:

пауза в миллисекундах получается 185.66. Точность потеряется

delay(185);
delayMicroseconds(66);

 

Megawollt
Offline
Зарегистрирован: 06.12.2015

Мотор переделан в биполярный. Драйвер l293d

Пока тестирую с простым delay, а дальше буду тестить то, что вы мне посоветовали

sadman41
Offline
Зарегистрирован: 19.10.2016

С биполярным еще проще: мотор к A4988 и на каждом срабатывании таймера blink одним пином в STEP драйверу на 5мкс. Программа уменьшается втрое. В тиньку зашьете легко.