Добрый день. патаюсь сделать паузу при отчете времени ,но увы. Прошу дать подсказку в чем ошибка Код (C++): #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display int keypad_pin = A0; // пин АНАЛОГОВОЙ клавиатуры int keypad_value = 0; //уровень int keypad_value_old = 0; //------------------ int code = 0; boolean enableCounter; //----------- char btn_push; byte mainMenuPage = 1; byte mainMenuPageOld = 1; byte mainMenuTotal = 2; // кол-во меню void setup() { lcd.init(); // initialize the lcd lcd.clear(); // очистка lcd lcd.backlight(); //------------------- Serial.begin(9600); enableCounter = true; //-------------------- MainMenuDisplay(); delay(1000); } void loop() { btn_push = ReadKeypad(); MainMenuBtn(); if(btn_push == 'S')//ок { WaitBtnRelease(); switch (mainMenuPage) { case 1: MenuA_TIME(); break; case 2: MenuB_SECUND(); break; } MainMenuDisplay(); WaitBtnRelease(); } delay(10); //-------------— End of loop() loop —------------------- // ------------- Под меню. функции что делать при выборе меню --- } void MenuA_TIME() { lcd.clear(); lcd.setCursor(0,0); lcd.print("Inside Menu A"); while(ReadKeypad()!= 'L') { //Insert Task for Menu A here } } void MenuB_SECUND() { lcd.clear(); lcd.setCursor(0,0); //while(ReadKeypad()!= 'L') // выход в главное меню //Insert Task for Menu C here { if (LOW == (ReadKeypad() == 'S')) //кнопка нажата { enableCounter = !enableCounter; // меняем на противоположное while(ReadKeypad()!= 'S'); // ждем пока отпустим кнопку } if (true == enableCounter) // если отсчет разрешен { code++; // увеличиваем счетчик if (code >=60) code = 0; // условия Serial.println(code); delay(200); lcd.setCursor(0,1); lcd.print( code); while(ReadKeypad()=='L'); } } } void MainMenuDisplay() // главное меню { lcd.clear(); lcd.setCursor(0,0); switch (mainMenuPage) { case 1: lcd.print("1. SAVE_TIME"); // название меню break; case 2: lcd.print("2. SECUND"); break; } } void MainMenuBtn() { WaitBtnRelease(); if(btn_push == 'U') { mainMenuPage++; if(mainMenuPage > mainMenuTotal) mainMenuPage = 1; } else if(btn_push == 'D') { mainMenuPage--; if(mainMenuPage == 0) mainMenuPage = mainMenuTotal; } if(mainMenuPage != mainMenuPageOld) //only update display when page change { MainMenuDisplay(); mainMenuPageOld = mainMenuPage; } } char ReadKeypad() { /* Уровень аналоговых кнопок 1 -0 2 -340 3 -453 4 -511 */ keypad_value = analogRead(keypad_pin); if(keypad_value < 50) return 'U'; // вверх else if(keypad_value < 400) return 'D'; // вниз else if(keypad_value < 500) return 'S'; // ок else if(keypad_value < 600) return 'L'; // назад } void WaitBtnRelease() { while( analogRead(keypad_pin) < 600){} } Код (C++): #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display int keypad_pin = A0; // пин АНАЛОГОВОЙ клавиатуры int keypad_value = 0; //уровень int keypad_value_old = 0; //------------------ int code = 0; boolean enableCounter; //----------- char btn_push; byte mainMenuPage = 1; byte mainMenuPageOld = 1; byte mainMenuTotal = 2; // кол-во меню void setup() { lcd.init(); // initialize the lcd lcd.clear(); // очистка lcd lcd.backlight(); //------------------- Serial.begin(9600); enableCounter = true; //-------------------- MainMenuDisplay(); delay(1000); } void loop() { btn_push = ReadKeypad(); MainMenuBtn(); if(btn_push == 'S')//ок { WaitBtnRelease(); switch (mainMenuPage) { case 1: MenuA_TIME(); break; case 2: MenuB_SECUND(); break; } MainMenuDisplay(); WaitBtnRelease(); } delay(10); //-------------— End of loop() loop —------------------- // ------------- Под меню. функции что делать при выборе меню --- } void MenuA_TIME() { lcd.clear(); lcd.setCursor(0,0); lcd.print("Inside Menu A"); while(ReadKeypad()!= 'L') { //Insert Task for Menu A here } } void MenuB_SECUND() { lcd.clear(); lcd.setCursor(0,0); //while(ReadKeypad()!= 'L') // выход в главное меню //Insert Task for Menu C here { if (LOW == (ReadKeypad() == 'S')) //кнопка нажата { enableCounter = !enableCounter; // меняем на противоположное while(ReadKeypad()!= 'S'); // ждем пока отпустим кнопку } if (true == enableCounter) // если отсчет разрешен { code++; // увеличиваем счетчик if (code >=60) code = 0; // условия Serial.println(code); delay(200); lcd.setCursor(0,1); lcd.print( code); while(ReadKeypad()=='L'); } } } void MainMenuDisplay() // главное меню { lcd.clear(); lcd.setCursor(0,0); switch (mainMenuPage) { case 1: lcd.print("1. SAVE_TIME"); // название меню break; case 2: lcd.print("2. SECUND"); break; } } void MainMenuBtn() { WaitBtnRelease(); if(btn_push == 'U') { mainMenuPage++; if(mainMenuPage > mainMenuTotal) mainMenuPage = 1; } else if(btn_push == 'D') { mainMenuPage--; if(mainMenuPage == 0) mainMenuPage = mainMenuTotal; } if(mainMenuPage != mainMenuPageOld) //only update display when page change { MainMenuDisplay(); mainMenuPageOld = mainMenuPage; } } char ReadKeypad() { /* Уровень аналоговых кнопок 1 -0 2 -340 3 -453 4 -511 */ keypad_value = analogRead(keypad_pin); if(keypad_value < 50) return 'U'; // вверх else if(keypad_value < 400) return 'D'; // вниз else if(keypad_value < 500) return 'S'; // ок else if(keypad_value < 600) return 'L'; // назад } void WaitBtnRelease() { while( analogRead(keypad_pin) < 600){} }
Логика программы запутана, так сходу и не скажешь что не так. Может подробней объясните, что делает программа? А так бы советовал не много пересмотреть логику в общем: введите очередь сообщений нажатых кнопок; обработку нажатия кнопок с постановкой сообщений в очередь лучше вынести в прерывание (по заверешению ADC преобразования), там же в прерывании программным способом решите проблему дребезга; в основном цикле просматривайте очередь сообщений и меняйте состояние "автомата" (вот тут надо определится сколько состояний в автомате, я пока увидел только два явно декларированных -- переменная 'mainMenuPage' может принимать значения 1 или 2 -- но я думаю состояний должно быть больше). Если готовы на такие кардинальные изменения, то готов поделится кусками кода -- реализации аналог.клавиатуры на прерывании, очереди сообщений и т.п. Правда проект разработан под ATtiny45, но проблем с портированием под Arduino не будет, если конечно используется Arduino на базе ATmega328.
Было бы проще, если бы Вы указали, в какой части скетча пытались делать паузу - я не нашел. Зато нашел строчку - if (LOW == (ReadKeypad() == 'S')) - не пишите такого, это говнокод, даже если он иногда работает
В подменю . Повторное нажатие S т.е ок пауза .... на счёт этой строчки я с вами соглашусь , т.к Вы больше меня знаете , и больше гугла тоже, не нашёл я ответ на свой вопрос ....
Это программа просто так , для своего развития , есть желание написать более нужную для дома, и так как там есть пауза я решил потренироваться на простеньком - поучиться , но меню будет это
Честно говоря. все равно не нашел. Пойдем пока дальше по глюкам. Вопрос - что возвращает функция ReadKeypad(), если ни одна кнопка не нажата?
Если правильно понял задумку автора, то как минимум ошибка в этом условии (типа "говнокод"): Код (C++): if (LOW == (ReadKeypad() == 'S')) //кнопка нажата Дело в том, что при нажатии 'S' условие вернёт "ложь", а во всех остальных случаях (нажатие либой другой кнопки или в случае, если все кнопки отжаты) вернёт "истину". Вот каунтер (enableCounter) и не "энаблится", а если и "энаблится", то сразу "дизаблится", что для глаз не заметно.
Задумка - переменную code в подменю остановить повторным нажатием на кнопку S и выйти в главное меню на кнопку L
Кмк, вторая ошибка в функции ReadKeypad() - в ней нет значения "по умолчанию", когда все кнопки отжаты. Я не знаю, что она вернет при ненажатых кнопках. То есть при нажатии "S" функция возвращает этот символ, а при отпускании кнопки? - без теста сразу не соображу, может значение "S" "залипает" до следующего нажатия?
Код (C++): char ReadKeypad() { /* Уровень аналоговых кнопок 1 -0 2 -340 3 -453 4 -511 */ keypad_value = analogRead(keypad_pin); if(keypad_value < 50) return 'U'; // вверх else if(keypad_value < 400) return 'D'; // вниз else if(keypad_value < 500) return 'S'; // ок else if(keypad_value < 600) return 'L'; // назад } void WaitBtnRelease() { while( analogRead(keypad_pin) < 600){} } Вот что выполняет ReadKeypad() , (определение кнопок) При отпускание не чего не должно выполнять
Так понимаю, что в функции 'MenuB_SECUND()' подразумевается, что строчка кода: Код (C++): while(ReadKeypad()=='L'); должна ожидать нажатия кнопки 'L'. Но в реале всё будет совсем по другому. Этот цикл вообще не имеет ни какого смысла и на работу программы ни как влиять не будет. Подтверждаю. При отжатых кнопках функция будет возвращать "мусор", оставшийся от работы других функций или т.п. Нет, не "залипнет". Надо смотреть дизассемблированный код -- например, если возврат идёт через какой-либо регистр, то вернётся значение регистра на момент выхода из функции, а в этом регистре может быть всё что угодно. А должна, если функция возвращает значение, то это значение должно быть явно определено или Вас будет ждать "сюрприз".
Код (C++): Код (C++): #define MY_BUTTON 5 int code = 0; boolean enableCounter; void setup() { Serial.begin(9600); pinMode(MY_BUTTON, INPUT_PULLUP); enableCounter = true; } void loop () { if (LOW == digitalRead(MY_BUTTON)) // кнопка нажата { enableCounter = !enableCounter; // меняем состояние переменной на противоположное while (!digitalRead(MY_BUTTON)); // ждем пока отпустят кнопку } if (true == enableCounter) // если отсчет разрешен { code++; // увеличиваем счетчик if (code >= 60) code = 0; // пограничные условия Serial.println(code); delay(200); } } Я ориентировало на этот пример, но собрав его на доске все работает , но у меня аналоговые кнопки и меню , не так все просто оказалось
Во-первых в примере опрос кнопки происходит в теле 'loop()', а не в отдельной функции. Во-вторых кнопка цифровая (точнее подключена к цифровому пину), а у Вас кнопки аналоговые. Функцию предлагаю переделать: Код (C++): char ReadKeypad() { /* Уровень аналоговых кнопок 1 -0 2 -340 3 -453 4 -511 */ keypad_value = analogRead(keypad_pin); if(keypad_value < 50) return 'U'; // вверх else if(keypad_value < 400) return 'D'; // вниз else if(keypad_value < 500) return 'S'; // ок else if(keypad_value < 600) return 'L'; // назад return 0; //возвращаем '0', если не нажато ни одной кнопки } Функцию 'MenuB_SECUND()' переделать в: Код (C++): if (ReadKeypad() == 'S') //кнопка нажата { enableCounter = !enableCounter; // меняем на противоположное while(ReadKeypad()!= 'S'); // ждем пока отпустим кнопку } if (true == enableCounter) // если отсчет разрешен { code++; // увеличиваем счетчик if (code >=60) code = 0; // условия Serial.println(code); delay(200); lcd.setCursor(0,1); lcd.print( code); Но это предложения, так сказать, "на скорую руку" -- может ни чего не заработать.
Для начала нужно разработать подробный алгоритм на основе пожеланий -- что же Вы хотите от устройства. А потом этот алгоритм описать на языке 'C'. А ту мешанину кода, что представили в первом посте, лучше выкинуть.