LCD+Encoder - глюк?
- Войдите на сайт для отправки комментариев
Здравствуйте. Подскажите пожалуйста почему данный ниже код работает с глюком.
Глюк заключается в том, что если выводить на LCD дисплей так: lcd.print("Param: "); lcd.print(myparam); то в этих строках:
if (encoder.isRight() && myparam < 35) myparam++;
if (encoder.isLeft() && myparam > 10) myparam--;
myparam меняется, но не так как нужно. Я пробовал в сериал выводить myparam сразу после этих строк для сравнения с отображением на LCD но и там и там одинаково и неправильно. Если так: lcd.print(myparam); (без предварительного lcd.print("Param: ");) то все нормально.
Неправильно - это меняется ели ели, как-то медленно, т.е. несколько щелчков энкодера что бы сменилось на единицу. И еще при повороте ручки в одну сторону значение myparam может(или нет) меняться и в ту и в другую сторону).
Там в коде последние четыре строки, если оставлять одну любую для проверки то две работают нормально а две нет.
Из-за чего такой неприятный глюк? Может это связано с конкретным моим железом или библиотеками. Название библиотек и их версии я в коде указал.
#include <LiquidCrystal_I2C.h> //name=LiquidCrystal_I2C //version=1.1.4 //author=Frank de Brabander //maintainer=Marco Schwartz <marcolivier.schwartz@gmail.com> //sentence=A library for I2C LCD displays. //paragraph= The library allows to control I2C displays with functions extremely similar to LiquidCrystal library. THIS LIBRARY MIGHT NOT BE COMPATIBLE WITH EXISTING SKETCHES. //category=Display //url=https://github.com/marcoschwartz/LiquidCrystal_I2C //architectures=avr #include <GyverEncoder.h> //name=GyverEncoder //version=4.8 //author=AlexGyver <beragumbo@ya.ru> //maintainer=AlexGyver <beragumbo@ya.ru> //sentence=Advanced library for encoder. //paragraph=Allows to get maximum uses of encoder: turns, holded turns, fast turns and more. //category=Sensors //url=https://github.com/AlexGyver/GyverLibs //architectures=* #define CLK 4 #define DT 5 #define SW 3 Encoder encoder(CLK, DT, SW); LiquidCrystal_I2C lcd(0x27, 20, 4); void setup() { encoder.setType(TYPE2); lcd.init(); lcd.backlight(); } byte myparam = 10; #define FLASH_MS 400 uint32_t ms = 0; bool f = true; void loop() { encoder.tick(); if (encoder.isRight() && myparam < 35) myparam++; if (encoder.isLeft() && myparam > 10) myparam--; if (millis() - ms >= FLASH_MS) { f = !f; ms += FLASH_MS; } lcd.setCursor(0, 0); // lcd.print(myparam); // Работает if (!f) lcd.print(" "); else lcd.print(myparam); // Работает // lcd.print("Param: "); lcd.print(myparam); // НЕ работает // lcd.print("Param: "); if (!f) lcd.print(" "); else lcd.print(myparam); // НЕ работает }
Или я чего-то не знаю про связку lcd.print и encoder :(
а чо de Brabander с Гайвером говорят?
Первая Ваша ошибка - использование библиотек от Гайвера. Гайвер - талантливый блогер, но никудышний программист.
Если я правильно понял Вашу проблему, при подключении вывода на дисплей энкодер начинает чудить, а без дисплея работает нормально. Причина, скорее всего, в том, что вывод на дисплей занимает довольно большое время, за которое мы не можем отслеживать состояние энкодера - откуда и ошибки.
Правильно подключать энкодер - через прерывания. Ну либо заботиться, чтобы между вызовами encoder.tick() не было длительных задержек.
Попробуйте работу с LCD временно выкинуть из loop() вообще.
Если я правильно понял Вашу проблему, при подключении вывода на дисплей энкодер начинает чудить, а без дисплея работает нормально.
Не совсем так. Глючить начинает когда перед выводом параметра на дисплей (lcd.print(myparam);) я вывожу строку (lcd.print("Param: ");)
Если выводить просто:
Попробуйте работу с LCD временно выкинуть из loop() вообще.
Код выше - это максимально упрощенный и сохранивший этот глюк.
Вообще изначально код был больше и опрос энкодера и вывод на экран были в разных функциях и не в loop обе.
Я долго искал ошибку в своей логике. Думал это я чего намудрил. Но когда нашел причину и сделал код минимальным для глюка.
Первая Ваша ошибка - использование библиотек от Гайвера. Гайвер - талантливый блогер, но никудышний программист.
Неожиданно :(
Ок. Попробую другую библиотеку для энкодера. У Гайвера удобная работа с энкодером... вот и остановился на ней. И у него в этой библиотеке есть вариант использования энкодера по прерываниям. Тоже попробую.
Я надеялся что это известный глюк и есть стандартное его решение. Спасибо.
С другой тоже весьма вероятно упретесь в то, что при наличии функций, работающих с LCD, энкодер в линейном алгоритме точно так же будет работать непредсказуемо. Чуть побольше объёмы вывода и всё, приплыли. Вместо lcd.*() просто delay поставьте и получите схожую картину.
С другой тоже весьма вероятно упретесь в то, что при наличии функций, работающих с LCD, энкодер в линейном алгоритме точно так же будет работать непредсказуемо. Чуть побольше объёмы вывода и всё, приплыли. Вместо lcd.*() просто delay поставьте и получите схожую картину.
Хм... как же тогда с ними(энкодерами) работать.... Как понять "энкодер в линейном алгоритме"?
Или это как раз намек на "попробовать с энкодером работать через прерывания"?
Хм... как же тогда с ними(энкодерами) работать....
Перечитайте последний абзац поста №2.
В общем так и поступил. Но с Гайверской библиотекой.
Вроде нормально. Буду переносить "идею" в основной код и смотреть как это все заработает. Спасибо
Или все же рекомендуете использовать другую библиотеку? А какую лучше?
Я такую юзаю: https://github.com/PaulStoffregen/Encoder
Мне эта понравилась
Вроде нормально. Буду переносить "идею" в основной код и смотреть как это все заработает. Спасибо
Или все же рекомендуете использовать другую библиотеку? А какую лучше?
Здравствуйте. Подскажите пожалуйста почему данный ниже код работает с глюком.
Потому что
//author=AlexGyver
Попробовал библиотеку из #11 но что-то она у меня с наскока не пошла. Я в код не вникал, запустил пример. Сменил только пины, куда реально у меня подключен энк. Возможно, как говорит Гайвер, имеются двух типов энкодеры, и может как-то можно сменить тип в данной либе... Слишком чувствительно работает. Ручку просто "шатаешь", даже щелчка не делаешь, а значения уже меняются, хотя энкодер новый, не расшатанный.
Из 12 скачал, но не смотрел.... Также не разобрался с "Лионидом Ивановичем".... И как я понял, все эти либы без обработки кнопки энкодера. Не критично, но...
В общем остановился пока на "гайвере" энкодер на двух прерываниях. Приемлимо. Посмотрю как будет дальше. У него(Гайвера) есть еще минилиба и просто "куски кода" для работы с энкодерами... Пока выявил небольшой (а может это и норма) косяк с пропуском шагов если ручку чуть побыстрее(не сильно) крутить...
Здравствуйте. Подскажите пожалуйста почему данный ниже код работает с глюком.
Потому что
//author=AlexGyver
Не пугайте меня) Неужели совсем так плохо?
Спасибо всем отвечавшим.
И как я понял, все эти либы без обработки кнопки энкодера.
Воспользуйтесь "титановым велосипедом".
Попробовал библиотеку из #11 но что-то она у меня с наскока не пошла. Я в код не вникал, запустил пример. Сменил только пины, куда реально у меня подключен энк. Возможно, как говорит Гайвер, имеются двух типов энкодеры, и может как-то можно сменить тип в данной либе... Слишком чувствительно работает. Ручку просто "шатаешь", даже щелчка не делаешь, а значения уже меняются, хотя энкодер новый, не расшатанный.
Да у гайвера там и на прерываниях написана какаято ересь...
я немца библиотеку юзаю, пропусков нет, все пины не пробовал, но импровизировал на разных, ведёт себя везде одинаково, сейчас к примеру на 4 и 5 у него там и на кнопку есть, одиночную, библиотека
А я вообще так до сих пор и не понял, зачем нужна библиотека энкодера, там кода 2-3 строки достаточно.
А Гайвер там что-то про двухимпульсные пишет или типа того?
Ну типа того, вот с его сайта:
Чем отличаются энкодеры на практике: если опрашивать одноимпульсный энкодер как двухимпульсный, то для отработки одного тика нужно повернуть рукоятку на два тика. Если опрашивать двухимпульсный как одноимпульсный, то для отработки одного тика нужно повернуть рукоятку на два тика. То есть при неправильном использовании причина сразу видна.
int32_t newEncoderPos = controlEncoder.read() / 4; - Это помогло.
В общем когда я в основном коде поменял использование энкодера с прерываниями с гайверовской либой, стало лучше, но пропуски шагов стали ужасно... т.е. ручку нужно медленно крутить, тогда норм и то может и пропустить.... Хотя я только начал писать скеч и он не такой большой, да собс-но там работа только с lcd и энкодером... Странно. Буду пробовать с другими либами...
И еще такой непонятный глюк появился. Если сразу как только запустить Arduino IDE 1.8.10 и в нем уже по умолчанию загружен скеч. Нажимаем "компиляция" или "Загрузка" не важно - то сразу вылазит:
Потому что файл не перекомпилируется, если он не изменялся.
Вам еще либа для обработки кнопки нужна?
Воспользуйтесь "титановым велосипедом".
Ну это по большей части из-за лени... Если есть готовый код, то почему бы и не воспользоваться...
Так-то можно вообще не использовать библиотек и самому все делать с нуля :)
А у меня не просто энкодер, а модуль уже с RC (китайский), поэтому хотелось как проще и меньше писанины, но.... получается как всегда). Вообще первый раз с энкодерами связался...
Все равно не понятно.
Вот я открыл IDE с уже загруженном скечем. Нажимаю первый раз компиляция. Варнинг. Сразу второй раз. Чисто. Ведь я же его не менял.
Но даже если что-то изменить, сохранить. Закрыть ИДЕ. И заново открыть. То опять первый раз варнинг, второй четко.
Начнем с того, что если кому то нужен программный антидребезг, сразу мимо. Два копеешных конденсатора, не стоят этих извращений.
А мой код на энкодер выглядит так:
Зачем тут библиотека ?
Зачем тут библиотека ?
Ну данный код по большому счету и ничего и не делает. Это как бы ядро.
Но даже так:
(Давно я не программировал... Можно ли так менять волатайловскую переменную?)
у меня получается два тика на один щелчок.
Может у меня энкодер дибильный :(
В прочем если дальше с этим ядром делать то что нужно + обработка кнопки, короткое нажатие, длинное удержание... Получится кода на еще одну библиотеку :)
(Давно я не программировал... Можно ли так менять волатайловскую переменную?)
у меня получается два тика на один щелчок.
Может у меня энкодер дибильный :(
В прочем если дальше с этим ядром делать то что нужно + обработка кнопки, короткое нажатие, длинное удержание... Получится кода на еще одну библиотеку :)
А кнопка вообще к энкодеру никакого отношения не имеет.
Там должен быть отдельный обработчик.
attachInterrupt() может быть не только CHANGE(с ним и будет два тика), а ещё и FALLING/RISING.
В коде был показан обработчик энкодера, как дальше использовать результат обработки, это уже отдельная песня.
Смысл приведения данного кода в том, что бы показать, что библиотека (любая,не говоря уже про библиотеку гивера) в принципе нафиг не нужна
в русском языке прижилось слово - волатильность )))
самое сложное как раз - как это использовать
Все равно не понятно.
Вот я открыл IDE с уже загруженном скечем. Нажимаю первый раз компиляция. Варнинг. Сразу второй раз. Чисто. Ведь я же его не менял.
Но даже если что-то изменить, сохранить. Закрыть ИДЕ. И заново открыть. То опять первый раз варнинг, второй четко.
1) Открыл скетч (исходник), нажал "компиляция", компилятор обнаружил в исходнике проблему - отсигнализировал, но объектный код создал, положил в каталог кэша.
2) Не закрывая IDE нажал опять "компиляция" - компилятор обнаружил, что объектный код уже есть, исходник не менялся, компиляцию делать не стал - ошибку не вывел.
3) Закрыл IDE - потерял пути к кэшированным файлам. Goto 1.
Странно. Буду пробовать с другими либами...
Вам нужно устранять проблему, а не перебирать библиотеки.
Ну это по большей части из-за лени... Если есть готовый код, то почему бы и не воспользоваться...
Так-то можно вообще не использовать библиотек и самому все делать с нуля :)
Все равно не понятно.
Это все понятно, но... Если на втором шаге, после второй компиляции ничего не закрывать(из IDE не выходить) а поменять что-то в тексте и нажать еще раз(третий, четвертый...) компиляцию, то варнинга больше нет.
Меня вот этот момент и задел. Как так, что варнинг показывается только при первой компиляции, а потом типа просто помни про него :( Я смотрел код библиотеки дисплея и его функцию begin и в теле begin действительно не используется передаваемый в нее параметр cols.
Это все понятно, но... Если на втором шаге, после второй компиляции ничего не закрывать(из IDE не выходить) а поменять что-то в тексте и нажать еще раз(третий, четвертый...) компиляцию, то варнинга больше нет.
И что в этом непонятного? Компилятор пересобирает только те обьектные файлы, исходники которых изменились. Вы меняете только текст своего скетча, текст библиотеки (той в которой возникает предупреждение) - не меняется, поэтому он не пересобирается и варнинга нет.
Вы, похоже, не читаете, что Вам пишут.
Я Вас понимаю и Вы в общем-то говорите правильно. Но как всегда есть но...
Во первых у меня нет столько времени разбираться как железка работает. С энкодером то еще ладно, но с дисплеем я бы тупил долго.... Во вторых у меня нет таких сильных познаний в си, к сожалению(
В третьих ну не зря же делаются эти библиотеки, Да, есть грамотно сделанные, есть не очень, ну и совсем фуфло тоже есть.... Может быть Вы себя считаете лучше всех в программировании, тогда да, вопросов нет. Лучше делать все с нуля и самому.
Но я например не уверен, что сделаю лучше даже чем гайвер, или даже уверен что многое не сделаю лучше чем сделано уже другими. Поэтому не считаю зазорным "пользоваться чужим" ибо это для этого и предназначено.
В конкретном моем случае я не уверен где основная ошибка. В библиотека энкодера гайвера, в библиотеке LCD, в версии IDE(ага, оказывается и такое может быть (но это не совсем так, новые компиляторы не совместимы со "старыми библиотеками" т.е. по сути дело не в IDE а в либах) или в моем коде. Хотелось бы разобраться.
Даже если самому с нуля делать можно так же напороться на грабли и долго искать проблему.
Уверен, что многие сейчас скажут. "Да вы что, я сам пишу все с нуля и никогда не наступаю на грабли и все у меня быстро решается и все у меня гладко" Я рад за таких людей и им завидую
И что в этом непонятного? Компилятор пересобирает только те обьектные файлы, исходники которых изменились. Вы меняете только текст своего скетча, текст библиотеки (той в которой возникает предупреждение) - не меняется, поэтому он не пересобирается и варнинга нет.
Все теперь понятно, вопросов больше по данному вопросу не имею. Спасибо.
На данный момент с библиотекой гайвера работа с экодером даже по двум прерываниям происходит ужасно. Очень сильно пропускаются шаги. Ручку нужно крутить ну очень медленно, что бы работало... Поэтому буду пробовать может быть самому обрабатывать этот энкодер, например за основу возьму #25.
Но как-то странно получается. Я пересмотрел(поверхностно) код всех либ, которые тут озвучены. В некоторых много чего используется... А по сути на выходе тоже самое что и в #25 Не все так просто как кажется и не все так сложно как есть на самом деле :)
На данный момент с библиотекой гайвера работа с экодером даже по двум прерываниям происходит ужасно. Очень сильно пропускаются шаги. Ручку нужно крутить ну очень медленно, что бы работало... Поэтому буду пробовать может быть самому обрабатывать этот энкодер, например за основу возьму #25.
Но как-то странно получается. Я пересмотрел(поверхностно) код всех либ, которые тут озвучены. В некоторых много чего используется... А по сути на выходе тоже самое что и в #25 Не все так просто как кажется и не все так сложно как есть на самом деле :)
попробуйте библиотеку из поста #12, она точно не пропускает, числа правда даёт в относительных, от начала старта единицах, вот пример как устанавливаю частоту:
Пробуйте
А вообще,что бы дисплей с энкодером не конфликтовали, дисплей нужно обновлять только тогда, когда обновляются выводимые данные, да и в принципе если это будет происходит с частотой достаточной для восприятия (скажем 5-10Гц), таких проблем не будет.
Накладки и задержки всегда будут. Выводи хоть раз в секунду, хоть раз в 10 секунд. Не с дисплеем, так с другим чем-то всплывёт задержка.
попробуйте библиотеку из поста #12, она точно не пропускает, числа правда даёт в относительных, от начала старта единицах....
Попробовал. Там в этом RotaryEncodor'е есть кстати getDirection()... Правда я со своими познаниями си сходу не понял как ее использовать. Но вот:
Если убрать delay(10) - (довольно большая в принципе задержка, но все же) то да, пропусков нет.
В общем наверное не все так просто с этими энкодерами(
PS:
Дык они и обновляются при вращении ручки энкодера :( Но вообще полностью согласен. Здесь по ходу нужно какую-то "хитрую" логику делать...
Но тут по всей видимости не только в дисплее дело :(
В библиотеке Стоффрегена прерывания подключаются в бэкграунде, если пины, на которые терминалы заведены, их поддерживают.
Но дело тут, зачастую, действительно может оказаться непростым и универсальных решений для всех случаев чохом - нет.
Пробуйте
Самый лучший результат пока получился. Спасибо.
В прочем это практически код из 25. Моя лень и низкие знания си не дали мне сразу сообразить это:
Но vosara мне дал хорошего пинка)
Как видно задержку я увеличил в пять раз (по сравнению с кодом использования библиотеки RotaryEncoder в #40) и все равно пропусков нет.
Да, если ручку вертеть слишком быстро, то может и пропускаются шаги, но они идут (в данном случае cnt увеличивается/уменьшается) строго на 1
В общем остановлюсь я пока на данном варианте
Немного подправил. Сделал для теста вот такой код:
В некоторых местах сделал специально "тормозной код". Работает лучше всего, что я пробовал выше.
Вопрос: переменную bool f_isrA = false; не нужно делать валотайловой(или валотильной, как правильно, вообщем volatile)?
Она хоть и используется только в прерываниях, но всеж...
Но я например не уверен, что сделаю лучше даже чем гайвер, или даже уверен что многое не сделаю лучше чем сделано уже другими. Поэтому не считаю зазорным "пользоваться чужим" ибо это для этого и предназначено.
В конкретном моем случае я не уверен где основная ошибка. В библиотека энкодера гайвера, в библиотеке LCD, в версии IDE(ага, оказывается и такое может быть (но это не совсем так, новые компиляторы не совместимы со "старыми библиотеками" т.е. по сути дело не в IDE а в либах) или в моем коде. Хотелось бы разобраться.
//Да, если ручку вертеть слишком быстро, то может и пропускаются шаги
разумеется будут пропуски если cnt суммировать в лупе, а не там, где encTick получен.
Если это поправить, то код будет работать не плохо пока контакты энкодера не окислятся. Потом на один шаг начнет несколько единиц прибавлять. Чтоб это поправить надо задуматься над несоответствием - контакты енкодкра выдают в общем одинаковый сигнал несколько сдвинутый по фазе. А обработчики 2-х прерываний сильно разные. Потому давят "дребезг" только в половине случаев. Обработчики тоже надо сделать с одинаковой логикой для спада обоих входных сигналов.
И еще. "Дребезг" вызывает частые вызовы обработчиков прерывания, что плохо. Потому в качестве f_isrA лучше использовать флаги разрешения прерываний. Т.е. всегда разрешено только одно из прерываний. Например разрешено сразу isrA. При срабатывании isrA разрешаем isrB и запрещаем isrA. Потом при срабатывании isrB разрешаем isrA и запрещаем isrB, ну и encTick присваиваем (или может увеличиваем или уменьшаем? ;)
// Вопрос: переменную bool f_isrA = false; не нужно делать валотайловой(или валотильной, как правильно, вообщем volatile)?
Тут пофиг оно.
Может быть Вы себя считаете лучше всех в программировании, тогда да, вопросов нет.
На сколько хватает моих познаний я все же стараюсь разобраться. Но увы, их не достаточно (
#46 - спасибо. Т.е. пока у меня новый энкодер, код из #44 работает нормально. Но скоро придет проблема. Правильно я понял?
Буду учитывать замечания по дребезгу и прерываниям. Всем спасибо.
Вы должны понимать, как работает ЛЮБОЙ кусок используемого Вами кода, вне зависимости от того, написан он Вами или кем-то другим. Вы же хотите использовать библиотеки, не разбираясь, как они работают.
В логике я еще разберусь, но для меня сложна в разбирании бинарная математика :( Если Вы обратили внимание, то я иногда тут поправляю код. Стараюсь его оптимизировать. Может и не получается у меня, но я ...стараюсь) И вы(все) мне в этом очень помогаете. Спасибо
Вы допускаете неприемлемо большие паузы между вызовами encoder.tick(), из-за чего происходят пропуски сигналов энкодера. Со всеми вытекающими последствиями.
Это да, у меня между вызовами процедуры опроса энкодера проходит всего 24 микросекунды, поэтому ни разу не наскочил на пропуски, работает как швейцарские часы