Меню

Sancho80
Offline
Зарегистрирован: 30.08.2014

Привет всем. Требуется небольшая помощь. Пишу меню и столкнулся с проблемой. Пока оно написано лишь частично и некоторые вещи в коде лишние. проблема вот в чем: есть кусок кода "установка времени простоя" (строки 111-128), и в нем не выполняется присваивание переменной menu значение 4. Причем в "установке времени работы"(93-110) все работает, и если эти блоки поменять местами, то "время простоя" работает (присваивает menu 4), а "время работы" - нет. Смотрел переменные через serial: item и menu совпадают по условиям. Получается 3 пункта меню, в каждом из них установка параметра, и вот в установку последнего параметра не заходит, непонятно почему. Заранее благодарю за помощь.

#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); 
#define pump 8
#define heat 9
#define ok 4 // кнопка возврата
#define up 3 // увеличение значения 
#define down 2 // уменьшение значения

byte okstate = 0;
byte upstate = 0;
byte downstate = 0;
byte menu = 0;
byte item = 1;
byte temp = 15;

void setup(){
  lcd.init(); // инициализация LCD
  lcd.backlight(); // включаем подсветку 
   pinMode(down, INPUT);
   pinMode(up, INPUT);
   pinMode(ok, INPUT);
   pinMode(pump, OUTPUT);
   pinMode(heat, OUTPUT);
   pinMode(13,OUTPUT);
  }
  
void filt(){ }

void loop(){
     if (menu == 0){
     filt();
     }
// кнопка ОК вход в главное меню
     if (menu == 0 && okstate == 0 && digitalRead(ok) == HIGH){
      menu = 1;
      okstate = 1;
      }
     if (okstate == 1 && digitalRead(ok) == LOW)
         okstate = 0;
// главное меню
     if (menu == 1){
// кнопка ВВЕРХ
     if (upstate == 0 && digitalRead(up) == HIGH){
             item ++;
             upstate = 1;
             }
     if (upstate == 1 && digitalRead(up) == LOW)
     upstate = 0;
     if (item > 4){
     item = 1;
     }
// кнопка ВНИЗ
     if (downstate == 0 && digitalRead(down) == HIGH){
     item--;
     downstate = 1;
     }
     if (downstate == 1 && digitalRead(down) == LOW)
     downstate = 0;
     if (item < 1){
     item = 4;
     }
// выход
     if (item == 4 && okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 0;
     item = 1;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW)
     okstate = 0;
     }
// установка температуры
     if (menu == 1 && item == 1){
     if (okstate == 0 && digitalRead(ok) == HIGH){
     menu = 2;
     lcd.clear();
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW)
     okstate = 0;
     }
     if (menu == 2 && okstate == 0 && digitalRead(ok) == HIGH)
     {
     lcd.clear();
     menu = 1;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW){
     okstate = 0;
     }
// установка времени работы
     if (menu == 1 && item == 2){
     if (okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 3;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW)
     okstate = 0;
     }
     if (okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 1;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW){
     okstate = 0;
     }
// установка времени простоя
     if (menu == 1 && item == 3){
     if (okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 4;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW)
     okstate = 0;
     }
     if (okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 1;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW){
     okstate = 0;
     }
// вывод меню
     if (menu == 0){
     lcd.setCursor(3,0);
     lcd.print("filter  ");
     }
     if (menu == 1){
     lcd.setCursor(3,0);
     lcd.print("main menu");
     if (item == 1){
     lcd.setCursor(3,1);
     lcd.print("set temp");
     }
     else if (item == 2){
     lcd.setCursor(3,1);
     lcd.print("set on  ");
     }
     else if (item == 3){
     lcd.setCursor(3,1);
     lcd.print("set off ");
     }
     else if (item == 4){
     lcd.setCursor(3,1);
     lcd.print("exit    ");
     }
    }
    if (menu == 2){
    lcd.setCursor(3,1);
    lcd.print("temp set ");
    }
    else if (menu == 3){
    lcd.setCursor(3,1);
    lcd.print("ON time  ");
    }
    else if (menu == 4){
    lcd.setCursor(3,1);
    lcd.print("OFF time  ");
    }
}

 

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

в допВкладке есть галочка - свернуть код ( нумеровать - тоже очень хорошо )

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

Sancho80
Offline
Зарегистрирован: 30.08.2014

Что-то я не могу свое сообщение открыть для редактирования. Как удалить тему?

upd: во 2 посте есть ссылка "изменить", а в 1 нет.

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

Sancho80 пишет:

Что-то я не могу свое сообщение открыть для редактирования. Как удалить тему?

Уже никак, и тебя сосчитали(((

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

тему нельзя удалить.... сообщения нежелательно править позднее минут 1.......5 - вытекает из постулатов энштейновых, неоднозначность :(

Sancho80
Offline
Зарегистрирован: 30.08.2014

Тогда так.

#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); 
#define pump 8
#define heat 9
#define ok 4 // кнопка возврата
#define up 3 // увеличение значения 
#define down 2 // уменьшение значения

byte okstate = 0;
byte upstate = 0;
byte downstate = 0;
byte menu = 0;
byte item = 1;
byte temp = 15;

void setup(){
  lcd.init(); // инициализация LCD
  lcd.backlight(); // включаем подсветку 
   pinMode(down, INPUT);
   pinMode(up, INPUT);
   pinMode(ok, INPUT);
   pinMode(pump, OUTPUT);
   pinMode(heat, OUTPUT);
   pinMode(13,OUTPUT);
  }
  
void filt(){ }

void loop(){
     if (menu == 0){
     filt();
     }
// кнопка ОК вход в главное меню
     if (menu == 0 && okstate == 0 && digitalRead(ok) == HIGH){
      menu = 1;
      okstate = 1;
      }
     if (okstate == 1 && digitalRead(ok) == LOW)
         okstate = 0;
// главное меню
     if (menu == 1){
// кнопка ВВЕРХ
     if (upstate == 0 && digitalRead(up) == HIGH){
             item ++;
             upstate = 1;
             }
     if (upstate == 1 && digitalRead(up) == LOW)
     upstate = 0;
     if (item > 4){
     item = 1;
     }
// кнопка ВНИЗ
     if (downstate == 0 && digitalRead(down) == HIGH){
     item--;
     downstate = 1;
     }
     if (downstate == 1 && digitalRead(down) == LOW)
     downstate = 0;
     if (item < 1){
     item = 4;
     }
// выход
     if (item == 4 && okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 0;
     item = 1;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW)
     okstate = 0;
     }
// установка температуры
     if (menu == 1 && item == 1){
     if (okstate == 0 && digitalRead(ok) == HIGH){
     menu = 2;
     lcd.clear();
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW)
     okstate = 0;
     }
     if (menu == 2 && okstate == 0 && digitalRead(ok) == HIGH)
     {
     lcd.clear();
     menu = 1;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW){
     okstate = 0;
     }
// установка времени работы
     if (menu == 1 && item == 2){
     if (okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 3;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW)
     okstate = 0;
     }
     if (okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 1;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW){
     okstate = 0;
     }
// установка времени простоя
     if (menu == 1 && item == 3){
     if (okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 4;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW)
     okstate = 0;
     }
     if (okstate == 0 && digitalRead(ok) == HIGH){
     lcd.clear();
     menu = 1;
     okstate = 1;
     }
     if (okstate == 1 && digitalRead(ok) == LOW){
     okstate = 0;
     }
// вывод меню
     if (menu == 0){
     lcd.setCursor(3,0);
     lcd.print("filter  ");
     }
     if (menu == 1){
     lcd.setCursor(3,0);
     lcd.print("main menu");
     if (item == 1){
     lcd.setCursor(3,1);
     lcd.print("set temp");
     }
     else if (item == 2){
     lcd.setCursor(3,1);
     lcd.print("set on  ");
     }
     else if (item == 3){
     lcd.setCursor(3,1);
     lcd.print("set off ");
     }
     else if (item == 4){
     lcd.setCursor(3,1);
     lcd.print("exit    ");
     }
    }
    if (menu == 2){
    lcd.setCursor(3,1);
    lcd.print("temp set ");
    }
    else if (menu == 3){
    lcd.setCursor(3,1);
    lcd.print("ON time  ");
    }
    else if (menu == 4){
    lcd.setCursor(3,1);
    lcd.print("OFF time  ");
    }
}

 

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

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

....могу быть не правым

std
Offline
Зарегистрирован: 05.01.2012

Программа слишком сложна, так что далее последуют предположения.

1. Сброс переменных *state при отжатой кнопке [вывод сделан по INPUT вместо INPUT_PULLUP в pinMode()] - видимо защита от многократного срабатывания кнопок. Слишком много мест с этим, так что лучше вытащить в отдельную функцию.

#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); 
#define pump 8
#define heat 9
#define ok 4 // кнопка возврата
#define up 3 // увеличение значения 
#define down 2 // уменьшение значения
#define KEY_OK 1
#define KEY_UP 2
#define KEY_DN 3

void setup(){
  lcd.init(); // инициализация LCD
  lcd.backlight(); // включаем подсветку 
  pinMode(down, INPUT);
  pinMode(up, INPUT);
  pinMode(ok, INPUT);
  pinMode(pump, OUTPUT);
  pinMode(heat, OUTPUT);
  pinMode(13,OUTPUT);
}
  
void loop(){
  if (digitalRead(ok) == HIGH){
    while(digitalRead(ok) == HIGH){}
    processKey(KEY_OK);
  }
  if (digitalRead(up) == HIGH){
    while(digitalRead(up) == HIGH){}
    processKey(KEY_UP);
  }
  if (digitalRead(down) == HIGH){
    while(digitalRead(down) == HIGH){}
    processKey(KEY_DN);
  }
}

void processKey(byte key){
}

processKey(key) - это будет реакция, то есть нажали кнопку, надо сделать нечто.

Далее, слишком часто пишется в одно и то же место экрана, так что заодно делаем показывание меню:

void menuDisplay(){
  lcd.setCursor(3,0);
  switch(menu){
    case 0:
     lcd.print("main menu");
    break;
    case 1:
     lcd.print("temp set ");
    break;
    case 2:
     lcd.print("ON time  ");
    break;
    case 3:
     lcd.print("filter   ");
    break;
    case 4:
     lcd.print("OFF time ");
    break;
  }
}

После этого рисуем на бумаге все возможные варианты меню, и таким образом получаем дерево режимов. Очередное предположение - menu это на самом деле mode, то есть то состояние в котором программа находится в данный момент, а вот item - это menu, то есть собственно пункты меню, то состояние в котором программа будет находиться, если нажмут Ok.

Пишите, что должно делать меню, тогда возможно будет написать нормально. Ещё одно предположение - есть три переменных (on, off, temp) которые можно мотать стрелками.

Sancho80
Offline
Зарегистрирован: 30.08.2014

state нашел в примерах, чтоб избавиться от дребезга и повторов при нажатой кнопке.

В основном цикле крутится функция filt, там будет таймер и термостат. При этом переменная menu = 0. По нажатию ОК входим в меню выбора параметра (menu=1): ontime - период работы насоса, offtime - период простоя насоса, temp set - уставка термостата. Здесь выбираем item и по нажатию ОК входим в пункт установки параметра (menu = 2;3;4). Время ставим в часах кнопками up и down, по нажатию ОК сохраняем в eeprom и выходим на пункт выше. То же и с температурой. Дело в том, что там, где menu присваиваем 2 и 3, все нормально, а вот там, где должно присвоить 4, не присваивает, и в этом условии вообще ничего не работает, если туда что-нибудь добавить. item, menu, onstate выводил в порт, все совпадает с условиями и по нажатиям изменяется как надо кроме присвоения menu 4. Загадка какая-то.

 

std
Offline
Зарегистрирован: 05.01.2012

Sancho80 пишет:
там, где должно присвоить 4, не присваивает, и в этом условии вообще ничего не работает

Мне в таком плоском цикле вообще невозможно найти, что откуда. Так что предлагаю так:

#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); 

#define pump 8
#define heat 9

#define ok 4      // ok/enter
#define up 3      // inc./up
#define down 2    // dec./down

#define KEY_OK 1
#define KEY_UP 2
#define KEY_DN 3

#define onmax   24
#define offmax  24
#define tempmin 1
#define tempmax 40

byte menu = 0;
byte item = 0;
byte temp = 15;
byte ontime = 1;
byte offtime = 1;

void setup(){
  lcd.init();
  lcd.backlight();
  pinMode(down, INPUT);
  pinMode(up, INPUT);
  pinMode(ok, INPUT);
  pinMode(pump, OUTPUT);
  pinMode(heat, OUTPUT);
  pinMode(13,OUTPUT);
  ontime = EEPROM.read(0x00);
  offtime= EEPROM.read(0x01);
  temp   = EEPROM.read(0x02);
  if(ontime>onmax)   ontime=onmax;
  if(offtime>offmax) offtime=offmax;
  if(temp>tempmax)   temp=tempmax;
}
  
void loop(){
  if (digitalRead(ok) == HIGH){
    while(digitalRead(ok) == HIGH){}
    processKey(KEY_OK);
  }
  if (digitalRead(up) == HIGH){
    while(digitalRead(up) == HIGH){}
    processKey(KEY_UP);
  }
  if (digitalRead(down) == HIGH){
    while(digitalRead(down) == HIGH){}
    processKey(KEY_DN);
  }
  if(menu==0) filt();
}

void menuDisplay(byte str){
  /* str: 0 - mode
          1 - menu item
          2 - both + clear screen */
  if(str==2) lcd.clear();
  if(mode>=2 && mode<=4){      // parameters edit modes
    lcd.blink();                  // show cursor
    lcd.cursor();
  }else{                       // other modes
    lcd.noBlink();                // hide cursor
    lcd.noCursor();
  }
  if(str==0 || str==2){
    lcd.setCursor(3,0);
    switch(menu){
      case 0:
       lcd.print("Filter   ");
      break;
      case 1:
       lcd.print("Main menu");
      break;
      case 2:
       lcd.print("ON time: ");
      break;
      case 3:
       lcd.print("OFF time:");
      break;
      case 4:
       lcd.print("Temp set:");
      break;
    }
  }
  if(str==1 || str==2){
    lcd.setCursor(3,1);
    switch(item){
      case 2:
       lcd.print("ON time ");
      break;
      case 3:
       lcd.print("OFF time");
      break;
      case 4:
       lcd.print("Temp set");
      break;
      case 5:
       lcd.print("Go back ");
      break;
    }
  }
}

void processKey(byte key){
  switch(key){
    case KEY_UP:
      if(menu==1 && item<5){    // menu navigation
        item++;
        menuDisplay(1);
      }
      if(menu>=2 && menu<=4) ]cd.setCursor(3,1); // parameter value coords
      if(menu==2 && ontime<onmax){     // menu=2..4 - edit parameter
        ontime++;
        lcd.print(ontime);
      }
      if(menu==3 && offtime<offmax){
        offtime++;
        lcd.print(offtime);
      }
      if(menu==4 && temp<tempmax){
        temp++;
        lcd.print(temp);
      }
    break;
    case KEY_DN:
      if(menu==1 && item>2){    // menu navigation
        item--;
        menuDisplay(1);
      }
      if(menu>=2 && menu<=4) ]cd.setCursor(3,1); // parameter value coords
      if(menu==2 && ontime>1){         // menu=2..4 - edit parameter
        ontime--;
        lcd.print(ontime);
      }
      if(menu==3 && offtime>1){
        offtime--;
        lcd.print(offtime);
      }
      if(menu==4 && temp>tempmin){
        temp--;
        lcd.print(temp);
      }
    break;
    case KEY_OK:
      switch(menu){
        case 0:             // setup mode
          menu=1;
          item=2;
          menuDisplay(2);
        break;
        case 1:             // select
          menu=item;
          menuDisplay(1);
        break;
        case 2:             // on
          storeONtime();
          menu=1;
          menuDisplay(2);
        break;
        case 3:             // off
          storeOFFtime();
          menu=1;
          menuDisplay(2);
        break;
        case 4:             // temp
          storeTEMP();
          menu=1;
          menuDisplay(2);
        break;
        case 5:             // return to main loop
          menu=0;
          menuDisplay(2);
        break;
      }
    break;
  }
}

void storeONtime(){         // storage routines
  if(EEPROM.read(0x00)!=ontime) EEPROM.write(0x00,ontime);
}
void storeOFFtime(){
  if(EEPROM.read(0x01)!=offtime) EEPROM.write(0x01,offtime);
}
void storeTEMP(){
  if(EEPROM.read(0x02)!=temp) EEPROM.write(0x02,temp);
}