ARDUINO Энкодер в прерывании

NikolasGood

✩✩✩✩✩✩✩
10 Сен 2020
2
0
Всем привет. Делаю пример "работа энкодера с прерыванием" из библиотеки по работе с энкодером, но он не работает. Сам пример работает, пока не добавишь в loop функцию delay(1000), чтобы проверить само прерывание. Для примера я просто увеличиваю и уменьшаю переменную count при прокрутки энкодера. Но он срабатывает 1 раз из 100. В общем сам пример из библиотеки написан не корректно, в нем нет хотя бы delay(1000)
Подскажите пожалуйста какой-нибудь пример с прерыванием, чтобы он работал когда в loop delay(1000). А в реале у меня отрисовка дисплея тормозит проверку энкодера, по этому и начал изучать прерывание.
 

b707_2

★★✩✩✩✩✩
22 Июл 2020
182
51
какая библиотека, какой пример - укажите четко. А самое лучшее - просто выложите свой код, которым вы проверяете.
 

NikolasGood

✩✩✩✩✩✩✩
10 Сен 2020
2
0
какая библиотека, какой пример - укажите четко. А самое лучшее - просто выложите свой код, которым вы проверяете.
Код примерно такой (пишу без компилятор, т.к. на работе сейчас)
C++:
/*

   Пример работы с энкодером с прерыванием. Максимальная чёткость работы
   в любом быдлокоде!
*/

#define CLK 2
#define DT 3
#define SW 4

#include "GyverEncoder.h"
Encoder enc1(CLK, DT, SW);
volatile int count;
void setup() {
  Serial.begin(9600);
  attachInterrupt(0, isr, CHANGE);    // прерывание на 2 пине! CLK у энка
  attachInterrupt(1, isr, CHANGE);    // прерывание на 3 пине!
}

void isr() {
  enc1.tick();  // отработка в прерывании

if (enc1.isRight()) count++;
if (enc1.isLeft()) count--;
}

void loop() {
   Serial.println(count);
   delay(1000);
}
 

kostyamat

★★★★★★✩
29 Окт 2019
1,098
632
@NikolasGood, а теперь сами подумайте. Когда вы крутите энкодер, у вас два раза, причем практически паралельно вызываеться функция isr(). Потому, что а) поставили ее аж на две ноги энкодера, а они меняются практически одновременно если крутить, б) потому что "по любому чиху" с опцией CHANGE. Не удивительно, что контроллеру "крышу сносит". Вы же не следуете принципу атомарного исполнения кода в isr.
Вообще-то, в обработчиках прерываний не принято вызывать другие функции, и считать что-то тяжелое. Еще val++, val--
или флаг установить, потом в основном коде его обработать - куда не шло, но всякие тики, обработчики энкода с задержками - такое себе.
Оставьте прерывание только на одной ноге.
 
Изменено:

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
573
@kostyamat, и тем не менее, оно работает, иначе пример бы не появился. Прямых задержек в обработчике нет..
 

poty

★★★★★★✩
19 Фев 2020
3,233
940
-
@kostyamat, и тем не менее, оно работает, иначе пример бы не появился. Прямых задержек в обработчике нет..
Интересно, ни в одном из Ваших примеров нет назначения одного прерывания на два выхода энкодера и обработки в прерывании срабатывания одного из событий. А @NicolasGood именно такой код и привёл. Так что не факт, что работает, не факт!
Теперь - по сути.
Не раскрыто много подробностей:
  • что за энкодер? Возможно, нет антидребезга, проц захлёбывается в прерываниях, либо тип энкодера выставлен неверно, либо в принципе неисправный энкодер;
  • каким образом отслеживается изменение count?
  • что за Ардуино? На какой частоте работает? Возможно, просто не хватает времени на обработку всех процедур дешифровки.
Теперь кое-какие замечания:
  • использование прерывания спасает только от потери "тика" энкодера, что толку, что Вы определили этот тик, если обработка, по Вашему замечанию, этой сработки, будет задержана в основном коде другим процессом?
  • использование с некоторыми интерфейсами экранов может не сработать из-за конфликта передачи многих данных по интерфейсу (с остановленными прерываниями) и ожиданием, что сработает это самое аппаратное прерывание;
  • на сайте имеется пример с аппаратным таймером, считаю для данного случая лучшим вариантом.
 
Изменено:

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
573
@poty, именно, прерывание спасает от потерянного тика. Такие функции, как удержания, клики по кнопке, нажатые повороты - требуют повторного вызова, так как там сидит тайм-аут. Вешать на прерывания таймера - заставить мк постоянно в принудительном порядке тратить процессорное время на опрос пинов. Поэтому аппаратное внешнее + опрос в основном цикле (если цикл не блокируется на большое время) - лучший вариант опроса энкодера со всеми временными фишками
 

poty

★★★★★★✩
19 Фев 2020
3,233
940
@AlexGyver, я отвечал по конкретному случаю, описанному в первом сообщении и по приведенному примеру. В частности, речь о том, что имеется блокирующий цикл отрисовки дисплея, который (далее начинаются предположения, поскольку информация так и не была представлена), как обычно работают программно эмулированные стандартные интерфейсы, запрещает прерывания на период передачи данных. Т.е., при использовании прерывания по изменению статуса порта, есть большая вероятность, что, в момент изменения статуса порта, прерывания заблокированы. Конечно, последнее прерывание будет кэшироваться, но понятно, что последовательности переключения, которая нужна для определения поворота, не будет. Поворот будет пропущен. Возможно, не один тик, а много, всё зависит от времени запрета прерываний. То, что автор всё собрал на одном прерывании существенно усугубляет ситуацию. Прерывание по таймеру от потери не спасает также, но, как минимум, упрощает жизнь тем, что оно вызывается 1 раз, а не 4.
Каждый тик энкодера, в идеале, продуцирует 4 последовательных события. Если энкодер не имеет подавителя дребезга или просто плохого качества, каждое из 4-х событий может вызывать до 3-6 импульсов дребезга с весьма непредсказуемой частотой, количество прерываний резко возрастает, часть из них теряется по причине того, что не закончилась обработка предыдущего прерывания (в обработчике прерываний они запрещены), что там надетектирует в этом случае код малопонятно. Часть этих проблем (но не все!) снимает прерывание по таймеру: его работа не зависит от дребезга, а вызов осуществляется с заданной и достаточно большой периодичностью, позволяющей сделать минимальную обработку в самом прерывании. Это, кстати, вторая ошибка: обработка действия внутри прерывания.
Почему это ошибка? Просто потому, что реальная обработка для получения результата занимает гораздо большее время, и будет всё равно выполняться в заблокированном loop. Впрочем, для простейшего кода типа "обнаружить кручение" это может и прокатить (реализовать с помощью counters), а вот если требуется ещё отслеживать кнопку, то - увы. Например, три щелчка в одну сторону, нажатие, три щелчка в другую сторону, нажатие, если не будет интерпретировано сразу же, может означать что угодно, например, два последовательных нажатия без поворота.
Короче, здесь много косяков. Не для всякого "быдлокода" работает Ваша библиотека.
 
  • Лойс +1
Реакции: bort707 и kostyamat