Проблема с тахометром с использованием AttachInterrupt и сервопривода

Итак, я создаю тахометр, используя черно-белый детекторный датчик. Вот код.

unsigned long WaktuOLD;
unsigned long WaktuNOW;
int Detection = HIGH;
int Counter = HIGH;
float HitungWaktu;
float HitungRPM;

void setup() {
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(3), rpm, RISING);
  WaktuNOW = millis();
}

void rpm() {
  Detection = digitalRead(3);
  if (Detection == HIGH && Counter == LOW) {
    WaktuNOW = millis();
    HitungWaktu = WaktuNOW - WaktuOLD;
    HitungRPM = 60 / (HitungWaktu / 1000);
    Counter = HIGH;
  } else if (Detection == HIGH && Counter == HIGH) {
    Counter = LOW;
    WaktuOLD = millis();
  }
}

void loop() {
  Serial.println(HitungRPM);
  delay(5000);
}

Код работает хорошо и правильно считывает RPM. А затем с того же Arduino я управляю серводвигателем, в данном случае я использую GWS03N/STD/F с этим кодом:

#include <Servo.h>

Servo myservo;
int pos = 0;

void setup() {
  myservo.attach(9);
}

void loop() {
  myservo.write(90);
}

И этот код тоже работает хорошо.

Но когда я пытаюсь объединить оба кода, хорошо работает только сервокод. Показания тахометра неправильные (показания должны быть в районе 1000-1500 об/мин, а сейчас показывают 3000-30 об/мин). Я уже пытаюсь изменить прерывание тахометра на контакт 2 или 3, а сервопривода на 3, 5, 6 и 9, но все то же самое.

Так что же здесь не так? Спасибо вам большое.

Это мой код при объединении обоих кодов.

#include <Servo.h>

Servo myservo;
int pos = 0;
unsigned long WaktuOLD;
unsigned long WaktuNOW; 
int Detection = HIGH;
int Counter = HIGH;
float HitungWaktu;
float HitungRPM;

void setup() {
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(3), rpm, RISING);
  WaktuNOW = millis();
  myservo.attach(9);
}

void rpm() {
  Detection = digitalRead(3);
  if (Detection == HIGH && Counter == LOW) {
    WaktuNOW = millis();
    HitungWaktu = WaktuNOW - WaktuOLD;
    HitungRPM = 60 / (HitungWaktu / 1000);
    Counter = HIGH;
  } else if (Detection == HIGH && Counter == HIGH) {
    Counter = LOW;
    WaktuOLD = millis();
  }
}

void loop() {
  Serial.println(HitungRPM);
  myservo.write(90);
  delay(5000);
}

, 👍2


2 ответа


0

Все переменные, к которым осуществляется доступ внутри ISR, необходимо объявить как изменчивые.

Вы используете прерывание RISING, поэтому нет необходимости проверять вывод в ISR. Вы можете быть уверены, что он перешел в HIGH для запуска прерывания.

,

Я поправился. Я, должно быть, неправильно прочитал номер пина. Тем не менее, переменные должны быть изменчивыми., @Delta_G

Это опечатка в одном из номеров пинов в Detection var, я уже исправил ее. И я уже пытаюсь сделать volatile WaktuOLD, WaktuNOW, Detection, Counter, HitungWaktu и HitungRPM, но это все еще не помогает. Я не пробовал удалить Detection var., @Naufal B


2

Возможно, ваша проблема связана с конфликтами прерываний.

В 8-битных Ардуино нет концепции приоритетов прерываний. Когда выполняется одна программа прерывания, невозможно запустить любую другую процедуру прерывания, пока не завершится первая.

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

Проблема здесь в том, что сервобиблиотека использует таймер (и связанное с ним прерывание) для генерации сигнала. При этом используется множество постоянно выполняемых вызовов прерываний - и пока они выполняются, ваше внешнее прерывание не может быть вызвано - по крайней мере, до тех пор, пока не завершится выполняющееся в данный момент прерывание таймера, после чего будет вызван ваш внешний обработчик прерываний, поскольку он высший приоритет.

Поэтому результаты, которые вы получите при всех этих задержках, совершенно бессмысленны.

И что же вы можете сделать? Что ж, есть несколько вариантов, каждый из которых предполагает не использование прерываний.

  • Вы не можете использовать библиотеку Servo.h и вместо этого перенастроить аппаратную ШИМ на правильную частоту и использовать ее для сервопривода.
  • Вы можете использовать один из таймеров с внешним источником синхронизации для подсчета импульсов тахометра (я думаю, что таймер 1 имеет такую возможность на Uno)

Или еще лучше: сделайте и то, и другое. Это даст вам наиболее эффективную систему, в которой основной процессор будет участвовать только в периодическом получении счетчика от таймера и настройке значения ШИМ для вашего сервопривода. Остальное выполняется аппаратно полностью асинхронно.

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

,

Существуют ли другие библиотеки вместо «Servo.h», которые могут решить эту проблему?, @Tharindu Sathischandra

Не то чтобы я об этом знал, но существует множество руководств по изменению частоты ШИМ., @Majenko

[Это](http://arduiniana.org/libraries/pwmservo/) может вас заинтересовать..., @Majenko

Можем ли мы использовать PWMServo так же, как Servo.h?, @Tharindu Sathischandra

Это зависит от того, какие таймеры оба используют. Если у них разные таймеры, то конечно. Если нет, то нет., @Majenko

Можем ли мы решить проблему, используя две отдельные платы Arduino Uno: одну для датчика и одну для сервопривода?, @Tharindu Sathischandra

Конечно, если на связь между ними это тоже не влияет, и поскольку при этом обычно также используются прерывания, вы, вероятно, столкнетесь с некоторыми проблемами., @Majenko

Я должен прокомментировать :-). Этот ответ идеален. Сначала, когда я увидел награду, я подумал, что Таринду выбросил свои очки за эту награду. Я никогда не работал с прерываниями сервопривода или энкодера, но я знал, что 328p пропускает прерывания RPM, поскольку библиотека сервоприводов использует прерывания для генерации импульсов. Но у меня не было решения. И возможность заменить оба элемента управления внутренней периферией MCU идеальна., @Juraj

@Юрай Да, я очень близко понял ответ. Но до сих пор я понятия не имею, как решить мою проблему. Можете ли вы предложить путь для начала?, @Tharindu Sathischandra

Я бы начал с тахогенератора. Прочтите техническое описание и узнайте, как настроить таймер 1 для использования вывода T1 в качестве тактового входа и подсчета тактовых импульсов., @Majenko