Проблемы с ШИМ и подключением прерываний

Я пытаюсь управлять скоростью двигателя постоянного тока с помощью ШИМ.

Я использую Arduino UNO для отправки ШИМ-сигнала на мосфет Velleman vma411, чтобы изменить среднее напряжение моего двигателя, который подключен к стабилизированному источнику питания (около 10 В). Чтобы получить частоту вращения моего двигателя, у меня есть датчик Холла рядом с осью вращения. Каждые пол-оборота датчик меняет значение (0 или 5 В). Чтобы обнаружить изменения, я использую attachInterrupt() для обнаружения изменений.

Когда Arduino не отправляет ШИМ-сигнал, измеренная частота в порядке (я проверил это с помощью осциллографа). НО когда я посылаю сигнал ШИМ на двигатель, частота больше не имеет смысла (примерно 1 значение из 3 в 10 раз превышает ожидаемое).

Чтобы решить эту проблему, я попробовал три разных способа:

  • установка конденсатора (от 100 до 2200 микроФ) между Arduino и сигнальным портом МОП-транзистора,
  • используя среднее значение последних 10 измеренных частот.
  • добавление числового фильтра,
  • используя один контакт земля для мосфета и другой для порта датчика,

Тем не менее, любая из этих идей действительно сработала для меня.

Полагаю, это может быть связано с какими-то проблемами с электрическим отражением? Может быть, мне стоит сменить мосфет или использовать L298N?

Заранее спасибо

Мой код, цель которого — точно измерить частоту вращения при отправке ШИМ-сигнала на МОП-транзистор:

/*
alimentation du capteur : 4V
mesure précise jusqu'à au moins 10V
*/

//порты
int rotation_port = 3;
int mosfet_sig_port = 11;
int debug_port = 10;

//меры:
volatile long t_new;
volatile long t_old;
volatile long res;
volatile float frequence;
volatile float old_frequence;

// утверждающий
float rapport_cyclique = 127; //вход 0 и 255

void setup() {
  pinMode(rotation_port, INPUT_PULLUP); // прерывание заливки
  attachInterrupt(digitalPinToInterrupt(rotation_port), capteur_hall_changement, FALLING);
  pinMode(debug_port, OUTPUT);
  pinMode(mosfet_sig_port, OUTPUT);
  Serial.begin(115200);
  old_frequence = 100;
}

void capteur_hall_changement() {
  t_new = micros();
  res = 1.0 / (t_new - t_old) * 1000000;
  if (res/old_frequence <= 1.5) {
    frequence = res;
    old_frequence=frequence;
  }
  t_old = t_new;
  Serial.println(frequence);
}


void loop() {
  // Отправка сигнала PWM при цифровой вылете mosfet_sig_port
  analogWrite(mosfet_sig_port, int(rapport_cyclique));
}

, 👍1

Обсуждение

1. Не используйте Serial.println() в контексте прерывания. 2. frequence и old_frequence избыточны (они всегда одни и те же). 3. В чем смысл «if (res/old_frequence <= 1.5)»?, @Edgar Bonet

цель if (res/old_frequence <= 1.5) — удалить меры, которые не должны появляться. Я хочу измерить частоту около 100 Гц, но некоторые измерения без причины дают частоту 200 Гц, поэтому целью была их численная фильтрация., @Grégoire Lefebvre


1 ответ


0

Когда вы используете прерывания, ваш ШИМ может работать неправильно, поэтому не используйте их оба одновременно.

,