Измерение скорости двигателя постоянного тока с помощью поворотного энкодера

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

boolean check;
boolean start;
unsigned int angle = 5;   //angle moved per encoder tick
unsigned long volatile time1;
unsigned long volatile time_11;
unsigned long interrupt_time;

void setup() {
  Serial.begin(9600);
  while (!Serial) ;
  pinMode(21, INPUT);  //Pin#21=interrupt pin, matched to interrupt#2
  attachInterrupt(digitalPinToInterrupt(2), speed, FALLING);
  time1 = 0;
  time_11 = 0;
  interrupt_time = 0;
  check = true;
  start = false;
  time_11 = millis(); //Start Clock
}

void loop() {
  if(time1 == interrupt_time && start) //Both times same , hence bool start.
  {
    if(check)
    {
      Serial.print(millis());  //Time taken to rise to steady speed.
      check = false;
    }
    Serial.println((angle/time1)*1000);   //Display Speed.
  }
  interrupt_time = time1;
  start = false;
  while(!start)
    {}
}

void speed(void) {
  start = true;
  time1 = millis()-time_11;
  time_11 = millis();
}

Я хочу, чтобы код был как можно более эффективным.У меня есть около 100 тиков на 360 градусов от моего кодера.Есть ли вероятность "пропустить" прерывание?

, 👍5

Обсуждение

Я думаю, что вам было бы лучше рассчитать скорость на основе количества импульсов в течение определенного промежутка времени, а не времени одного импульса. Во-вторых, вы должны использовать атомарные операции над многобайтовыми переменными, которые изменяются подпрограммой прерывания. Например, во время сравнения "time1" в " цикле может быть вызван ISR, и значение time1` изменится. Оператор if мог бы сравнить первые два байта long, но затем проверяет последние два байта нового значения. Надеюсь, в этом есть смысл., @Gerben

millis (), вероятно, не будет работать для этого, если только ваш двигатель не работает медленно и ваш кодер низкого разрешения, как правило, между событиями кодера будет меньше миллисекунды. Если вы действительно хотите засечь отдельные события, научитесь использовать аппаратный таймер и соответствующим образом подключайте входы. В противном случае лучше подсчитывать события за определенный период времени. В зависимости от проводки и деталей вы можете подсчитывать события в режиме счетчика аппаратного таймера., @Chris Stratton

Однако режим счетчика таймера HW плохо масштабируется. Взятие временной метки четного и вычисление дельты от предыдущего позволяет использовать даже контакты PCINT., @Igor Stoppa

Serial.println((angle/time1)*1000); Будьте осторожны, чтобы не делить на 0. Также имейте в виду, что это целочисленное деление, и поэтому оно будет усечено (перед умножением на 1000)., @Adrian McCarthy

Как быстро, по-вашему, будет работать мотор? И как быстро вы хотите отчитаться о скорости?, @Dave X


2 ответа


1

Всего пара замечаний:

  1. начало должно быть изменчивым, но вы можете удалить его и просто проверить , что time1 != 0.

  2. нет смысла дважды вызывать millis() внутри процедуры обслуживания прерываний:

void speed(void) {
  unsigned long now = millis();
  time1 = now - time_11;
  time_11 = now;
}
,

1

Спасибо вам за отзывы! Это моя попытка рассчитать скорость с помощью метода усреднения.

unsigned long volatile encodercount;
unsigned long encodercount_previous;
unsigned long volatile timer;
unsigned int angle;
boolean first;
boolean firstencodertick;
void setup() {
      angle=3;
      encodercount=0;
      encodercount_previous=0;
      Serial.begin(9600);
      while (!Serial); 
      pinMode(21,INPUT);  //Pin#21=interrupt pin, matched to interrupt#2
      attachInterrupt(digitalPinToInterrupt(2),speed,FALLING);
      first=true;
      firstecnodertick=true;
        }

  void loop() {
     delay(100); 

   if(encodercount==encodercount_previous&&encodercount!=0)
    {
   if(first)
     {
   Serial.println(millis()-timer);  //Steady State Time Taken 
   first=false;
     }
  Serial.println((encodercount); //Angle Moved in 0.1second.  
    }
  encodercount_previous=encodercount;
  encodercount=0;   
   }


  void speed(void)
 {
 if(firstencodertick)
 {
 timer=millis();
 firstencodertick=false;
  }
 encodercount++; 
}
,