энкодер и лсд1602
- Войдите на сайт для отправки комментариев
Чт, 12/07/2018 - 16:26
добрый день. есть у меня энкодер, и хочу я данные с него выводить на дисплей ( в серийный порт скетч все пишет исправно). только вот когда дописываю lcd.print (nc) в функцию encoderTurn - контроллер виснет, успевая в серийник отправить только Tu
/* Если кому нужно, выкладываю скетч подключения дешманского китайского энкодера KY-040 с прерыванием по вращению и прерыванием по нажатию. Двойной шаг вращения (с фиксацией ручки экнодера) считается за один. Немного отрегулировал чувствительность, протестировал на нескольких энкодерах KY-040, все работают. */ #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,16,2); //Скетч для подключения энкодера KY-040 к Ардуино Мега с прерыванием по вращению и нажатию //----------------------------— //Указываем пины энкодера #define CLK 2 //Прерывание1! #define DT 4 #define SW 3 //Прерывание2! //----------------------------— #define NORM_STEP 1 // шаг изменения переменной norm_counter при вращении #define HOLD_STEP 1 // шаг изменения переменной hold_counter при нажатии, удерживании и вращении //#define Beeper 12 //Указываем пин Пищалки //================================================================================================== //Объявляем переменные int norm_counter, hold_counter, nc, hc, d; boolean DT_now, DT_last, SW_state, hold_flag, butt_flag, turn_flag; unsigned long debounce_timer; //================================================================================================== void setup() { Serial.begin(9600); pinMode(CLK, INPUT); pinMode(DT, INPUT); pinMode(SW, INPUT_PULLUP); lcd.init(); lcd.backlight(); attachInterrupt(0, encoderTick, CHANGE);//подключаем прерывание для вращения attachInterrupt(1, encoderTick, CHANGE);//подключаем прерывание для нажатия DT_last = digitalRead(CLK); // читаем начальное положение CLK (энкодер) //pinMode(Beeper, OUTPUT); //Подключаем пищалку //tone(Beeper, 3000, 5);// Пищим } //================================================================================================== void loop() { Encoder_Hold(); //Опрос кнопки энкодера на предмет ее удержания в нажатом положении (Hold) } //=================================================================================================== //Функции Энкодера void encoderTick() { DT_now = digitalRead(CLK); // читаем текущее положение CLK SW_state = !digitalRead(SW); // читаем положение кнопки SW // отработка нажатия кнопки энкодера //-------------------------------------------------------------------------------------------------— //Нажали кнопку, держим if (SW_state && !butt_flag) //Если: { butt_flag = 1; //Кнопку точно нажали hold_flag = 0; //Немного удерживали turn_flag = 0; //Не крутили debounce_timer = millis(); //Засекаем таймер //tone(Beeper, 3000, 5); //Пищим encoderClick(); //Выполняем команды в функции Нажатие (Клик) } //-------------------------------------------------------------------------------------------------— if (!SW_state && butt_flag && hold_flag) //Если держали долго: { butt_flag = 0; //Кнопку отпустили debounce_timer = millis(); //Сравниваем время } //-------------------------------------------------------------------------------------------------— if (!SW_state && butt_flag && millis() - debounce_timer > 10 && millis() - debounce_timer < 500) { butt_flag = 0; if (!turn_flag && !hold_flag) { // если кнопка отпущена и ручка не поворачивалась turn_flag = 0; encoderPress(); } debounce_timer = millis(); } //-------------------------------------------------------------------------------------------------— if (DT_now != DT_last) { // если предыдущее и текущее положение CLK разные, значит был поворот if (digitalRead(DT) != DT_now) { // если состояние DT отличается от CLK, значит крутим по часовой стрелке if (SW_state) { // если кнопка энкодера нажата d = hc; hold_counter -= HOLD_STEP; hc=hold_counter/2; if (hc < d) { //tone(Beeper, 3000, 5); encoderHoldTurn(); } } else { // если кнопка энкодера не нажата d = nc; norm_counter -= NORM_STEP; nc=norm_counter/2; if (nc < d) { encoderTurn(); } } } else { // если совпадают, значит против часовой if (SW_state) { // если кнопка энкодера нажата d = hc; hold_counter += HOLD_STEP; hc=hold_counter/2; if (hc > d) { //tone(Beeper, 3000, 5); encoderHoldTurn(); } } else { // если кнопка энкодера не нажата d = nc; norm_counter += NORM_STEP; nc=norm_counter/2; if (nc > d) { //tone(Beeper, 3000, 5); encoderTurn(); } } } turn_flag = 1; // флаг что был поворот ручки энкодера } DT_last = DT_now; // обновить значение для энкодера } //=================================================================================================== //Опрос кнопки энкодера на предмет ее удержания в нажатом положении (Hold) void Encoder_Hold() { if (SW_state && butt_flag && millis() - debounce_timer > 500 && !hold_flag) //Если: { hold_flag = 1; //Долго удерживали в нажатом состоянии (более 500мс) if (!turn_flag) //Но при этом не крутили { turn_flag = 0; //tone(Beeper, 3000, 5);//Пищим encoderHold(); //Выполняем команды в функции Холд } } } //=================================================================================================== void encoderClick() { Serial.print("Click, "); Serial.print("butt_flag: "); Serial.print(butt_flag); Serial.print(", hold_flag: "); Serial.print(hold_flag); Serial.print(", millis(): "); Serial.println(millis()); } //=================================================================================================== void encoderPress() { Serial.print("Press, "); Serial.print("butt_flag: "); Serial.print(butt_flag); Serial.print(", hold_flag: "); Serial.print(hold_flag); Serial.print(", millis(): "); Serial.println(millis()); } //=================================================================================================== void encoderHold() { Serial.print("Hold, "); Serial.print("butt_flag: "); Serial.print(butt_flag); Serial.print(", hold_flag: "); Serial.print(hold_flag); Serial.print(", millis(): "); Serial.println(millis()); } //=================================================================================================== void encoderTurn() { Serial.print("Turn: "); Serial.print("butt_flag: "); Serial.print(butt_flag); Serial.print(", hold_flag: "); Serial.print(hold_flag); Serial.print(", NORM_STEP: "); Serial.print(NORM_STEP); Serial.print(", nc: "); Serial.println(nc); //lcd.print(nc); } //=================================================================================================== void encoderHoldTurn() { Serial.print("HTurn: "); Serial.print("butt_flag: "); Serial.print(butt_flag); Serial.print(", hold_flag: "); Serial.print(hold_flag); Serial.print(", HOLD_STEP: "); Serial.print(HOLD_STEP); Serial.print(", hc: "); Serial.println(hc); }
не знаю, как код под кат убрать, извините
вопрос
"Двойной шаг вращения (с фиксацией ручки экнодера) считается за один."
сам не смог придумать ради чего за такое биться =) расскажите зачем такая функция понадобилась
Попробуйте в функции encoderTurn() закоментируйте все Serial.print(), оставьте там только lcd.
иначе энкодер за оин шаг по два прибавляет. хз мочему, даже не копал. не до этого
неа. виснет так же, мробовал уже. при чем, если в лупе, то все норм.
Нечего все в обработчик прерывания совать. Напхали - ловите глюки.
подробней. куда пихать надо, так что все норм было и после первого свидания не бросила? виснет даже если убираю весь сериал.
Если Вы не пишете lcd.print(nc); , а только сериал, у Вас код работает, все функции выполняются. Как только запихиваете в функцию ЛСД получается глюк. Я правильно понял.
Вся работа с сериалами-дисплеями - только в лупе. В обработчике только фиксация факта проворота энкодера.
ясно, спасибо
да, именно.
И, кстати, два раза обработчик срабатывает при одном щелчке потому что вы, как я понимаю, повесили оба терминала энкодера на прерывания. Вот они друг за другом и вызывают tick(). Снимите прерывание с любого второго терминала и щелкать будет один раз. Пока не разболтается.
эт не я, это добрый самаритянин)
не скажите, с чем связано такое нежелание работать с дисплеем в обработчике?
Полагаю с тем, что он подключен через I2C, Wire хочет прерывания и не имеет выхода из функций по таймауту, а прерывания на время выполнения обработчика запрещены.
Но для точного диагноза нужно пройтись по всей цепочке библиотек до самого низа.