Используем Энкодер

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

andriano пишет:

Кстати, насчет конденсаторов: схему естественно, подключать только к тем ногам МК, у которых есть триггера Шмитта.

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

*нафиг всю обвязку, кроме подтяжки пинов к питанию.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Поддержу мысль andriano фактами. Схема из #248 наиболее  правильная из простых решений. Почему, смотрим:

Осциллограмма сигнала энкодера без конденсаторов:

Синий канал без всего, жёлтый с конденсатором 100nF, но без последовательного резистора

Синий канал без всего, жёлтый с конденсатором 100nF и с последовательным резистором 2кОм

Казалось бы разница между двумя последними вариантами несущественна, но в реальности она принципиальна. Приблизим переходный процесс. С конденсатором, но без последовательного резистора имеем разряд конденсатора отрицательной полярности размахом 1 вольт! такие вещи очень недружат с прерываниями:

И вот вариант с конденсатором и с последовательным резистором:

Конечно импульс сильно растянулся - там клетка 2µS, а тут 500µS. Но зато никаких выбросов, а значит и никаких помех.

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Спасибо, что не оставили без внимания мой месседж. У меня, наиболее вероятно, первый вариант энкодера, без осциллографа я точно не могу судить, но выглядит он так:

 

У продавца о распиновке ничего не было, предположил что выводы в последовательности ACB, средний земляной. Пробовал в двух средах, FLOWCOD и ARDUINO IDE - толком ни в одной не работает. Я даже пробовал в код #212 вставлять после проверок короткий блинк встроенным в ардуинку светодиодом - блинькает каждый щелчек, прерывание реально работает ВСЕГДА. Значиит пропуск шагов  говорит о том, что ни одна из проверок не выполняется. Значит в реале существует и третья (а может и четвертая...) ситуация с входными битами порта A.

Ну а что касается предложенной схемы подключения энкодера, то не могу понять зачем токоограничивающие резисторы разряда конденсатора? Организм до отвращения сопротивляется такой схеме. Автор может обосновать их наличие? Кстати, попробовал без блокировочных конденсаторов - работоспособность почти 0%.

 

 

Monday
Offline
Зарегистрирован: 01.07.2017

такого типа энкодер работает: http://arduino.ru/forum/programmirovanie/enkoder-schitaet-cherez-4

Qanatoz пишет:
У продавца о распиновке ничего не было, предположил что выводы в последовательности ACB, средний земляной. Пробовал в двух средах, FLOWCOD и ARDUINO IDE - толком ни в одной не работает
Для проверки выводов достаточно омметра или батарейки со светодиодом

Qanatoz пишет:
Ну а что касается предложенной схемы подключения энкодера, то не могу понять зачем токоограничивающие резисторы разряда конденсатора? Организм до отвращения сопротивляется такой схеме. Автор может обосновать их наличие? Кстати, попробовал без блокировочных конденсаторов - работоспособность почти 0%.

это   RC фильтр низкой частоты

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Qanatoz пишет:

Ну а что касается предложенной схемы подключения энкодера, то не могу понять зачем токоограничивающие резисторы разряда конденсатора? Организм до отвращения сопротивляется такой схеме.

Офигеть! Я целый пост посвятил рассказу зачем там дополнительный  резистор, и вам всё ещё непонятно?

Qanatoz
Offline
Зарегистрирован: 24.05.2017

dimax пишет:

Qanatoz пишет:

Ну а что касается предложенной схемы подключения энкодера, то не могу понять зачем токоограничивающие резисторы разряда конденсатора? Организм до отвращения сопротивляется такой схеме.

Офигеть! Я целый пост посвятил рассказу зачем там дополнительный  резистор, и вам всё ещё непонятно?

Не надо так пафосно. Да - "фильтр низкой частоты", да - сглаживает обратный импульс тока. Ну и что? КАК напряжение ОБРАТНОЙ полярности НИЗКОГО уровня может повлиять на ЛОГИЧЕСКИЙ вход? Как "...такие вещи очень недружат с прерываниями..."? Может быть ЛОГИЧЕСКИЙ вход воспримет такой импульс как "-1"?

Теория подтверждается практикой! Две минуты работы (поиск резисторов на ДВА КИЛООМА и подпайка) и... , что и требовалось доказать - пропуски стали чаще и чаще стал появляться реверс. 

Вы, в запале спора об подключении энкодера, совершенно забыли (тактично обошли проблему) о вашей РЕАЛЬНО НЕРАБОЧЕЙ программе. Программа из 72 поста РЕАЛЬНО РАБОТАЕТ, и я уверен, что она будет работать даже если я уберу блокировочные кондеры, а ваша нет. Я не могу проверить, что она будет работаь и с другим типом энкодера, но уверен, что будет работать. "Может, что-то в конскерватории подправить?" (с)

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Qanatoz, да ничего не подтверждается. Обработчик "в loop" работает совершенно на других принципах и таймингах.  У обработчика  на прерываниях нет таких возможностей, если он расчитан на определённый тип энкодера -то с другим он работать не обязан, и это неизбежность.

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Дмитрий, вы же реальный человек, а не тролль. До этого все ваши посты я воспринимал, как истину - сплошная конкретика и никакой воды. Ну почему сейчас вы хватаетесь за отдельные "проблемки" и совершенно игнорите ГЛАВНУЮ ПРОБЛЕМУ? Вы не ответили ни  на один мой вопрос, ведь реально же НЕ РАБОТАЕТ обработчик. Если бы энкодер был НЕРАБОЧИЙ или НЕ ТОТ, то программа не работала бы никогда, но ИНОГДА РАБОТАЕТ же! Значит программа содержит ЛОГИЧЕСКУЮ ошибку. Но вы даже не пытаетесь ее найти. У вас есть несколько типов энкодеров и вы РЕАЛЬНО пробовали вашу программу и энкодеры работали на 100%? Ну, не верю...

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Qanatoz, я ответил на ваш вопрос ещё постом #247  Посмотрите осциллограммы ещё раз - сложно написать универсальный обработчик на прерываниях по причинам которые там указаны.  То, что частично работает  -ни о чём не говорит. Я писал свой обработчик  под тот энкодер  что у меня был (ky-40), и с ним нет никаких глюков.  Много других людей его использовали,  и у всех работает нормально.  Тем не менее даже если бы вы взяли такой же модуль энкодера(ky-40) то не факт, что всё бы работало хорошо -сегодня китайцы припаивают одну модель -завтра станут другую, и все тайминги поменяются.

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Без комментария. Буду биться со СВОЕЙ проблемой САМ. Возьму у друга ригол и найду причину неработы энкодера.

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Monday пишет:

такого типа энкодер работает: http://arduino.ru/forum/programmirovanie/enkoder-schitaet-cherez-4

Такой, да не совсем такой. Скетч с подключенной библиотекой работает, но с горем пополам. Считает по 4 за каждый щелчек, то есть все значения позиции энкодера должны быть кратны 4, но как тогда быть с позициями, например, 470 или 37?

Monday пишет:

 Для проверки выводов достаточно омметра или батарейки со светодиодом

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

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

Qanatoz пишет:

Считает по 4 за каждый щелчек, то есть все значения позиции энкодера должны быть кратны 4, но как тогда быть с позициями, например, 470 или 37?

А-фи-геть!

Qanatoz
Offline
Зарегистрирован: 24.05.2017

andriano пишет:

А-фи-геть!

Не стОит, живите в здравом уме. Да, библиотечная реализация  работает лучше на порядок (реализация в 72 посте вне конкуренции), чем местные самописки, но тоже не без греха. Как эту библиотеку использовать в серьезных программах, где без прерываний не обойтись?

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Monday пишет:

Для проверки выводов достаточно омметра или батарейки со светодиодом

Для "проверки выводов", я писал о цоколевке, вы скептично ответили - значит точно имели ввиду ЦОКОЛЕВКУ, вам достаточно омметра со светодиодом? Еще раз, методу цоколевки в студию! С нетерпением жду!

Logik
Offline
Зарегистрирован: 05.08.2014

dimax пишет:

Конечно импульс сильно растянулся - там клетка 2µS, а тут 500µS. Но зато никаких выбросов, а значит и никаких помех.

Только не пишите что Вас не предупреждал я о том что ФНЧ приводит к пропускам при быстром вращении ))) Попался энкодер с 96 импульсами на оборот дающий импульсы до 1-2мсек и "шеф, все пропало" А ведь элементарные вещи RC с постоянной 0,1мсек выдаст установивщийся уровень через 0,3мсек (ага 3 тау), а для фиксации импульса с определением направления вращения надо 4 фазы сигналов, а это по 0,25-0,5мсек. П ричем фазы не сильно равные по длительности, на осцилограмах хороше видно, что 01 и 01 сильно короче чем 00 и 11. Вот и пропускает.

 

 

dimax пишет:

У обработчика  на прерываниях нет таких возможностей

Это ж каких, "таких" возможностей нету. Угадаю - делай не работает ;) А запустить формирование требуемого интервала (если нет тямы как без них обойтись) на таймере и отработать завершение времени в обработчике прерываний таймера - не?

dimax пишет:

и он расчитан на определённый тип энкодера -то с другим он работать не обязан, и это неизбежность.

Это называется "уменя все работает, а проблемы индейцев шерифа не волнуют". А нафиг код такой постить?

 

dimax пишет:

 Тем не менее даже если бы вы взяли такой же модуль энкодера(ky-40) то не факт, что всё бы работало хорошо

Фу какой дешовый слив )))

ПС. Обычная история костылестроения, когда вместо понимания происходяших процессов начинают приводить реальный сигнал к идеальному. Посмотрите на свои же осцилограмы, та же очевидно видно, где сигнал шумный, а где - нет даже без ФНЧ.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Logik, ничего не понял из ваших комментариев. Кто пропускает, что пропускает? У меня ничего не пропускает. Свой обрабочик я применяю во всех своих программах именно потому, что не нужно "запускать формирование временного интервала"  тем или иным способом.   Про проблемы индейцев -да, если у кого-то не работает, то это не моя проблема -это точно. Предложите свой вариант, который у всех будет работать и всех устроит, я только за.

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

Qanatoz пишет:

andriano пишет:

А-фи-геть!

Не стОит, живите в здравом уме.

Согласен, разумное предложение.

Но моя реплика относилась к тому, что сформулированой Вами "проблемы" не существует. От слова совсем. Во-первых, энкодер легко фиксируется и между "щелчками", так что получить любое из указанных Вами значений можно без труда. А во-второых, если уж Вм хочется непременно получать за один щелчок изменение на 1, а не на 4, то в арифметике есть такая операция - называется "деление". В данном случае делить нужно (кто бы мог подумать!) на 4.

Цитата:

Да, библиотечная реализация  работает лучше на порядок (реализация в 72 посте вне конкуренции), чем местные самописки, но тоже не без греха. Как эту библиотеку использовать в серьезных программах, где без прерываний не обойтись?

Увы, в 72 посте данной темы никакой реализации не увидел (смотрел чисто из любопытства). По поводу библиотеки тоже ничего сказать не могу - для таких элементарных вещей, как работа с энкодерами, всегда использую "самописку". Естественно, в каждом конкретном случае решаю, что именно лучше всего использовать в данном случае. Использовал и обычные прерывания на Due, которые там на каждой ноге, и PCINT на 328, которые тоже на каждой ноге, и вообще без прерываний - опрос в цикле loop(). Согласен с dimax, что единого универсального решения здесь не существует, но всегда можно выбрать то, которое окажется наилучшим в каждом конкретном случае.

Qanatoz
Offline
Зарегистрирован: 24.05.2017

andriano пишет:

...сформулированой Вами "проблемы" не существует. От слова совсем. ... А во-второых, если уж Вм хочется непременно получать за один щелчок изменение на 1, а не на 4, то в арифметике есть такая операция - называется "деление". В данном случае делить нужно (кто бы мог подумать!) на 4.

Подкол на счет деления засчитан. Но я просто имел ввиду несовершенство библиотечной реализации, в которой возможны некратные 4 значения позиции энкодера. И остановка энкодера между фиксациями этого не объясняет. Ну сами представьте механизм такой ошибки. Энкодер остановился между щелчками, библиотека  выдала некратное значение, например 7. Дальше, энкодер всегда останавливается без ошибки - строго фиксируясь. Теперь все последующие значения не будут кратны четырем - 11,...25,... и т.д. Но такого не случается - библиотека ликвидирует такую ошибку. Так, что "остановкой между" этого не объяснить.

andriano пишет:

Увы, в 72 посте данной темы никакой реализации не увидел (смотрел чисто из любопытства).

Писал по памяти, ошибся пост #74 - реализация лучше библиотечной.

Сегодня на глаза попалась статья, ну вылитый мой энкодер. Я решил, что распиновка моего энкодера ACB, а человек доказывает, что ABC. Я настолько уверовал в своей ошибке, что перерисовал и перетравил плату, вновь запаял все детали, предварительно сдув их с предыдущей. Ну и что в результате? Стало еще хуже - энкодер практически не работает. Реализации в посте #212 и #213 не работают - это для ИДЕАЛЬНОГО энкодера. Во всяком случае, я ПРАКТИЧЕСКИ доказал, что такая реализация на моем энкодере при любом подключении не работает.

PS Я все еще жду нашего "гения" Monday, котрый с помощью батарейки и светодиода сможет определить цоколевку энкодера. Ау, где ты? Что, так трудно признать, что ступил? Посыпь голову пеплом и не вякай в следующий раз неподумав.

 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

не тема, а какой-то АдЪ - кто-то может объяснить, что за херня тут происходит? ¯\_(ツ)_/¯

*одни конденсаторы вешают на энкодеры с прерываниями, другие не могут победить /4, постоянно какая-то библиотека пострадавшим упоминается и кто-то его с распиновкой надул.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Qanatoz пишет:

 Реализации в посте #212 и #213 не работают - это для ИДЕАЛЬНОГО энкодера. Во всяком случае, я ПРАКТИЧЕСКИ доказал, что такая реализация на моем энкодере при любом подключении не работает.

Это обработчик был написан для энкодера ky-40, который за 1 щёлчок делает только одно размыкание или замыкание контактов. Тогда я ещё не знал, что существуют и другие разновидности :) Поэтому не пояснил дня какого именно типа..

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

Qanatoz пишет:

Подкол на счет деления засчитан. Но я просто имел ввиду несовершенство библиотечной реализации, в которой возможны некратные 4 значения позиции энкодера. И остановка энкодера между фиксациями этого не объясняет. Ну сами представьте механизм такой ошибки. Энкодер остановился между щелчками, библиотека  выдала некратное значение, например 7. Дальше, энкодер всегда останавливается без ошибки - строго фиксируясь. Теперь все последующие значения не будут кратны четырем - 11,...25,... и т.д. Но такого не случается - библиотека ликвидирует такую ошибку. Так, что "остановкой между" этого не объяснить.

Отнюдь.

Если в результате остановки в промежуточном положении мы получили 7, значит, следующей остановке на щелчке будет соответстввать 8. И дальше? 12, 16, 20, 24...

Т.е. "на щелчке" - всегда кратно 4, а "между" - все остальные значения: 7, 9, 10, 11, 13, 14, 15, 17...

Чудес не бывает.

Если у Вас сначала на щелчке было кратное, а потом вдруг перестало, значит, где-то Вы пропустили отсчет. Ищите аппаратную проблему

Некратное на щелчке может быть (при правильной работе) только в том случае, если в момент включения энкодер стоял "между". Но и в этом случае проблем не вижу, т.к. при работе энкодера остаток от деления на 4 "на щелчке" всегда будет равен одному и тому же числу (правда, не 0). Так что если Вам нужен один отсчет на щелчок, - можете смело применять ту же операцию деления: отличия от вариатнта остановки на щелчке Вы не заметите.

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Клапауций 112 пишет:

не тема, а какой-то АдЪ - кто-то может объяснить, что за херня тут происходит? ¯\_(ツ)_/¯

*одни конденсаторы вешают на энкодеры с прерываниями, другие не могут победить /4, постоянно какая-то библиотека пострадавшим упоминается и кто-то его с распиновкой надул.

Мировой арбитр?

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

Qanatoz пишет:

Мировой арбитр?

скромный русофоб.

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Клапауций 112 пишет:

Qanatoz пишет:

Мировой арбитр?

скромный русофоб.

Сочуствую.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

Qanatoz пишет:

Сочуствую.

своим детям и внукам посочувствуй.

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Клапауций 112 пишет:

Qanatoz пишет:

Сочуствую.

своим детям и внукам посочувствуй.

Я сочуствую, только убогим умом. А мои дети и внуки, слава Богу, могут жить своими руками и умом. А убогоньких с НАПОЛЕОНОВСКИМИ ЗАМАШКАМИ мне жалко. Так что не переживай, бедолага, станешь ты НАПООЛЕОНОМ.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

Qanatoz пишет:

Я сочуствую, только убогим умом. 

я - всем аборигенам Суберии.

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Клапауций 112 пишет:

Qanatoz пишет:

Я сочуствую, только убогим умом. 

я - всем аборигенам Суберии.

Ты крут, ты уже почти НАПОЛЕОН. Всё, всё... все уже увидели твою крутизну, прими снотворное и слабительное и успокойся.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

Qanatoz пишет:

Ты крут, ты уже почти НАПОЛЕОН.

ты директор мокшанского дурдома?

Qanatoz
Offline
Зарегистрирован: 24.05.2017

Клапауций 112 пишет:

Qanatoz пишет:

Ты крут, ты уже почти НАПОЛЕОН.

ты директор мокшанского дурдома?

Ты помнишь меня? Я надеялся, что мы тебя подлечили, а ты опять за своё. Дебилизм неизлечим.

Igoreck
Offline
Зарегистрирован: 01.03.2017

Дети.

bds
Offline
Зарегистрирован: 04.03.2018


Logik пишет:

Можна конечно и так кнопку применить, но интересней другой вариант применения. В меню: без нажатия - навигация по пунктам меню; нажатие - вход в подменю или выбор конечной редактируемой величины; вращение при нажатой - навигация между уровнями меню от корня до последней выбираемой конечной величины или места где находились в меню в момент. После выбора конечной величины: вращение - изменение величины; нажатие(точней отпускание) - подтверждение ввода; вращение при нажатии - перебор вариантов ввод, отмены изменения и нескольких предустановок. Так на одном энкодере делается удобное управление многоуровневым меню. Но все зависит от задачи.

привет всем, я новичок в программирование ардуино. Кто не будь может помочь с примерам именно в этом вопросе/варианте?  У меня часть "...без нажатия - навигация по пунктам меню..." работает без проблем, дальше часть "...нажатие - вход в подменю..." и навигация врашением не получается. взял за основу скетч меню с кнопками.

 #include <LiquidCrystal.h> //Библиотека LCD
 LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
 char* Efecte[]={"All","All2","VU","VU2","VU3","VU4","Ripple",
                  "Ripple2","Fire","Fire Blue","Sinelon","Pattern3","Twinkle",
                  "Balls","Blur","Matrix One","Drip"};
 char* Regim[]={"Regim All","Regim VU","Regim Ripple","Regim Fire","Other Regim"};
 #define PinA 14
 #define PinB 15
 #define PinButon 5
 #define PinButon2 6
 #define bounce 30 //задержка антидребезга
 boolean f_key=0;//флаг для фиксации нажатия кнопки
 int counter = 0; 
 int p0=1;
 int p1=3;
 int p2=7;
 int p3=9;
 int p4=11;
 int aState;
 int aLastState;
 unsigned long time;
 unsigned long PSTimer = 0;//таймер для обновления экрана
 unsigned long KPTimer = 0;//таймер для опроса кнопок
 
 void setup() { 
   pinMode (PinA,INPUT);
   pinMode (PinB,INPUT);
   pinMode (PinButon,INPUT_PULLUP);
   pinMode (PinButon2,INPUT_PULLUP);
   lcd.begin(16,2);
   Serial.begin (9600);
   // Reads the initial state of the PinA
   aLastState = digitalRead(PinA);
  } 
  
 void loop()
 {
  if (millis()-KPTimer>=bounce) {//опрос кнопок раз в 10мсек
    KPTimer=millis();
    if (f_key==false) {
      key_dn();//проверка нажатия кнопки
    }
    if(f_key==true) {
      key_up();//проверка отпускания кнопки
    }
  }
   
   aState = digitalRead(PinA); // Считывает «текущее» состояние PinA
   // Если предыдущее и текущее состояние PinA отличаются друг от друга, это означает, что произошел импульс
   if (aState != aLastState) {     
     // Если состояние PinB отличается от состояния PinA, это означает, что кодер вращается по часовой стрелке
     if (digitalRead(PinB) != aState) {       
       //action(0);
       action(0);
     }
     else {
      //  action(1);
        action(1);
     }
   }
   aLastState = aState;
   
     if (millis()-PSTimer>=50) {//вывод экрана каждые 50мсек (20к/с)
    PSTimer=millis();
     
      PreentScreen(counter);
     }
    }

void key_dn(){
  if (f_key==false) {
    if (digitalRead(PinButon)== HIGH)
    {
      PreentScreen2(0);
      f_key=true;//устанавливаем флаг
      counter=0;
      }
    }
  }

void key_up() {
  if (digitalRead(PinButon)==0) {
    f_key=false;//сброс флага
  }
}

void PrintLabel(char* t, byte x, byte y)
{//char* t - лейбл, x-столбец, y-строка
  lcd.setCursor(x, y);
  lcd.print(t);
}

void PreentScreen(int s)
{//Вывод меню
   lcd.clear();//отчистка экрана
  //Описание экранов меню
  switch (s) {
  case 0://Экран выводимый по умолчанию (не пункт меню)
    PrintLabel("Regim",0,0);
    break;

  case 1://экран изменения переменной 1 
    PrintLabel("Regim",0,0);
    PrintLabel(Regim[0],0,1);
    break;

  case 2://экран изменения переменной 2
    PrintLabel("Regim",0,0);
    PrintLabel(Regim[1],0,1);
    break;

  case 3:
    PrintLabel("Regim",0,0);
    PrintLabel(Regim[2],0,1);
    break;

  case 4:
    PrintLabel("Regim",0,0);
    PrintLabel(Regim[3],0,1);
    break;

  case 5:
    PrintLabel("Regim",0,0);
    PrintLabel(Regim[4],0,1);
    break;
  }
}

 void PreentScreen2(int s)
 {//Вывод меню
   lcd.clear();//отчистка экрана
  //Описание экранов меню
  switch (s) {
  case 0:
    PrintLabel(Regim[0],0,0);
    PrintLabel(Efecte[p0],0,1);
    break;

  case 1:
    PrintLabel(Regim[1],0,0);
    PrintLabel(Efecte[p1],0,1);
    break;

  case 2:
    PrintLabel(Regim[2],0,0);
    PrintLabel(Efecte[p2],0,1);
    break;

  case 3:
    PrintLabel(Regim[3],0,0);
    PrintLabel(Efecte[p3],0,1);
    break;

  case 4:
    PrintLabel(Regim[4],0,0);
    PrintLabel(Efecte[p4],0,1);
    break;

  }
}

void action(byte x)
{
  switch (x) {
  case 0:
    counter=var(counter, 1, 5, 1, 1, 1);//увеличиваем переменную уровня меню
    break;
  case 1:
    counter=var(counter, 1, 5, 1, 0, 1);//уменьшаем переменную уровня меню
    break;
  case 2:
    if (counter==1){//если нажали UP когда экран с переменной р1
      p0= var(p0, 1, 2, 1, 1, 1);//то при нажатии кнопки + увеличиваем переменную р1 на единицу
    }
    if (counter==2){//если нажали UP когда экран с переменной р2
      p1= var(p1, 3, 6, 1, 1, 1);
    }
    if (counter==3){//если нажали UP когда экран с переменной р2
      p2= var(p2, 7, 8, 1, 1, 1);
    }
    if (counter==4){//если нажали UP когда экран с переменной р2
      p3= var(p3, 9, 10, 1, 1, 1);
    }
    if (counter==5){//если нажали UP когда экран с переменной р2
      p4= var(p4, 11, 17, 1, 1, 1);
    }
    break;
  case 3:
    if (counter==1){//если нажали DOWN когда экран с переменной р1
      p0= var(p0, 1, 2, 1, 0, 1);//то при нажатии кнопки + увеличиваем переменную р1 на единицу
    }
    if (counter==2){//если нажали DOWN когда экран с переменной р2
      p1= var(p1, 3, 6, 1, 0, 1);
    }
    if (counter==3){//если нажали DOWN когда экран с переменной р1
      p2= var(p2, 7, 8, 1, 0, 1);//то при нажатии кнопки + увеличиваем переменную р1 на единицу
    }
    if (counter==4){//если нажали DOWN когда экран с переменной р1
      p3= var(p3, 9, 10, 1, 0, 1);//то при нажатии кнопки + увеличиваем переменную р1 на единицу
    }
    if (counter==5){//если нажали DOWN когда экран с переменной р1
      p4= var(p4, 11, 17, 1, 0, 1);//то при нажатии кнопки + увеличиваем переменную р1 на единицу
    }  
    break;
  }
}

   int var(int v, int mn, int mx, int stp, boolean pm, boolean c)
{
  switch (pm) {//pm=1 увеличение pm=0 уменьшение
  case 0:
    v -= stp;//уменьшаем на шаг
    break;
  case 1:
    v += stp;//увеличиваем на шаг
    break;
  }
  switch (c) {//c-1 циклически с-0 до пределов
  case 1://
    if (v<mn) {
      v=mx;
    }
    if (v>mx) {
      v=mn;
    }
    break;
  case 0:
    if (v<mn) {
      v=mn;
    }
    if (v>mx) {
      v=mx;
    }
    break;
  }
  return v;
}

 

ziercool
Offline
Зарегистрирован: 28.04.2018

leshak пишет:

 Фух. Я опять чуствую себя полноценным девелопером. :)
Победил!!!
Четко ловится каждый "щелчек". Без ошибок направления, без пропусков (даже если "крутить" достаточно быстры).

Общий подход такой
1. На нисходящем фронте A, смотрим состояние B и запоминаем его. А так же время "когда это произошло" (падение A)
2. На восходящем фронте A, смотрим сколько времени прошло с пукнта 1. Если меньше определенного значения (5 msec опытно подобрал) - игнорируем, если больше - меняем счетчик энкодра. Направление определяем по состоянию канала B, запомненного на пункте 1.

 

#define PIN_A 2
#define PIN_B 3
#define PULSE_PIN_LEN 5 // минимальная длинна импульса в миллесекундах на которую мы обращаем внимание


volatile unsigned long failingTime=0;
volatile bool fl=false; // флаг что нужно вывести
volatile bool value_b=0;
volatile byte prevA=0;
volatile int encValue=0;
volatile unsigned long pulseLen=0;
void setup(){
  Serial.begin(57600);
  digitalWrite(PIN_A,HIGH);
  digitalWrite(PIN_B,HIGH);
  
  attachInterrupt(0,handler_a,CHANGE);
  
  Serial.println("Ready");
}

void handler_a(){
 // byte portValue=PINE ; // для меги  
//  byte A= (portValue & B10000)>0 ;// digitalRead(PIN_A); PE4
   byte A=digitalRead(PIN_A);
  
  if(!fl){ // пока не отчитались ничего больше не делаем

      if(prevA && !A){ // фронт упал
        //value_b=(portValue & B100000)>0; // digitalRead(PIN_B); PE5 // определили направление, но пока только "запомнили его"
        value_b=digitalRead(PIN_B); // определили направление, но пока только "запомнили его"
        failingTime=millis(); // и запомнили когда мы "упали в ноль", начали отсчет длины импульса
      }
      
    
      if(!prevA && A && failingTime){ // восходящий фронт и мы в режиме "отсчет времени импульса
         pulseLen=millis()-failingTime;
        if( pulseLen>PULSE_PIN_LEN){ // импульс бы достаточно длинный что-бы поверить тому что мы прочитали в его начале
          if(value_b)encValue++; else encValue--;
          fl=true; // включаем пометку что нужно отчитатся в Serial
        }
        failingTime=0; // больше не ведем осчет времени импульса
      }
 }

  prevA=A;
}

void loop(){
  if(fl){
    Serial.print("Enc=");Serial.print(encValue);  
    Serial.print(",Dir="); Serial.print(value_b?"R":"L"); // выводим направление
    Serial.print(",PulseLen=");Serial.println(pulseLen); // выводим длину импульса (удобно для первоначальной настройки)
    fl=false;
  }
}

 

Выдает (сделал 10-ть щелчков по часовой и 10-ть против):

Ready
Enc=1,Dir=R,PulseLen=45
Enc=2,Dir=R,PulseLen=71
Enc=3,Dir=R,PulseLen=58
Enc=4,Dir=R,PulseLen=83
Enc=5,Dir=R,PulseLen=70
Enc=6,Dir=R,PulseLen=30
Enc=7,Dir=R,PulseLen=72
Enc=8,Dir=R,PulseLen=46
Enc=9,Dir=R,PulseLen=97
Enc=10,Dir=R,PulseLen=78
Enc=9,Dir=L,PulseLen=44
Enc=8,Dir=L,PulseLen=28
Enc=7,Dir=L,PulseLen=40
Enc=6,Dir=L,PulseLen=27
Enc=5,Dir=L,PulseLen=14
Enc=4,Dir=L,PulseLen=33
Enc=3,Dir=L,PulseLen=20
Enc=2,Dir=L,PulseLen=27
Enc=1,Dir=L,PulseLen=47
Enc=0,Dir=L,PulseLen=20

Количество щелчков четко совпадет с тем что "чувствуется рукой". Крутил в темпе "что-бы самому успевать считать щелчки".

 

 

Можно попросить схему подключения энкодера?

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

dimax пишет:

Мой вариант обработчика энкодера. Очень простой и совершенно безглючен. Обработчик сидит в теле внешнего прерывания PCINT.   В нижеследующем скетче задействованы входы A0 и A1 как цифровые. Используется подтяжка к питанию (распаянная на платке стандартного энкодера),  и антидребезговые конденсаторы 0,1мкф на землю. Кому нужно на другие ноги - смотреть даташит страница 73 и маскировку битов сделать по аналогии.

volatile int enc;
void setup() {                
Serial.begin(9600);
PCICR=1<<PCIE1; //разрешить пренрывание
PCMSK1=(1<<PCINT9)|(1<<PCINT8); //выбрать входы
}

ISR (PCINT1_vect){
static byte old_n=PINC&3; // маска B00000011 что б читать только нужные 2 бита
byte new_n=PINC&3;
if (old_n==1&&new_n==3||old_n==2&&new_n==0) {enc++;}
if (old_n==2&&new_n==3||old_n==1&&new_n==0) {enc--;}
old_n= new_n;
}

void loop() {
Serial.println(enc); 
}

 

А можно аналогичный пример для 5 и 6 пина, у меня получилось следующее, но пока не работает, честно сказать уже не знаю что неправильно, пробовал по разному

PCICR=1<<PCIE2; //разрешить пренрывание
PCMSK2=(1<<PCINT21)|(1<<PCINT22); //выбрать входы

ISR (PCINT2_vect){
static byte old_n=PIND&B01100000; // маска B00000011 что б читать только нужные 2 бита
byte new_n=PIND&B01100000;
if (old_n==1&&new_n==3||old_n==2&&new_n==0) {enc++;}
if (old_n==2&&new_n==3||old_n==1&&new_n==0) {enc--;}
old_n= new_n;
}

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

мошт, надо old_n и new_n на 5 бит вправо сдвигать, а потом сравнивать с 3, 2 и 1? 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

А хрен знает, я уже думать нехочу. Несколько часов промучался

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

jeka_tm,

volatile int enc;
void setup() {                
Serial.begin(9600);
PCICR=1<<PCIE2; //разрешить прерывание
PCMSK2=1<<PCINT21; //выбрать вход на котором сработает прерывание
}

ISR (PCINT2_vect){((PIND&0x20)>>4)^((PIND&0x40)>>5)?enc++:enc--;}

void loop() {
Serial.print("enc= ");  Serial.println(enc);
}
jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

Спасибо заработало

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

мой велосипед для работы с энкодером - https://github.com/enjoyneering/RotaryEncoder

Мааленькая и быстрая. На основе 4-х комбинаций с помощью булевой алгебры и switch-case делается простейший счетчик. Все! Правда есть нюанс. Функция digitalRead() оказалась настолько медленной, что ATmega328 не успевал читать значения pinA и pinB при срабатывании внешнего прерывания на pin A. Поэтому для AVR пришлось использовать прерывание по Timer1. Каждые 0.01 секунд таймер не спеша читает состояние пинов и обновляет счетчик энкодера. Для быстрых STM32 и ESP8266 все работает на внешнем прерывании - как только энкодер начинает крутиться, срабатывает внешнее прерывание на pinA, считываются значения pinA и pinB и обновляется позиция энкодера.

В библиотеки два класса: легкий "RotaryEncoder" и тяжелый класс с "RotaryEncoderAdvanced" на template.
 
Легкий класс тупо счетчик кликов в диапазоне -32768..32767 и обработчик нажатия кнопки. На лету можно менять значения счетчика и сотяние кнопки. Все.
 
В Advanced классе можно прописывать количество шагов на клик, минимальное и максимальное значение. Получился законченный велосипед. Из-за template библиотека может занимать меньше памяти - все зависит от типа используемых переменных.
 
Вот так для float:
RotaryEncoderAdvanced<float> encoder(PIN_A, PIN_B, BUTTON, 0.1, 0.0, 3.3);  //0.1 step per click, minimum value 0.0, maximum value 3.3

Вот так для byte:

RotaryEncoderAdvanced<byte> encoder(PIN_A, PIN_B, BUTTON, 1, 0, 255);  //1 step per click, minimum value 0, maximum value 255
Добавил возможность на лету менять - step per click, minimum value и maximum value. Управляем множеством различных значений с помощью одного энкодера!!!
 
БЕЗ ГАСЯЩИХ КОНДЕНСАТОРОВ БИБЛИОТЕКА РАБОТАТЬ НЕ БУДЕТ, СМОТРИ ПОСТ #252!!!
 
Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015

Подскажите как поменять пины энкодера вместо А0 и А1 на 2 и 3 (у меня все порты А заняты)

в коде для энкодера с поста http://arduino.ru/forum/apparatnye-voprosy/ispolzuem-enkoder?page=2#comment-111309

volatile int enc;
void setup() {                
Serial.begin(9600);
PCICR=1<<PCIE1; //разрешить пренрывание
PCMSK1=(1<<PCINT9)|(1<<PCINT8); //выбрать входы А1 и А0
}

ISR (PCINT1_vect){
static byte old_n=PINC&3; // маска B00000011 что б читать только нужные 2 бита
byte new_n=PINC&3;
if (old_n==1&&new_n==3||old_n==2&&new_n==0) {enc++;}
if (old_n==2&&new_n==3||old_n==1&&new_n==0) {enc--;}
old_n= new_n;
}

void loop() {
Serial.println(enc); 
}

голову уже сломал

в примере из кода http://arduino.ru/forum/apparatnye-voprosy/ispolzuem-enkoder?page=5#comment-419049

volatile int enc;
void setup() {                
Serial.begin(9600);
PCICR=1<<PCIE2; //разрешить прерывание
PCMSK2=1<<PCINT21; //выбрать вход на котором сработает прерывание
}

ISR (PCINT2_vect){((PIND&0x20)>>4)^((PIND&0x40)>>5)?enc++:enc--;}

void loop() {
Serial.print("enc= ");  Serial.println(enc);
}

мой энкодер прибавляет или отнимает по 2 еденицы, а не по 1 за один щелчек 

vvadim
Offline
Зарегистрирован: 23.05.2012

Sanyaba пишет:

в примере из кода http://arduino.ru/forum/apparatnye-voprosy/ispolzuem-enkoder?page=5#comment-419049

volatile int enc;
void setup() {                
Serial.begin(9600);
PCICR=1<<PCIE2; //разрешить прерывание
PCMSK2=1<<PCINT21; //выбрать вход на котором сработает прерывание
}

ISR (PCINT2_vect){((PIND&0x20)>>4)^((PIND&0x40)>>5)?enc++:enc--;}

void loop() {
Serial.print("enc= ");  Serial.println(enc);
}

мой энкодер прибавляет или отнимает по 2 еденицы, а не по 1 за один щелчек 

 

вот костылёк))))

 

int val_enc = 0;
volatile int enc;

void setup()
{
  Serial.begin(9600);
  PCICR = 1 << PCIE2;     //разрешить прерывание
  PCMSK2 = 1 << PCINT21;  //выбрать вход на котором сработает прерывание
}

ISR (PCINT2_vect)
{
  ((PIND & 0x20) >> 4)^((PIND & 0x40) >> 5) ? enc++ : enc--;
}

void loop()
{
  val_enc = enc / 2;
  Serial.print("enc= ");
  Serial.println(val_enc);
}

 

Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015

vvadim пишет:

вот костылёк))))

ясное дело что сразу заюзал 

enc / 2

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Для энкодеров, которые за один щелчок совершают полный импульс (типа ec-11, подробно об этом в #247) есть более совершенный вариант обработчика. Алгоритм взял тут у Леонид Иваныча, и воткнул в прерывания. С этим методом дребезгоподавляющие конденсаторы не нужны. По аналогии можно переделать на другие пины

//Энкодер на пинах А0, А1. Используется внутренняя подтяжка.
volatile int enc;
void setup(){                
Serial.begin(9600);
pinMode(A0,INPUT_PULLUP);
pinMode(A1,INPUT_PULLUP);
PCIFR=PCIFR; PCICR=1<<PCIE1; //разрешить прерывание
PCMSK1=1<<PCINT8 | 1<<PCINT9; //выбрать вход на котором сработает прерывание 
}

ISR(PCINT1_vect){
static char EncPrev=0;      //предыдущее состояние энкодера
static char EncPrevPrev=0;  //пред-предыдущее состояние энкодера
  char EncCur = 0;
  if(!(PINC & (1 << PC0))){EncCur  = 1;} //опрос фазы 1 энкодера
  if(!(PINC & (1 << PC1))){ EncCur |= 2;} //опрос фазы 2 энкодера
  if(EncCur != EncPrev)             //если состояние изменилось,
  {
    if(EncPrev == 3 &&        //если предыдущее состояние 3
       EncCur != EncPrevPrev )      //и текущее и пред-предыдущее не равны,
    {
      if(EncCur == 2)          //если текущее состояние 2,
        enc++;            //шаг вверх
      else                          //иначе
        enc--;            //шаг вниз
    }
    EncPrevPrev = EncPrev;          //сохранение пред-предыдущего состояния
    EncPrev = EncCur;               //сохранение предыдущего состояния
  }


  }



void loop() {
Serial.println(enc); 
}

 

bwn
Offline
Зарегистрирован: 25.08.2014

dimax, добрый человек, в 7-й строке, что за колдунство? Не могу у Евстифеева найти, или ищу не там????(((((

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

bwn, PCIFR=PCIFR убрать флаг (что б не влетело в прерывание сходу) -это не обязательная команда. PCICR=1<<PCIE1 разрешить групповые прерывания для второй группы.

bwn
Offline
Зарегистрирован: 25.08.2014

Пасиб, я в виду имел, где про эти регистры почитать.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

bwn, даташит не предлагать? :) Ну гугль наверное что нить подскажет..

bwn
Offline
Зарегистрирован: 25.08.2014

dimax пишет:

bwn, даташит не предлагать? :) Ну гугль наверное что нить подскажет..

Ну почему не предлагать. Вполне можно. Ввиду языкового кретинизма пользуюсь Евстифеевым, а там про них ни слова. Вы сказали, в даташите есть. Полезу буквицы, бусурманские, разбирать. Спасибо.))))

son32
Offline
Зарегистрирован: 04.12.2017

Всем доброго времени суток!!! Прошу помощи допилить скетч) в общем суть такая, собираю внешнее управление для авто магнитолы, управление работает по can шине. из устройств имеется ардуино нано+can шилд mcp2515+джойстик ky-023, под эту связку я нормально скетч сделал. но мне нужно добавить энкодер KY-040 для управления громкостью. то есть при вращении энкодера в одну сторону должен в шину поступать один пакет can, в другую сторону другой пакет. Пробовал примеры работы с энкодером, но как что то изменяю в примере у меня ни чего не работает.

вот мой скетч для управления магнитолой, точнее это часть скетча:

#include <SPI.h>
#include <mcp2515.h>

int sensorPin = A0;
int sensorPin2 = A1;
const int butPin = 4;
unsigned long timing1;
unsigned long timing2;

struct can_frame canMsg1;  //frame
struct can_frame canMsg2;  //OK
struct can_frame canMsg3;  //Up
struct can_frame canMsg4;  //Dw
struct can_frame canMsg5;  //L
struct can_frame canMsg6;  //R
struct can_frame canMsg7;  //Sound -
struct can_frame canMsg8;  //Sound +
struct can_frame canMsg9;  //BeaK
struct can_frame canMsg10;  //Lo
struct can_frame canMsg11; //Ro
MCP2515 mcp2515(10);

void setup() {
  canMsg1.can_id  = 0x1F3;
  canMsg1.can_dlc = 8;
  canMsg1.data[0] = 0x00;
  canMsg1.data[1] = 0x00;
  canMsg1.data[2] = 0x00;
  canMsg1.data[3] = 0x86;
  canMsg1.data[4] = 0x00;
  canMsg1.data[5] = 0x00;
  canMsg1.data[6] = 0x77;
  canMsg1.data[7] = 0x00;

  canMsg2.can_id  = 0x1F3;
  canMsg2.can_dlc = 8;
  canMsg2.data[0] = 0x00;
  canMsg2.data[1] = 0x00;
  canMsg2.data[2] = 0x01;
  canMsg2.data[3] = 0x86;
  canMsg2.data[4] = 0x00;
  canMsg2.data[5] = 0x00;
  canMsg2.data[6] = 0x77;
  canMsg2.data[7] = 0x00;
 
  canMsg3.can_id  = 0x1F3;
  canMsg3.can_dlc = 8;
  canMsg3.data[0] = 0x00;
  canMsg3.data[1] = 0x00;
  canMsg3.data[2] = 0x02;
  canMsg3.data[3] = 0x86;
  canMsg3.data[4] = 0x00;
  canMsg3.data[5] = 0x00;
  canMsg3.data[6] = 0x77;
  canMsg3.data[7] = 0x00;

    pinMode(butPin,INPUT_PULLUP);
  mcp2515.reset();
  mcp2515.setBitrate(CAN_250KBPS);
  mcp2515.setNormalMode();
  Serial.begin(9600);
}

void loop() {
  if (millis() - timing1 > 100){
  timing1 = millis(); 
  mcp2515.sendMessage(&canMsg1);
  }
  if (digitalRead(butPin) == LOW) {
     if (millis() - timing2 > 500){
     timing2 = millis();
     mcp2515.sendMessage(&canMsg2);
     }
  }
   int sensorValue = analogRead(sensorPin);
   if (sensorValue > 900 && sensorValue < 1020) {
      if (millis() - timing2 > 500){
      timing2 = millis();
      mcp2515.sendMessage(&canMsg5);
      }
  }
   int sensorValue2 = analogRead(sensorPin);
   if (sensorValue2 > 1 && sensorValue2 < 100) {
      if (millis() - timing2 > 500){
      timing2 = millis();
      mcp2515.sendMessage(&canMsg6);
      }
  }

мне нужно что бы при повороте энкодера выполнялась вот это часть программы:

      if (millis() - timing2 > 500){
      timing2 = millis();
      mcp2515.sendMessage(&canMsg7);

ну и соответственно при повороте в другую такая же только с другим пакетом can:

      if (millis() - timing2 > 500){
      timing2 = millis();
      mcp2515.sendMessage(&canMsg8);

свои наработки по энкодеру не выкладываю, так как дальше примеров не ушел. а в программирование не селен))

если кому не трудно помогите!!!)))

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

son32 пишет:

Всем доброго времени суток!!! Прошу помощи достроить баню!!!

.

.

.

 

свои наработки и фотки по бане не выкладываю, так как дальше фундамента не ушел. а в строительствах не селен))

если кому не трудно помогите!!!)))

Примерно так и я могу написать