Столкновение прерываний таймера
Я работаю с MEGA2560, пытаясь реализовать скоростные рампы для трех степперов одновременно. Цель состоит в том, чтобы двигаться в разные позиции, применяя ускорения и замедления, одновременно завершая их все.
Чтобы сделать это, исходя из расстояний, на которые должен двигаться каждый из двигателей, я вычисляю количество шагов, которые нужно сделать, и скорости для каждого из этих шагов, чтобы гарантировать, что все двигатели закончат работу одновременно. Для этого я использую таймеры 3, 4 и 5 в режиме сравнения. Таким образом, при каждом перерыве я заставляю двигатели делать один шаг и после этого устанавливаю новое значение сравнения для таймера, чтобы достичь новой скорости движения.
Моя проблема в том, что в какой-то момент мои прерывания терпят крах, и один из двигателей перестает работать. Это происходит только при одном условии: когда двигатель 1 должен сделать 18 шагов, а двигатель 2-34. В этом случае оба двигателя 1 и 3 заканчивают работу, но двигатель 2 застревает и больше не движется. Хотя, если его мотор 1, который должен сделать 34 шага, и мотор 2, 18, то все работает. Двигатель 1 связан с таймером 3, а двигатель 2-с таймером 4. Это наводит меня на мысль, что это должно быть связано с приоритетами прерываний.
В следующем коде вы можете увидеть мои прерывания:
ISR(TIMER3_COMPA_vect) {
m1_step();
m1_steps_done++;
m1_configure_vel();
}
ISR(TIMER4_COMPA_vect) {
m2_step();
m2_steps_done++;
m2_configure_vel();
}
ISR(TIMER5_COMPA_vect) {
m3_step();
m3_steps_done++;
m3_configure_vel();
}
В то время как в конфигурации скорости я имею:
void m1_configure_vel() {
if (m1_steps_done < m1_acceleration_steps) {
m1_temp_vel = m1_temp_vel + acceleration;
}
else if (m1_steps_done <= (m1_steps - m1_acceleration_steps)) {
m1_temp_vel = m1_temp_vel;
}
else if (m1_steps_done < m1_steps) {
m1_temp_vel = m1_temp_vel - acceleration;
}
else {
m1_temp_vel = 0;
m1_finished = true;
}
if (m1_temp_vel <=0){
m1_temp_vel = 0;
}
OCR3A = frequency_to_compare_value(m1_temp_vel);
}
Как вы можете видеть, все, что я делаю здесь, зависит от шагов, выполняемых двигателем, и количества шагов, которые нужно сделать, я увеличиваю, поддерживаю или уменьшаю скорость двигателя и устанавливаю значение сравнения для таймера.
Все дело в том, что этот код работает нормально, пандусы рассчитаны правильно, а двигатели двигаются правильно. Проблема в том, что при условии, которое я объяснил ранее, прерывания могут сталкиваться из-за их приоритетов, и один из них просто перестает происходить.
Мне было интересно, имел ли кто-нибудь представление или сталкивался с чем-то подобным раньше.
@Izar Thomson, 👍1
Обсуждение2 ответа
Я думаю, что проблема вызвана размером ваших ISR. При использовании ISR важно сделать код как можно короче, и вы, конечно же, должны избегать использования каких-либо функций!
Я бы изменил каждый из ваших ISR на:
ISR(TIMER3_COMPA_vect) {
m1_steps_done++;
}
ISR(TIMER4_COMPA_vect) {
m2_steps_done++;
}
ISR(TIMER5_COMPA_vect) {
m3_steps_done++;
}
затем в главном цикле кода вы можете изменить его так, чтобы, если m1_steps_done, m2_steps_done или m3_steps_done увеличились, выполнить шаг и настроить функции
Другой подход может заключаться в использовании одного таймера вместо 3 отдельных. Поддерживайте 3 программных счетчика и увеличивайте их все на каждом прерывании с отдельными предельными тестами и сбросами. Это будет немного медленнее, но не будет возможности столкновений.
- Установка timer3 в режиме CTC - конфликт с сервобиблиотекой
- Как измерить ультразвуковой датчик без импульсного метода?
- Как выйти из прерывания таймера (ISR(TIMER1_COMPA_vect))
- Arduino IDE с ошибкой ATtiny85 «множественное определение `__vector_5»
- Проблема прерывания библиотеки MPU6050 Arduino Jeff Rowberg
- Arduino Mega TIMER1 интервал в одну секунду
- Изменчивая переменная не обновляется с таймера ISR
- Таймеры, выводы ШИМ и цифровые выходы на Arduino Mega
Это странная проблема. Как я знаю, на чипах AVR нет приоритета прерывания. Если происходит прерывание, в то время как другой ISR в настоящее время работает, соответствующий флаг установлен, и выполнение ISR произойдет после завершения первого ISR. У вас есть доступ к осциллографу или логическому анализатору? Было бы неплохо проверить, выводится ли ожидаемый сигнал на вывод motor2. Возможно, есть аппаратная проблема. Или у вас есть какой-то код, который может использовать один из таймеров?, @chrisl
Спасибо за ваш ответ @christl . Я отбрасываю аппаратные проблемы, так как вся система работает во всех других ситуациях. Теперь я попытался изменить прескалер таймеров. Они были установлены на 1, но теперь я настроил их на 8, так что таймеры теперь имеют частоту 2 МГц. Удивительно, но теперь система не дает сбоев, вся последовательность выполняется без ошибок, и ни одно прерывание не замерзает. Я полагаю, что, уменьшив частоту таймеров, они могут теперь работать под меньшим "давлением", так что они могут не ударять друг друга., @Izar Thomson
@chrisl Существует то, что называется "естественным приоритетом" - каждый интрерупт имеет свой номер, и они проверяются последовательно - прерывания с более низкими номерами происходят раньше прерываний с более высокими номерами. Если прерывание с более низким номером повторится до того, как появится шанс запустить прерывание с более высоким номером, то оно будет ответлено предпочтительнее, чем прерывание с более высоким номером. Вот почему ISR должны быть как можно короче., @Majenko
@Majenko Я реализовал эти прерывания таймера на частоте, намного превышающей ту, о которой я упоминал ранее. Когда это происходит и мои прерывания прекращаются, ни один из них не имеет частоты выше 500 Гц, в то время как с тем же кодом они могут совершать одновременные движения на 4 кГц. При этом я имею в виду, что мой код внутри прерываний не длится достаточно долго, чтобы не допустить других прерываний. В моем критическом случае частоты ISR достаточно низки, чтобы запустить весь код внутри, но без смысла один из них просто застревает., @Izar Thomson
@Majenko О, интересно. Я этого не знал, спасибо :), @chrisl
Я удивлен, что никто не попросил вас опубликовать компилируемый код. У нас даже нет соответствующих типов данных., @timemage