Прерывания и энкодер
- Войдите на сайт для отправки комментариев
Приветствую всех!
Возник вопрос по работе с энкодером. В проекте Нужно отслеживать энкодер, ну что это по простому? По простому - изменять значения глобальных переменных (причем если режим №1 - одну переменную меняем, если №2 - вторую и так далее).
Использую:
ISR(PCINT2_vect) { unsigned char result = r.process(); if (result == DIR_CW && metod == 1) { // делаем 1 } if (result == DIR_CW && metod == 2) { // делаем 2 } if (result == DIR_CW && metod == 3) { // делаем 3 } }
Не нужно говорить, что "проще использовать свич а не "если", так практичнее" и подобное, вопрос не в этом.
Собственно вопрос: Я не понимаю (или просто туплю может) - В этой функции меняются значения переменных типа long, эти переменные глобальные. Из других прерываний использую millis (они же используют прерывания, на сколько я знаю?). И вот начитавшись всякого, не понимаю: нужно ли во время изменения значений этих самым глобальных переменных отключать прерывания? И если нужно - как это повлияет на millis в loop()? И нужно ли их помечать как volatile?
millis используется в loop() для отсчета времени.
есть же библиотека для работы с энкодером-rotate.Она и использует прерывания Int0, Int1
На время работы с любой многобайтовой переменной, изменяющейся а прерывании, необходимо прерывания запрещать.
На millis() влияет даже чтение millis().
Помечать, как volatile надо, чтобы компилятор не заоптимизировал их из лучших побуждений.
Сэдман, поясни ещё как правильно прерывания отключить на это время? Ну то есть как я понимаю все не нужно, ведь от энкодера внешнее прерывание, нужно только внешнее и отключить, как это делается (или где почитать)?
есть же библиотека для работы с энкодером-rotate.Она и использует прерывания Int0, Int1
Хотелось бы увидеть как сама библиотека использует прерывания (в соседней ветке обсуждение подобное идёт), не подскажите?
Насчёт избирательного отключения никто особо не заморачивается в Ардуине. С detach/attachInterrupt выигрыша не будет, а прямая манипуляция регистрами вне концепции. См. Макрос ATOMIC_BLOCK (поиском по форуму).
Внутри прерывания другие прерывания автоматически запрещаются до выхода из этого прерывания. Поэтому в прерывании сильно не рекомендуется делать что-либо длительное или полагаться на другие прервания, типа ждать изменеия millis.
Мне больше понять - если все прерывания отключать/включать на время присвоения значения на millis не повлияет (ну то есть отсчёт 2-3 секунды в loop() нормально, не сбросится?]? Прости за глупый, скорее всего, вопрос. Не догоняю, иначе бы не спрашивал.
На millis() влияет даже чтение millis().
Это с какого еще бодуна?
Не с бодуна, а с содержимого функции. Влияет ровно так же, как и ATOMIC_BLOCK - ненадолго запрещает все прерывания.
Не с бодуна, а с содержимого функции. Влияет ровно так же, как и ATOMIC_BLOCK - ненадолго запрещает все прерывания.
Ну запрещает. но ведь не влияет же.
а нафик тебе прерывания для тупого энкодера? Можно прекрасно обойтись и без них
а нафик тебе прерывания для тупого энкодера? Можно прекрасно обойтись и без них
"прежде чем продать что-то ненужное, надо купить что-то ненужное" )))
Не с бодуна, а с содержимого функции. Влияет ровно так же, как и ATOMIC_BLOCK - ненадолго запрещает все прерывания.
Так каким же образом запрещение ненадолго прерывания влияет на миллис?
Темы для размышления:
- Останавливается ли таймер если запрещеные прерывания?
- Как часто происходит прерывания от таймера используемого millis()?
- Cколько времени занимет выполнение кода
-Что случится если таймер таки сработает когда прерывания были запрещены?
Ёлки-иголки, я хотел разобраться в "теме вопроса", а в итоге только запутали меня. ((
Собственно постараюсь переформулировать вопрос:
Есть энкодер и кнопка (переключающая режимы (mode в коде)). "Одинаковость" - в функции прерывания изменяются переменные типа long при вращении энкодера. Различие - в зависимости от измененных переменных в основном цикле (функции loop() ) ведется отсчет с использованием millis для появления "порога", в зависимости от "порога" происходят действия. Это, по сути, тестовый проект для "потренироваться" перед использованием в других проектах.
Начитавшись литературы, что 8 битные контроллеры (atmega168 в данном случае) могут ошибочно заносить данные при изменении переменных во время прерываний, начал читать и путаться. Поэтому и вопрос задал тут.
Предварительные мои выводы: нужно нафик отрубать прерывания во время изменения переменных. Но вот как до сего времени не понятно - millis не "собъется"? Корректно время отсчитает? +/- 100 миллисекунд не считается.
Поскольку счётчик для millis изменяется программно в обработчике таймера, то очевидно, что любое препятствование вызову обработчика тем или иным образом повлияет на ритмичность или результат счета.
Вопроса же о том насколько это критично и какова будет девиация относительно "беспрепятственного хода" - не стояло.
Boom, если на плате Ардуино не припаян высокоточный задающий генератор уровня Stratum 0, то от запрета прерываний на время чтения/записи многобайтовой переменной земля на небесную ось не налетит. Если хочется минимизировать вообще шанс потери тактов МК, то стоит завести однобайтовый флаг и по его готовности читать/писать атомарно.
Чтение millis() на результаты его работу не влияет. В редком случае можно получить предыдущее его значение, хотя уже должно было бы быть следующее. Но уже при следующем чтении данные будут правильные.
Читать millis() внутри прерывания можно, но бесполезно ждать его обновления. Он не обновится пока прерывания не будут разрешены.
Надо ли запрещать прерывания во время измения глобальных переменных зависит от структуры конкретной программы. Когда надо, а когда и не надо.
Расскажите про структуру программы, в которой можно забить на атомарное чтение переменной, изменяемой в прерывании.
Расскажите про структуру программы, в которой можно забить на атомарное чтение переменной, изменяемой в прерывании.
Расскажите сначала как чтение миллис влияет на результат его счета.
Если больше дополнений не будет, то могу считать тему закрытой. Под мои «хотелки» ответ я услышал, а большее если только потом (опять же - если доживу до них). Спасибо огромное всем участвующим в обсуждении!
Расскажите про структуру программы, в которой можно забить на атомарное чтение переменной, изменяемой в прерывании.
А там функция, есть такая - "сколько будет дважды два - сорок...семь восемь где-то так, ну не сорок же"