Помогите с меню
- Войдите на сайт для отправки комментариев
Пнд, 14/11/2016 - 21:52
Госпада! Помогите с меню.
Основной экран.
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 экран: установка часов
// если кнопка не нажата "возвращаемся на основной экран"
я не смогу. Мой стиль заставит вас переписать всю программу.
Не заставит. Ибо переписывать пока нечего.
Я бы первую строку ТС переформулировал: "Господи! Помоги мне с меню."
я не смогу. Мой стиль заставит вас переписать всю программу.
Я в программировании новичок. Не пинайте сильно. Может что и на крутил тут не то. Подскажите пожалуйста. Пытаюсь учится но без косяков никуда.
Ребята. подскажите кто что может. мозг опух и ничего не получается.
Схему покажите, нарисуйте как должен выглядеть интерфейс, укажите как должны выглядеть и изменяться значения на экране при нажатии кнопок. Как переходить между экранами, как переходить между элементами на экране.
Опишите своё видение подробно, тогда и мысли появлятся как реализовать. Удобное меню трудно в одном листинге уместить.
Если всё более менее подробно опишите, чтобы не было неоднозначностей в понимании, я покажу как это можно было бы реализовать.
Я делал так, создавал переменную в которой хранилас информация о состоянии страниц экрана. Один бит одина страница. При переходе со страници на строницу старый бит сбрасывался новый устанавливался. Это нужно было для работы с переменными используемыми при изменении их параметров. Далее мы при нажатии на любую кнопку навигации по меню или странице обращаемся только к тем переменным которые учавствуют в алгоритме страницы и естественно сбрасываем таймер бездействия если нажимается хоть одна кнопка. Если за установленное время ни одна кнопка не нажата, то переходим на главную страницу(выходим из меню). С радостью выложил бы алгоритм, но увы при восстановлении компа проек умер. а копия только в прошивке контроллера.
Примерно так. Может что проще предложите.
https://yadi.sk/d/SksKaSP_ymqSB
#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; }Вот примерно как то так, может где и ошибся, должно бегать по меню и возвращаться в главное если вышло время. Сдесь не реализован таймер сброса в основное меню. Надо дописать ео обрабботчик.
#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; }Вот примерно как то так, может где и ошибся, должно бегать по меню и возвращаться в главное если вышло время. Сдесь не реализован таймер сброса в основное меню. Надо дописать ео обрабботчик.
За пример спасибо. Буду пробовать.
Да, упустил, в функции сброса в старт меню
if(time == true) { start_menu(); status_menu = start_menu; N_str = 0; }Это что бы при возврате мы начинали работу с меню как бы с начала. На мой взгляд использовать "симафоры" для определения состояния системы самый оптимальный вариант. И я надеюсь вы понимаете что в лучшем случае вы увидите только свои меню и работать с ними не сможите. Надо писать обработчики кнопок для каждой функции в конкретном меню. И здесь нету подавления дребезга.
както тоже искал меню, но пока обошолся а недавно попалась библиотека , вроди все понятно но не пробовал
https://github.com/jonblack/arduino-menusystem
можите попробовать и потом расскажите чем закончится, может и у меня дойдут руки до меню
Вобщем просмотрел предложенный мной код. Писать на лету без дебага ж....па. Работать будет но неправильно. Так должно работать.
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; }А это так для раздумия
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() { }Ну раз такое дело то и я попробую посоветовать. Посмотрите и мой вариант Вашего меню. Ваш код я старался не тогать чтобы было понятней
/* адрес 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 экран: установка часов // если кнопка не нажата "возвращаемся на основной экран"Спасибо огромное за примеры. Буду учится и разбираться!
qwone, человеку надо сначала определиться и понять процесс с помощью элементарных функций. А уж потом все это можно вынести в структуры. Для человека начинающего изучать С бывает непросто понять принцип передачи информации с помощью указателей на переменные.
qwone, человеку надо сначала определиться и понять процесс с помощью элементарных функций. А уж потом все это можно вынести в структуры. Для человека начинающего изучать С бывает непросто понять принцип передачи информации с помощью указателей на переменные.
Но меню делается 2 способами. Или через switch...case или структурой. Вариант if даже не рассматриваю.
Вот у в меню есть номера экранов. А вот в каждом экране ответ на нажатие кнопок будет различным. То есть если кнопок 3 (может 4 или 5). Экранов 5 . Вот и набирается 15-25 функций ообработчиков ответа. Ну да половину можно игнорировать. (подключить функцию ничего не делать). А вот фунции можно делать элементарными. Я просто показал заготовку. А пользоваться или нет пусть ТС решает.
Согласен что так правильней и читабельней. Этот вариант работает для кнопок безотказно. Немного сложнее когда делается меню на tft с тачскрином. Тут активная область может находится в любой части экрана и использование структуры реализовать сложнее. Мне в последних проектах чаще приходилось решать именно такие вопросы. Что касается функций заглушек, то да, наверное их использование экономичней чем обработчик количества кнопок в зависимости от пункта меню.