Не работает сервопривод на регистре b таймера 1 вместе с циклом Loop

Доброго времени суток! Столкнулся с проблемой на своей atmega328p, у меня есть сервопривод, его нужно крутить на “втором loop цикле”, а параллельно нужно что-нибудь печатать в порт. Я подключил библиотеки для прерываний, настроил регистр b таймера 1 и в обработчике прерываний кручу серво, а в loop печатаю, но серво не крутится, только печатается в порт. Кто знает где я просчитался?

#include <avr/io.h>
#include <avr/interrupt.h>
#include <Servo.h>

Servo servo;

void setup() {
  Serial.begin(115200);
  cli();
  TCCR1A = 0;
  TCCR1B = 0;
  TIMSK1 = (1 << TOIE1);
  TCCR1B |= (1 << CS10);
  sei();

  servo.attach(4);
  servo.write(0);
}

void loop() {
  servo.write(100);
  delay(100);
  servo.write(0);
  delay(100);
}

ISR(TIMER1_OVF_vect) {
  Serial.println("isr");
}

а в коде все наоборот - серво в ЛУП, а печать - в прерывании:

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

прежде чем задавать вопросы, приведите в соответствие текст и код.
Что у вас должно быть в ЛУП, а что в прерывании?

Какой смысл вам отвечать, если вы потом скажете, что имели в виду совсем другое?

Ну я попытаюсь перефразировать, должен ли работать функция ISR как второй loop цикл и если да то почему она печатает всего один раз в порт после запуска программы?

Я разве в #2 непонятно написал, в чем у вас проблема?
Я повторю:

Вот смотрите, в тексте сообщения вы пишете

А в коде у вас наоборот, в прерывании печать, а в ЛУП - серво.
Так где правильно?

Ответ на ваш вопрос зависит от того, что именно вы делаете в луп, а что в прерываниях.

Или вы считаете, что прерывания - это просто второй цикл луп и между ним, и основным циклом нет никакой разницы? - это не так.
Например, печатать в Сериал в прерывании нельзя.

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

Я брал этот образец из этой статьиArduino и прерывания таймера / Хабр
И там сказано
цитирую
“Timer1 установлен на прерывание по переполнению и давайте предположим, что вы используете Atmega328 с тактовой частотой 16 МГц. Поскольку таймер 16-битный, он может считать до максимального значения (2^16 – 1), или 65535. При 16 МГц цикл выполняется 1/(16 ∗ 10^6) секунды или 6.25e-8 с. Это означает что 65535 отсчетов произойдут за (65535 ∗ 6.25e-8 с) и ISR будет вызываться примерно через 0,0041 с. И так раз за разом, каждую четырехтысячную секунды. Это слишком быстро, чтобы увидеть мерцание.” Может я чего-то не понимаю.

Нет! Более того - нахождение в прерывании не должно долго длиться (Вы же прерыванием останавливаете основное выполнения кода).

Кстати Serial.print() достаточно долго выполняется, поэтому его и игнорируют по выполнении (прерывание может длиться очень не долго).

Вот давай ты не будешь писать про то чего не знаешь? Никто никого никогда не игнорирует при выполнении. Выполняется всё. Это программа, как написана так и будет выполняться. Прерывание может выполняться вечно. Ни кто ни где не ограничивал время выполнения прерывания. Можешь всю программу написать в прерывании и она будет там например моргать светодиодом без остановки. Другое дело может это одно, а должна это другое. Это как программист пожелает так и должна. В программе бывают и другие прерывания и им тоже хочется поработать.
Поэтому стараются быть в одном прерывании поменьше, что бы всем хватило времени.

Спорить с более опытными не в моей привычке. Значит я не правильно понял то, что мне объясняли на старом форуме несколько лет назад. Там я, как раз, почти всю программу запихал в прерывание и она не работала…

какое мерцание??? Вы в прерывании пытаетесь печатать.
Вы уверены, что вывод строчки “isr” 250 раз в секунду - это то что вы хотели?

1 лайк

При одном маленьком условии - если в программе не встретится другое прерывание.

И тут стоит вспомнить, что как раз вывод в Сериал это “другое прерывание” может и задействовать. И тогда все зависнет.

Что, как мне кажется, у ТС и происходит.

Если ей хотелось другие прерывания использовать, а ты её не давал, то вполне нормальное поведение. Тут ведь как - понимаешь что делаешь можно и в прерывании работать, а не понимаешь можно и … сломать.

1 лайк

Да всё правильно ты понял. Это же такой стандарт/парадигма/логика, как хочешь её назови. И это правильно. Прерывания только прерывают тебя от основного процесса/процессов. Не надолго. И тогда все будут довольны. Но сам ты, можешь поступать как хочешь. Можешь просто забить на остальных и болтать с прервавшым тебя.) Я встречал такие реализации. И они работали.) Только там было всего 2 задачи.))

Меня смущает, что ТС так и не написал, что именно он запускает в прерывании.
Наверное это неспроста.
Он сам нифига не понимает, что ему надо.

В такой ситуации довольно трудно ему помочь.

2 лайка

Я же статью привел и цитату из нее

Понимаете в чем дело. У меня в setup() прописано деление частоты на 1 (Cs10). В главном цикле у меня крутится сервопривод, а вобработчике прерываний печатаетя в порт. Так работает только сервопривод, а печатаеися в порт только один раз, если же я поменяю их местами то работает только отправка в порт. Что я забыл учесть, вроде она должна работать, а вроде на половину. P. S. Я знаю чтот такое синхронное прерывания с помощью millis() в главном цикле и оно работает. Но мне надо разделить программу на цикл и обработчик прерываний.

Зачем?
Может быть опишите первоначальную задачу?

У вас программа простаивает по 100мс(delay(100)).
Вместо задержки на delay() используйте millis().
Пример
За 100мс можно много чего напечатать.
И прерывание не нужно.