Помогите с меню

sir_kimas
Offline
Зарегистрирован: 01.08.2016

Госпада! Помогите с меню.

Основной экран.

1 экран: установка нижнего давления
2 экран: установка верхнего давления
3 экран: установка часов
если кнопка не нажата "возвращаемся на основной экран"
/* адрес eeprom
  Давление
  EEPROM 0 Минимальное значение давления
  EEPROM 1 Максимальное значение давления
*/

// Подключаем библиотеки:
//*****************************************
//#include <EEPROM.h>                        // подключаем библиотеку для работы с EEPROM
#include <Wire.h>                            // подключаем библиотеку для работы с шиной I2C
#include "LCD_1602_RUS.h"                    // подключаем библиотеку для работы с LCD дисплеем с русским языком
//*****************************************

LCD_1602_RUS lcd(0x3F, 20, 4);               // объявляем  переменную для работы с LCD дисплеем
//*****************************************

int sensor = A1;                             // Пин датчика давления "аналоговый"
int dig_out;
int RelePin = 10;                            // Пин реле "насоса"
int ledPin_Rele = 11;                        // Пин светодиода "вклюсение насоса" автоматический режим
int ledPin_Error = 12;                       // Пин светодиода "авария насоса"
int ledPin_Rele_manual = 13;                 // Пин светодиода "вклюсение насоса" ручной режим
int buttonPin_manual = 2;                    // Пин кнопка "вклюсение насоса" ручной режим
int buttonPin_SET = 3;                       // Пин кнопка "SET"
int buttonPin_UP = 4;                        // Пин кнопка "UP"
int buttonPin_DOWN = 5;                      // Пин кнопка "DOWN"
int val = 0;

//*****************************************
void setup()
{
  pinMode(RelePin, OUTPUT);                  // устанавливает режим работы - выход
  pinMode(ledPin_Rele, OUTPUT);              // устанавливает режим работы - выход
  pinMode(ledPin_Error, OUTPUT);             // устанавливает режим работы - выход
  pinMode(ledPin_Rele_manual, OUTPUT);       // устанавливает режим работы - выход
  pinMode(buttonPin_manual, INPUT);          // устанавливает режим работы - вход
  pinMode(buttonPin_SET, INPUT);             // устанавливает режим работы - вход
  pinMode(buttonPin_UP, INPUT);              // устанавливает режим работы - вход
  pinMode(buttonPin_DOWN, INPUT);            // устанавливает режим работы - вход
  pinMode(sensor, INPUT);                    // устанавливает режим работы - выход
  {
    lcd.init();                              // инициируем LCD дисплей
    lcd.backlight();                         // включаем подсветку LCD дисплея
    //Serial.begin(9600);
  }
}
void loop()
{
  float dig_out = analogRead(sensor = A1);    // Считываем входное напряжение
  dig_out = dig_out * 5.0 / 1024.0;           // Преобразуем значение
  dig_out = 1.111 * dig_out - 0.555;

  if (dig_out < 0 )
  {
    ('-', false);
    dig_out *= 0;
  }
  {
    val = digitalRead(buttonPin_manual);       // нажата кнопка "вклюсение насоса" ручной режим
    digitalWrite(RelePin, val);                // включает реле
    digitalWrite(ledPin_Rele_manual, val);     // включаем светодиод
  }
  //******************************************
  //Основной экран.
  //Serial.println(dig_out);
  lcd.setCursor(1, 0);
  lcd.print(L"РЕЛЕ ДАВЛЕНИЯ  v.1");            // Выводим надпись
  lcd.setCursor(0, 2);
  lcd.print("MPa");                            // Выводим надпись
  lcd.setCursor(8, 2);
  lcd.print("MPa");                            // Выводим надпись
  lcd.setCursor(16, 2);
  lcd.print("MPa");                            // Выводим надпись
  lcd.setCursor(8, 3);
  lcd.print(dig_out);                          // Выводим давление

  delay(500);                                  // Время задержки
}
// 1 экран: установка нижнего давления
// 2 экран: установка верхнего давления
// 3 экран: установка часов
// если кнопка не нажата "возвращаемся на основной экран"

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

я не смогу. Мой стиль заставит вас переписать всю программу.

okta
Offline
Зарегистрирован: 10.01.2015

Не заставит. Ибо переписывать пока нечего.

Я бы первую строку ТС переформулировал: "Господи! Помоги мне с меню."

sir_kimas
Offline
Зарегистрирован: 01.08.2016

qwone пишет:

я не смогу. Мой стиль заставит вас переписать всю программу.

Я в программировании новичок. Не пинайте сильно. Может что и на крутил тут не то. Подскажите пожалуйста. Пытаюсь учится но без косяков никуда.

sir_kimas
Offline
Зарегистрирован: 01.08.2016

Ребята. подскажите кто что может. мозг опух и ничего не получается.

uni
uni аватар
Offline
Зарегистрирован: 24.09.2015

Схему покажите, нарисуйте как должен выглядеть интерфейс, укажите как должны выглядеть и изменяться значения на экране при нажатии кнопок. Как переходить между экранами, как переходить между элементами на экране.

Опишите своё видение подробно, тогда и мысли появлятся как реализовать. Удобное меню трудно в одном листинге уместить.

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

diger67
Offline
Зарегистрирован: 25.07.2015

Я делал так, создавал переменную в которой хранилас информация о состоянии страниц экрана. Один бит одина страница. При переходе со страници на строницу старый бит сбрасывался новый устанавливался. Это нужно было для работы с переменными используемыми при изменении их параметров. Далее мы при нажатии на любую кнопку навигации по меню или странице обращаемся только к тем переменным которые учавствуют в алгоритме страницы и естественно сбрасываем таймер бездействия если нажимается хоть одна кнопка. Если за установленное время ни одна кнопка не нажата, то переходим на главную страницу(выходим из меню). С радостью выложил бы алгоритм, но увы при восстановлении компа проек умер. а копия только в прошивке контроллера.

sir_kimas
Offline
Зарегистрирован: 01.08.2016

Примерно так. Может что проще предложите.

https://yadi.sk/d/SksKaSP_ymqSB

diger67
Offline
Зарегистрирован: 25.07.2015
#define_t start_menu 0b00000001
#define str_menu1 0b00000010
#define str_menu2 0b00000100
#define str_menu3 0b00001000

uint8_t status_menu = start_menu;
uint8_t N_str = 0;

...........................
void loop(void)
{
  void press_key_down(void)
  {
     N_str++;    
     {
         namber_str(N_str);
     }
     if(N_str > 3)
     {
        N_str = 3;
     }
​     if(status_menu == start_menu)
​     {
            namber_str(N_str)
     }
     if(status_menu == menu1)
     {
         //обрабатываем события menu1
     }
      if(staus_menu == menu2)
     {
        //обрабатываем события menu2
     }
     if(staus_menu == menu3)
     {
        //обрабатываем события menu3
     }
      time = false; 
  }

  void press_key_up(void)
  {
     N_str--;    
     {
         namber_str(N_str)
     }
     if(N_str < 1);
     {
        N_str = 1;
     }
     if(status_menu == start_menu)
​     {
            namber_str(N_str)
     }
     if(status_menu == menu1)
     {
         //обрабатываем события menu1
     }
      if(staus_menu == menu2)
     {
        //обрабатываем события menu2
     }
     if(staus_menu == menu3)
     {
        //обрабатываем события menu3
     }
     time = false; 
  }

  if(time == true)
  {
       start_menu();
  }
}
//------------------------------------------------------------
void namber_str(uint8_t n_str)
 {
     if(n_str == 1)
     {
         menu1();
     }
     else if(n_str  == 2)
     {
         menu2();
     }
     else if(n_str  == 3)
     {
         menu3();
     }
  }
//---------------------------------------------------------
void start_menu)
{
  status_menu = 0b00000000;
   //выводим на LCD start_menu
  status_menu = 0b00000010;
}

void menu1()
{
  status_menu = 0b00000000;
   //выводим на LCD menu1
  status_menu = 0b00000010;
}
//- - - - - - - - - - -
//- - - - - - - - - - -
void menu3()
{
  status_menu = 0b00000000;
   //выводим на LCD menu3
  status_menu = 0b00001000;
}

Вот примерно как то так, может где и ошибся, должно бегать по меню и возвращаться в главное если вышло время. Сдесь не реализован таймер сброса в основное меню. Надо дописать ео обрабботчик.

sir_kimas
Offline
Зарегистрирован: 01.08.2016

diger67 пишет:

#define_t start_menu 0b00000001
#define str_menu1 0b00000010
#define str_menu2 0b00000100
#define str_menu3 0b00001000

uint8_t status_menu = start_menu;
uint8_t N_str = 0;

...........................
void loop(void)
{
  void press_key_down(void)
  {
     N_str++;    
     {
         namber_str(N_str);
     }
     if(N_str > 3)
     {
        N_str = 3;
     }
​     if(status_menu == start_menu)
​     {
            namber_str(N_str)
     }
     if(status_menu == menu1)
     {
         //обрабатываем события menu1
     }
      if(staus_menu == menu2)
     {
        //обрабатываем события menu2
     }
     if(staus_menu == menu3)
     {
        //обрабатываем события menu3
     }
      time = false; 
  }

  void press_key_up(void)
  {
     N_str--;    
     {
         namber_str(N_str)
     }
     if(N_str < 1);
     {
        N_str = 1;
     }
     if(status_menu == start_menu)
​     {
            namber_str(N_str)
     }
     if(status_menu == menu1)
     {
         //обрабатываем события menu1
     }
      if(staus_menu == menu2)
     {
        //обрабатываем события menu2
     }
     if(staus_menu == menu3)
     {
        //обрабатываем события menu3
     }
     time = false; 
  }

  if(time == true)
  {
       start_menu();
  }
}
//------------------------------------------------------------
void namber_str(uint8_t n_str)
 {
     if(n_str == 1)
     {
         menu1();
     }
     else if(n_str  == 2)
     {
         menu2();
     }
     else if(n_str  == 3)
     {
         menu3();
     }
  }
//---------------------------------------------------------
void start_menu)
{
  status_menu = 0b00000000;
   //выводим на LCD start_menu
  status_menu = 0b00000010;
}

void menu1()
{
  status_menu = 0b00000000;
   //выводим на LCD menu1
  status_menu = 0b00000010;
}
//- - - - - - - - - - -
//- - - - - - - - - - -
void menu3()
{
  status_menu = 0b00000000;
   //выводим на LCD menu3
  status_menu = 0b00001000;
}

Вот примерно как то так, может где и ошибся, должно бегать по меню и возвращаться в главное если вышло время. Сдесь не реализован таймер сброса в основное меню. Надо дописать ео обрабботчик.

За пример спасибо. Буду пробовать.

diger67
Offline
Зарегистрирован: 25.07.2015

Да, упустил, в функции сброса в старт меню

if(time == true)
{
       start_menu();
       status_menu = start_menu;
       N_str = 0;
}

Это что бы при возврате мы начинали работу с меню как бы с начала. На мой взгляд использовать "симафоры" для определения состояния системы самый оптимальный вариант. И я надеюсь вы понимаете что в лучшем случае вы увидите только свои меню и работать с ними не сможите. Надо писать обработчики кнопок для каждой функции в конкретном меню. И здесь нету подавления дребезга.

Baks
Baks аватар
Offline
Зарегистрирован: 11.01.2016

както тоже искал меню, но пока обошолся а недавно попалась библиотека , вроди все понятно но не пробовал

https://github.com/jonblack/arduino-menusystem

можите попробовать и потом расскажите чем закончится, может и у меня дойдут руки до меню

diger67
Offline
Зарегистрирован: 25.07.2015

Вобщем просмотрел предложенный мной код. Писать на лету без дебага ж....па. Работать будет но неправильно. Так должно работать.

void press_key_down(void)
  {
     N_str++;    
     {
         namber_str(N_str);
     }
     if(N_str > 4)
     {
        N_str =4;
     }
     if(status_menu == start_menu && N_str = 1)
     {
            namber_str(N_str)
     }
     if(status_menu == menu1 && N_str = 2)
     {
         namber_str(N_str)
​        //обрабатываем события menu1
     }
      if(staus_menu == menu2 && N_str = 3)
     {
        namber_str(N_str)
        //обрабатываем события menu2
     }
     if(staus_menu == menu3 && N_str = 4)
     {
        namber_str(N_str)
        //обрабатываем события menu2
     }
     time = false; 
  }

void press_key_up(void)
  {
     N_str--;    
     {
         namber_str(N_str)
     }
     if(N_str < 2);
     {
        N_str = 2;
     }
     if(staus_menu == menu3 && N_str = 3)
     {
        namber_str(N_str)
        //обрабатываем события menu2
     }

     if(staus_menu == menu2 && N_str = 2)
     {
        namber_str(N_str) 
        //обрабатываем события menu1
     }
     time = false; 
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

А это так для раздумия

void viev0() { // показать 0 экран
}
void viev1() { // показать 1 экран
}
void do_nothing() { // ничего не делать
}
struct str {  // создание общей стуктуры экрана
  void (*viev)(void); // показать экран
  void (*do_left)(void); // сделать если нажата кнопка влево
  void (*do_right)(void);// сделать если нажата кнопка вправо
};
const str str_a[] = {
// показ   влево     вправо
  viev0, do_nothing, do_nothing, // 0 экран
  viev1, do_nothing, do_nothing  // 1 экран
};

void setup() {
  str_a[0].viev();
  str_a[0].do_left();
  str_a[0].do_right();

}

void loop() {

}

 

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

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

/* адрес eeprom
  Давление
  EEPROM 0 Минимальное значение давления
  EEPROM 1 Максимальное значение давления
*/

// Подключаем библиотеки:
//*****************************************
//#include <EEPROM.h>                        // подключаем библиотеку для работы с EEPROM
#include <Wire.h>                            // подключаем библиотеку для работы с шиной I2C
#include "LCD_1602_RUS.h"                    // подключаем библиотеку для работы с LCD дисплеем с русским языком
//*****************************************

LCD_1602_RUS lcd(0x3F, 20, 4);               // объявляем  переменную для работы с LCD дисплеем
//*****************************************

#define sensor 1                // Пин датчика давления "аналоговый"
#define RelePin 10            // Пин реле "насоса"
#define ledPin_Rele 11        // Пин светодиода "вклюсение насоса" автоматический режим
#define ledPin_Error 12       // Пин светодиода "авария насоса"
#define ledPin_Rele_manual 13 // Пин светодиода "вклюсение насоса" ручной режим
#define buttonPin_manual 2    // Пин кнопка "вклюсение насоса" ручной режим
#define buttonPin_SET 3       // Пин кнопка "SET"
bool f_SET;
#define buttonPin_UP 4        // Пин кнопка "UP"
bool f_UP;
#define buttonPin_DOWN 5      // Пин кнопка "DOWN"
bool f_DOWN;
int val = 0;
float dig_out;
int ekran = 0; //перем. ЭКРАНА
float macs_dig; //Перем. МАКСИМУМА
float min_dig; //Перем. Минимума
unsigned long period;

//*****************************************
void setup()
{
  pinMode(RelePin, OUTPUT);                  // устанавливает режим работы - выход
  pinMode(ledPin_Rele, OUTPUT);              // устанавливает режим работы - выход
  pinMode(ledPin_Error, OUTPUT);             // устанавливает режим работы - выход
  pinMode(ledPin_Rele_manual, OUTPUT);       // устанавливает режим работы - выход
  pinMode(buttonPin_manual, INPUT);          // устанавливает режим работы - вход
  pinMode(buttonPin_SET, INPUT);             // устанавливает режим работы - вход
  pinMode(buttonPin_UP, INPUT);              // устанавливает режим работы - вход
  pinMode(buttonPin_DOWN, INPUT);            // устанавливает режим работы - вход
  //pinMode(sensor, INPUT);                    // устанавливает режим работы - вход
  
   lcd.init();                              // инициируем LCD дисплей
   lcd.backlight();                         // включаем подсветку LCD дисплея
    //Serial.begin(9600);
  
}
void loop()
{
  dig_out = analogRead(sensor);    // Считываем входное напряжение
  dig_out = dig_out * 5.0 / 1024.0;           // Преобразуем значение
  dig_out = 1.111 * dig_out - 0.555;
  if (dig_out < 0 )
  {
    ('-', false);
    dig_out *= 0;
  }
  val = digitalRead(buttonPin_manual);       // нажата кнопка "вклюсение насоса" ручной режим
  digitalWrite(RelePin, val);                // включает реле
  digitalWrite(ledPin_Rele_manual, val);     // включаем светодиод

  //Кнопкой SET переключаем экраны
  if (digitalRead(buttonPin_SET) == HIGH && f_SET == 0) {
    period = millis();
    ekran++;
    if (ekran > 3)ekran = 0;
    f_SET = 1;
  }
  if (f_SET == 1 && digitalRead(buttonPin_SET) == LOW)f_SET = 0;

  //Кнопкой UP увеличуем установки в зависимости от екрана
  if (digitalRead(buttonPin_UP) == HIGH && f_UP == 0) {
    period = millis();
    if (ekran == 1)min_dig++;
    if (ekran == 2)macs_dig++;
    f_UP = 1;
  }
  if (f_UP == 1 && digitalRead(buttonPin_UP == LOW))f_UP = 0;

  //Кнопкой DOWN уменьшаем установки в зависимости от екрана
  if (digitalRead(buttonPin_DOWN) == HIGH && f_DOWN == 0) {
    period = millis();
    if (ekran == 1)min_dig--;
    if (ekran == 2)macs_dig--;
    f_DOWN = 1;
  }
  if (f_DOWN == 1 && digitalRead(buttonPin_DOWN == LOW))f_DOWN = 0;

  //Прошло 3 секунды без нажатий - включаем основной екран
  if (millis() - period >= 3000)ekran = 0;



  //******************************************
  //Основной экран.
  //Serial.println(dig_out);

  if (ekran == 0) {
    lcd.setCursor(1, 0);
    lcd.print("РЕЛЕ ДАВЛЕНИЯ  v.1");            // Выводим надпись
    lcd.setCursor(0, 2);
    lcd.print("MPa");                            // Выводим надпись
    lcd.setCursor(8, 2);
    lcd.print("MPa");                            // Выводим надпись
    lcd.setCursor(16, 2);
    lcd.print("MPa");                            // Выводим надпись
    lcd.setCursor(8, 3);
    lcd.print(dig_out);                          // Выводим давление
  }
  //Экран установки минимума
  if (ekran == 1) {
    lcd.setCursor(1, 0);
    lcd.print(min_dig);            // Выводим надпись
    lcd.print(" Minimal");
  }
  //Экран установки максимума
  if (ekran == 2) {
    lcd.setCursor(1, 0);
    lcd.print(macs_dig);            // Выводим надпись
    lcd.print(" Maxsim");
  }

}
// 1 экран: установка нижнего давления
// 2 экран: установка верхнего давления
// 3 экран: установка часов
// если кнопка не нажата "возвращаемся на основной экран"

 

sir_kimas
Offline
Зарегистрирован: 01.08.2016

Спасибо огромное за примеры. Буду учится и разбираться! 

diger67
Offline
Зарегистрирован: 25.07.2015

qwone, человеку надо сначала определиться и понять процесс с помощью элементарных функций. А уж потом все это можно вынести в структуры. Для человека начинающего изучать С бывает непросто понять принцип передачи информации с помощью указателей на переменные.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

diger67 пишет:

qwone, человеку надо сначала определиться и понять процесс с помощью элементарных функций. А уж потом все это можно вынести в структуры. Для человека начинающего изучать С бывает непросто понять принцип передачи информации с помощью указателей на переменные.

Но меню делается 2 способами. Или через switch...case  или структурой. Вариант if даже не рассматриваю.

Вот у в меню есть номера экранов. А вот в каждом экране ответ на нажатие кнопок будет различным. То есть если кнопок 3 (может 4 или 5). Экранов 5  . Вот и набирается 15-25 функций ообработчиков ответа. Ну да половину можно игнорировать. (подключить функцию ничего не делать). А вот фунции можно делать элементарными. Я просто показал заготовку. А пользоваться или нет пусть ТС решает.

diger67
Offline
Зарегистрирован: 25.07.2015

Согласен что так правильней и читабельней. Этот вариант работает для кнопок безотказно. Немного сложнее когда делается меню на tft с тачскрином. Тут активная область может находится в любой части экрана и использование структуры реализовать сложнее. Мне в последних проектах чаще приходилось решать именно такие вопросы. Что касается функций заглушек, то да, наверное их использование экономичней чем обработчик количества кнопок в зависимости от пункта меню.