ПАУЗА секундомер

Тема в разделе "Arduino & Shields", создана пользователем ИванМорозов, 8 авг 2017.

  1. Добрый день. патаюсь сделать паузу при отчете времени ,но увы. Прошу дать подсказку в чем ошибка

    Код (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){}

    }
     
  2. AlexU

    AlexU Гуру

    Логика программы запутана, так сходу и не скажешь что не так. Может подробней объясните, что делает программа?
    А так бы советовал не много пересмотреть логику в общем:
    • введите очередь сообщений нажатых кнопок;
    • обработку нажатия кнопок с постановкой сообщений в очередь лучше вынести в прерывание (по заверешению ADC преобразования), там же в прерывании программным способом решите проблему дребезга;
    • в основном цикле просматривайте очередь сообщений и меняйте состояние "автомата" (вот тут надо определится сколько состояний в автомате, я пока увидел только два явно декларированных -- переменная 'mainMenuPage' может принимать значения 1 или 2 -- но я думаю состояний должно быть больше).
    Если готовы на такие кардинальные изменения, то готов поделится кусками кода -- реализации аналог.клавиатуры на прерывании, очереди сообщений и т.п.

    Правда проект разработан под ATtiny45, но проблем с портированием под Arduino не будет, если конечно используется Arduino на базе ATmega328.
     
    arkadyf нравится это.
  3. b707

    b707 Гик

    Было бы проще, если бы Вы указали, в какой части скетча пытались делать паузу - я не нашел. Зато нашел строчку - if (LOW == (ReadKeypad() == 'S')) - не пишите такого, это говнокод, даже если он иногда работает
     

  4. В подменю . Повторное нажатие S т.е ок пауза .... на счёт этой строчки я с вами соглашусь , т.к Вы больше меня знаете , и больше гугла тоже, не нашёл я ответ на свой вопрос ....
     


  5. Это программа просто так , для своего развития , есть желание написать более нужную для дома, и так как там есть пауза я решил потренироваться на простеньком - поучиться , но меню будет это
     
  6. b707

    b707 Гик

    Честно говоря. все равно не нашел.
    Пойдем пока дальше по глюкам. Вопрос - что возвращает функция ReadKeypad(), если ни одна кнопка не нажата?
     
  7. AlexU

    AlexU Гуру

    Если правильно понял задумку автора, то как минимум ошибка в этом условии (типа "говнокод"):
    Код (C++):
    if (LOW == (ReadKeypad() == 'S'))    //кнопка нажата
    Дело в том, что при нажатии 'S' условие вернёт "ложь", а во всех остальных случаях (нажатие либой другой кнопки или в случае, если все кнопки отжаты) вернёт "истину". Вот каунтер (enableCounter) и не "энаблится", а если и "энаблится", то сразу "дизаблится", что для глаз не заметно.
     
  8. Ага ..... подумаем....
     
  9. Задумка - переменную code в подменю остановить повторным нажатием на кнопку S и выйти в главное меню на кнопку L
     
  10. b707

    b707 Гик

    Кмк, вторая ошибка в функции ReadKeypad() - в ней нет значения "по умолчанию", когда все кнопки отжаты. Я не знаю, что она вернет при ненажатых кнопках. То есть при нажатии "S" функция возвращает этот символ, а при отпускании кнопки? - без теста сразу не соображу, может значение "S" "залипает" до следующего нажатия?
     
  11. Код (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() , (определение кнопок)


    При отпускание не чего не должно выполнять
     
  12. AlexU

    AlexU Гуру

    Так понимаю, что в функции 'MenuB_SECUND()' подразумевается, что строчка кода:
    Код (C++):
    while(ReadKeypad()=='L');
    должна ожидать нажатия кнопки 'L'. Но в реале всё будет совсем по другому. Этот цикл вообще не имеет ни какого смысла и на работу программы ни как влиять не будет.
    Подтверждаю. При отжатых кнопках функция будет возвращать "мусор", оставшийся от работы других функций или т.п.
    Нет, не "залипнет". Надо смотреть дизассемблированный код -- например, если возврат идёт через какой-либо регистр, то вернётся значение регистра на момент выхода из функции, а в этом регистре может быть всё что угодно.
    А должна, если функция возвращает значение, то это значение должно быть явно определено или Вас будет ждать "сюрприз".
     
    arkadyf нравится это.
  13. Код (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);
      }
    }


     
    Я ориентировало на этот пример, но собрав его на доске все работает , но у меня аналоговые кнопки и меню , не так все просто оказалось
     
  14. AlexU

    AlexU Гуру

    Во-первых в примере опрос кнопки происходит в теле '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);
     
    Но это предложения, так сказать, "на скорую руку" -- может ни чего не заработать.
     
    arkadyf нравится это.
  15. Дайте подалуйста ещё подсказку для решения этой проблемы ?!
     
  16. b707

    b707 Гик

    Вы сделали то, что предложил AlexU? Как результаты?
     
  17. Ага, при нажатие на S выходит в глав меню , а должно останавливать счётчик
     
  18. AlexU

    AlexU Гуру

    Для начала нужно разработать подробный алгоритм на основе пожеланий -- что же Вы хотите от устройства. А потом этот алгоритм описать на языке 'C'.
    А ту мешанину кода, что представили в первом посте, лучше выкинуть.