Witam
Tym razem temat całkiem poważny. Wielu z nas, łącznie ze mną ma lub miało problemy z MenuBackend.
Być może samo zrozumienie podstaw nie jest problemem (odsyłam tutaj do artykułu:
http://majsterkowo.pl/forum/menubackend-...t1549.html
gdzie starałem się wszystko opisać). Jednak samo stosowanie tego "wynalazku" jest już wyższą szkołą jazdy niestety:-)
Myślę, że jednak warto poświęcić trochę czasu na zrozumienie o co w tym wszystkim biega.
Czym jest owo MenuBackend? To biblioteka (zamieszczam w załączniku), która umożliwia w łatwy sposób tworzyć nawet bardzo rozbudowane MENU dla naszej aplikacji.
Często bowiem borykamy się z dylematem: Mamy gotowy program, który coś tam robi, coś tam mierzy, coś tam pokazuje... ale przydałoby się aby dodać do tego jakieś sensowne MENU, tak aby móc w każdej chwili na przykład zmienić temperaturę załączenia grzałki, czas załączenia timera, załączyć alarm i nie wiem co tam jeszcze.
Słowem potrzebna jest jakaś interakcja. Mamy na przykład nowiusieńką klawiaturkę, joystick, manipulator czy po prostu kilka microswitch-ów i chcemy wykorzystać ich "potencjał" :-)
No i właśnie teraz zaczynają się schody. Kurcze jeśli już coś działa, to albo nie działa tak, jak sobie wyobrażaliśmy albo sam program nie robi tego z naszym Menu, co robił poprawnie bez niego, prawda?
MenuBackend od czasu pierwszego wydania tej biblioteki przeżyło kilka poprawek i w chwili obecnej jest już całkiem fajne. Niestety nie mam wiedzy jak zachowuje się z różnymi wersjami IDE Arduino, miejmy jednak nadzieję, że nie ma niespodzianek (czego nie można powiedzieć o LiquidCrystal_I2C).
Dobra, do rzeczy. Nie wiem czy dzisiaj ukończę ten post. W każdym razie będę tu dodawał kolejne fragmenty, jak by co :-)
Jest konkretny projekt do ogarnięcia - sterowanie domowym zbiorem akwarium,( nie wiem czy dopełniacz liczby mnogiej to "akwariów"), w którym nasz kolega ma obsługę:
- kilku akwariów (ups. gramatyka)
- sterowanie temperaturą
- sterowanie oświetleniem
- sterowanie 3 wentylatorami (pompkami chyba... w sumie nie wiem o co biega, nazwijmy to wentylatory)
- sterowanie wyłącznikiem czasowym o nieznanym bliżej przeznaczeniu.
Założenia projektu - za pomocą 4 przycisków i Menu należy mieć możliwość:
1) ustawienia w dowolnym momencie:
- temperatury załączenia grzałek
- temperatury wyłączenia grzałek
- czasu załączenia oświetlenia
- czasu wyłączenia oświetlenia
- załączenia/wyłączenia każdego z 3 wentylatorów
- ustawiania czasu załączenia i wyłączenia Timera
2) To wszystko musi być niezależne od pracy głównego programu (odczyt temperatur, odmierzanie czasu RTC, sterowanie alarmami przekroczeń dopuszczalnych temperatur, sterowanie wentylatorów... i nie wiem co jeszcze.
Jak widać problem nie jest wcale trywialny. Jak zatem metodycznie podejść do tego zagadnienia?
Moim skromnym zdaniem trzeba je podzielić na 2 funkcjonalne bloki - program główny i obsługę menu.
Jeśli w dużym uproszczeniu uda nam się to zrobić w funkcji loop() to mamy pełen sukces :-)
Zacznijmy od menu:
Każdą linię opatrzyłem stosownym komentarzem, więc powinno być "z górki" :-)
linia:
... odpowiada za utworzenie obiektu klasy MenuBackend o nazwie menu.
Argumentami tego konstruktora (bo tak właśnie nazywa się funkcja która tworzy obiekt każdej klasy), są 2 funkcje, które "potrafią" przekazać informację do samego MENU jaką opcję wybrano i odpowiedzieć co było aktywne przed i po tym wyborze. Czyli w prostych, żołnierskich słowach wiemy gdzie w galęzi tego menu aktualnie jesteśmy - mamy tzw. mapkę nawigacji po menu.
Biblioteka MenuBackend zasadniczo składa się z 2 klas: MenuBackend i MenuItem. Pierwsza to mama dla drugiej.
Jednak związek mama-córka nie jest tutaj najtrafniejszy, ściśle rzecz ujmując raczej obie te klasy są zaprzyjaźnione, bo de facto tak jest właśnie :-) O dobrodziejstwach tej przyjaźni dowiesz się najwięcej i najwięcej zrozumiesz - jeśli sięgniesz po biblię pana Grębosza - Symfonię C++. Sorry ale musiałem zareklamować tę pozycję, bo jest tego warta :-)
Pierwsza klasa opisuje zasadnicze menu, sposób jego organizacji i dostęp do składników i funkcji obsługi. Druga opisuje poszczególne opcje tego menu ( stąd MenuItem właśnie).
W bibliotece MenuBackend jest opisany sposób dodawania tych opcji oraz sposób tworzenia samego menu. Odpowiada za to funkcja menuSetup:
... i tu także jest sporo objaśnień.
Nasze menu składa się z 4 opcji głównych (parent) i szeregu opcji (children).
Jeśli opcje są równorzędne to dodajemy je w poziome za pomocą addRight, addLeft.
Jeśli dodajemy "dziecko" to za pomocą zwykłego add ( jakby w pionie).
W bibliotece MenuBackend jest jeszcze kilka innych opcji, ale o tym potem.
W każdym razie załączony przykład ilustruje jak się takie menu tworzy.
Prawdę mówiąc jest jeszcze sporo do omówienia, więc najlepiej chyba będzie jak zamieszczę cały gotowy przykładowy kod, a jutro opiszę dokładnie o co tam biega.
Do testów wykorzystuję oryginalną klawiaturkę z modułu LCD Keypad Shield (5 przycisków na A0). Mam nadzieję, że nie będzie problemu z ogarnięciem o co chodzi.
Poniżej kod:
... a biblioteka w załączniku
Na końcu, za loop-em umieściłem funkcje do obsługi ustawień temperatury i czasu.
Z założenia każda z nich czyta stan klawiatury i dopóki nie wciśnięto OK (tutaj wartość =4), dopóty reagujemy na zmiany klawiszy UP-DOWN (prawo-lewo, czy Plus-Minus... jak kto woli).
Do pełni szczęścia brakuje jeszcze zapisu wartości do EEPROM-a no i całego programu głównego, ale to już zadanie dla autora projektu :-)
Trzeba jeszcze zamienić Seriale na obsługę wyświetlacza LCD - a tu może być pomocny mój poprzedni post:
Sandbox 4 :-)
Pozdrawiam
Tym razem temat całkiem poważny. Wielu z nas, łącznie ze mną ma lub miało problemy z MenuBackend.
Być może samo zrozumienie podstaw nie jest problemem (odsyłam tutaj do artykułu:
http://majsterkowo.pl/forum/menubackend-...t1549.html
gdzie starałem się wszystko opisać). Jednak samo stosowanie tego "wynalazku" jest już wyższą szkołą jazdy niestety:-)
Myślę, że jednak warto poświęcić trochę czasu na zrozumienie o co w tym wszystkim biega.
Czym jest owo MenuBackend? To biblioteka (zamieszczam w załączniku), która umożliwia w łatwy sposób tworzyć nawet bardzo rozbudowane MENU dla naszej aplikacji.
Często bowiem borykamy się z dylematem: Mamy gotowy program, który coś tam robi, coś tam mierzy, coś tam pokazuje... ale przydałoby się aby dodać do tego jakieś sensowne MENU, tak aby móc w każdej chwili na przykład zmienić temperaturę załączenia grzałki, czas załączenia timera, załączyć alarm i nie wiem co tam jeszcze.
Słowem potrzebna jest jakaś interakcja. Mamy na przykład nowiusieńką klawiaturkę, joystick, manipulator czy po prostu kilka microswitch-ów i chcemy wykorzystać ich "potencjał" :-)
No i właśnie teraz zaczynają się schody. Kurcze jeśli już coś działa, to albo nie działa tak, jak sobie wyobrażaliśmy albo sam program nie robi tego z naszym Menu, co robił poprawnie bez niego, prawda?
MenuBackend od czasu pierwszego wydania tej biblioteki przeżyło kilka poprawek i w chwili obecnej jest już całkiem fajne. Niestety nie mam wiedzy jak zachowuje się z różnymi wersjami IDE Arduino, miejmy jednak nadzieję, że nie ma niespodzianek (czego nie można powiedzieć o LiquidCrystal_I2C).
Dobra, do rzeczy. Nie wiem czy dzisiaj ukończę ten post. W każdym razie będę tu dodawał kolejne fragmenty, jak by co :-)
Jest konkretny projekt do ogarnięcia - sterowanie domowym zbiorem akwarium,( nie wiem czy dopełniacz liczby mnogiej to "akwariów"), w którym nasz kolega ma obsługę:
- kilku akwariów (ups. gramatyka)
- sterowanie temperaturą
- sterowanie oświetleniem
- sterowanie 3 wentylatorami (pompkami chyba... w sumie nie wiem o co biega, nazwijmy to wentylatory)
- sterowanie wyłącznikiem czasowym o nieznanym bliżej przeznaczeniu.
Założenia projektu - za pomocą 4 przycisków i Menu należy mieć możliwość:
1) ustawienia w dowolnym momencie:
- temperatury załączenia grzałek
- temperatury wyłączenia grzałek
- czasu załączenia oświetlenia
- czasu wyłączenia oświetlenia
- załączenia/wyłączenia każdego z 3 wentylatorów
- ustawiania czasu załączenia i wyłączenia Timera
2) To wszystko musi być niezależne od pracy głównego programu (odczyt temperatur, odmierzanie czasu RTC, sterowanie alarmami przekroczeń dopuszczalnych temperatur, sterowanie wentylatorów... i nie wiem co jeszcze.
Jak widać problem nie jest wcale trywialny. Jak zatem metodycznie podejść do tego zagadnienia?
Moim skromnym zdaniem trzeba je podzielić na 2 funkcjonalne bloki - program główny i obsługę menu.
Jeśli w dużym uproszczeniu uda nam się to zrobić w funkcji loop() to mamy pełen sukces :-)
Zacznijmy od menu:
Kod:
// ---------------------------------------------------------------------------------------------------
/* Schemat menu:
root
Temperatura Oswietlenie Wentylatory Timer
T_zal Czas_zal Wentylator 1 Timer_zal.
T_wyl Czas_wyl Wentylator 2 Timer_wyl.
Wentylator 3
*/
// ---- definicja wszystkich opcji menu -------------------------------------------------------------
MenuBackend menu = MenuBackend(co_wybrano, co_zmieniono); // tworzymy obiekt klasy MenuBackend o nazwie menu
// co_wybrano i co zmieniono to funkcje menu, ktore służą do jego obsługi
// poniżej definicja wszystkich opcji menu:
MenuItem miTemperatura = MenuItem("Temperatura"); // obiekt klasy MenuItem o nazwie miTemperatura
MenuItem miT_zal = MenuItem("T zal."); // itd. dla każdej opcji tworzymy instancję (egzemplarz)
MenuItem miT_wyl = MenuItem("T wyl."); // klasy MenuItem
MenuItem miOswietlenie = MenuItem("Oswietlenie");
MenuItem miCzas_zal = MenuItem("Czas_zal");
MenuItem miCzas_wyl = MenuItem("Czas_wyl");
MenuItem miWentylatory = MenuItem("Wentylatory");
MenuItem miW1 = MenuItem("Wentylator 1");
MenuItem miW2 = MenuItem("Wentylator 2");
MenuItem miW3 = MenuItem("Wentylator 3");
MenuItem miTimer = MenuItem("Timer");
MenuItem miTimer_ON = MenuItem("Timer_ON");
MenuItem miTimer_OFF = MenuItem("Timer_OFF"); // koniec, to już wszystkie przykładowe opcje
linia:
Kod:
MenuBackend menu = MenuBackend(co_wybrano, co_zmieniono);
Argumentami tego konstruktora (bo tak właśnie nazywa się funkcja która tworzy obiekt każdej klasy), są 2 funkcje, które "potrafią" przekazać informację do samego MENU jaką opcję wybrano i odpowiedzieć co było aktywne przed i po tym wyborze. Czyli w prostych, żołnierskich słowach wiemy gdzie w galęzi tego menu aktualnie jesteśmy - mamy tzw. mapkę nawigacji po menu.
Biblioteka MenuBackend zasadniczo składa się z 2 klas: MenuBackend i MenuItem. Pierwsza to mama dla drugiej.
Jednak związek mama-córka nie jest tutaj najtrafniejszy, ściśle rzecz ujmując raczej obie te klasy są zaprzyjaźnione, bo de facto tak jest właśnie :-) O dobrodziejstwach tej przyjaźni dowiesz się najwięcej i najwięcej zrozumiesz - jeśli sięgniesz po biblię pana Grębosza - Symfonię C++. Sorry ale musiałem zareklamować tę pozycję, bo jest tego warta :-)
Pierwsza klasa opisuje zasadnicze menu, sposób jego organizacji i dostęp do składników i funkcji obsługi. Druga opisuje poszczególne opcje tego menu ( stąd MenuItem właśnie).
W bibliotece MenuBackend jest opisany sposób dodawania tych opcji oraz sposób tworzenia samego menu. Odpowiada za to funkcja menuSetup:
Kod:
void menuSetup() // konfiguracja menu (położeń wszystkich opcji)
{
menu.getRoot().add(miOswietlenie); // ustalam rodzica dla opcji Oświetlenie
menu.getRoot().add(miWentylatory); // ustalam rodzica dla opcji Wentylatory
menu.getRoot().add(miTimer); // ustalam rodzica dla opcji Timer
menu.getRoot().add(miTemperatura); // ustalam rodzica dla opcji Temperatura
// bo chcę, aby po wciśnięciu klawisza UP wyjść z MENU (czyli do roota - korzenia)
miTemperatura.add(miT_zal).add(miT_wyl); // Temperatura ma 2 opcje, więc je dodaję (funkcja add)
miTemperatura.addRight(miOswietlenie); // na prawo od Temperatura jest Oświetlenie (funkcja addRight)
miOswietlenie.add(miCzas_zal).add(miCzas_wyl); // Oświetlenie ma 2 opcje, więc je dodaję (funkcja add)
miOswietlenie.addRight(miWentylatory); // na prawo od Oświetlenie są Wentylatory (funkcja addRight)
miWentylatory.add(miW1).add(miW2).add(miW3); // dodaję 3 kolejne opcje dla Wentylatorów (po kolei)
miWentylatory.addRight(miTimer); // na prawo od Wentylatory jest Timer
miTimer.add(miTimer_ON).add(miTimer_OFF); // Timer ma 2 opcje, więc je dodaję
miTimer.addRight(miTemperatura); // zamykam pętlę aby przejść do Temperatura :-)
}
... i tu także jest sporo objaśnień.
Nasze menu składa się z 4 opcji głównych (parent) i szeregu opcji (children).
Jeśli opcje są równorzędne to dodajemy je w poziome za pomocą addRight, addLeft.
Jeśli dodajemy "dziecko" to za pomocą zwykłego add ( jakby w pionie).
W bibliotece MenuBackend jest jeszcze kilka innych opcji, ale o tym potem.
W każdym razie załączony przykład ilustruje jak się takie menu tworzy.
Prawdę mówiąc jest jeszcze sporo do omówienia, więc najlepiej chyba będzie jak zamieszczę cały gotowy przykładowy kod, a jutro opiszę dokładnie o co tam biega.
Do testów wykorzystuję oryginalną klawiaturkę z modułu LCD Keypad Shield (5 przycisków na A0). Mam nadzieję, że nie będzie problemu z ogarnięciem o co chodzi.
Poniżej kod:
Kod:
#include <MenuBackend.h> // niezbędna biblioteka MenuBackend
// --- zmienne programu -----------------------------------------------------------------------------
volatile int start=1; // zmienna odpowiedzialna za przełączanie: program -> start=1, menu -> start=0
float Tz=20; // przykładowa temperatura zalączenia grzałki
float Tw=30; // przykładowa temperatura wyłączenia grzałki
int Gz=7; // przykładowa godzina załączenia oświetlenia
int Gw=10; // przykładowa godzina wyłączenia oświetlenia
int Mz=20; // przykładowa minuta załączenia oświetlenia
int Mw=40; // przykładowa minuta wyłączenia oświetlenia
int GMz=Gz*60+Mz; // czas załączenia oświetlenia GMz=Gz*60+Mz
int GMw=Gw*60+Mw; // czas wyłączenia oświetlenia GMw=Gw*60+Mw
int TGz=18; // przykładowa godzina zalączenia timera
int TGw=22; // przykładowa godzina wyłączenia timera
int TMz=20; // przykładowa minuta zalączenia timera
int TMw=40; // przykładowa minuta wyłączenia timera
int TGMz=TGz*60+TMz; // czas załączenia timera TGMz=TGz*60+TMz
int TGMw=TGw*60+TMw; // czas wyłączenia timera TGMw=TGw*60+TMw
int stW1=0; // stan wentylatora 1
int stW2=0; // stan wentylatora 2
int stW3=0; // stan wentylatora 3
// ---------------------------------------------------------------------------------------------------
/* Schemat menu:
root
Temperatura Oswietlenie Wentylatory Timer
T_zal Czas_zal Wentylator 1 Timer_zal.
T_wyl Czas_wyl Wentylator 2 Timer_wyl.
Wentylator 3
*/
// ---- definicja wszystkich opcji menu -------------------------------------------------------------
MenuBackend menu = MenuBackend(co_wybrano, co_zmieniono); // tworzymy obiekt klasy MenuBackend o nazwie menu
// co_wybrano i co zmieniono to funkcje menu, ktore służą do jego obsługi
// poniżej definicja wszystkich opcji menu:
MenuItem miTemperatura = MenuItem("Temperatura"); // obiekt klasy MenuItem o nazwie miTemperatura
MenuItem miT_zal = MenuItem("T zal."); // itd. dla każdej opcji tworzymy instancję (egzemplarz)
MenuItem miT_wyl = MenuItem("T wyl."); // klasy MenuItem
MenuItem miOswietlenie = MenuItem("Oswietlenie");
MenuItem miCzas_zal = MenuItem("Czas_zal");
MenuItem miCzas_wyl = MenuItem("Czas_wyl");
MenuItem miWentylatory = MenuItem("Wentylatory");
MenuItem miW1 = MenuItem("Wentylator 1");
MenuItem miW2 = MenuItem("Wentylator 2");
MenuItem miW3 = MenuItem("Wentylator 3");
MenuItem miTimer = MenuItem("Timer");
MenuItem miTimer_ON = MenuItem("Timer_ON");
MenuItem miTimer_OFF = MenuItem("Timer_OFF"); // koniec, to już wszystkie przykładowe opcje
// ---- funkcje programu -----------------------------------------------------------------------------
void menuSetup() // konfiguracja menu (położeń wszystkich opcji)
{
menu.getRoot().add(miOswietlenie); // ustalam rodzica dla opcji Oświetlenie
menu.getRoot().add(miWentylatory); // ustalam rodzica dla opcji Wentylatory
menu.getRoot().add(miTimer); // ustalam rodzica dla opcji Timer
menu.getRoot().add(miTemperatura); // ustalam rodzica dla opcji Temperatura
// bo chcę, aby po wciśnięciu klawisza UP wyjść z MENU (czyli do roota - korzenia)
miTemperatura.add(miT_zal).add(miT_wyl); // Temperatura ma 2 opcje, więc je dodaję (funkcja add)
miTemperatura.addRight(miOswietlenie); // na prawo od Temperatura jest Oświetlenie (funkcja addRight)
miOswietlenie.add(miCzas_zal).add(miCzas_wyl); // Oświetlenie ma 2 opcje, więc je dodaję (funkcja add)
miOswietlenie.addRight(miWentylatory); // na prawo od Oświetlenie są Wentylatory (funkcja addRight)
miWentylatory.add(miW1).add(miW2).add(miW3); // dodaję 3 kolejne opcje dla Wentylatorów (po kolei)
miWentylatory.addRight(miTimer); // na prawo od Wentylatory jest Timer
miTimer.add(miTimer_ON).add(miTimer_OFF); // Timer ma 2 opcje, więc je dodaję
miTimer.addRight(miTemperatura); // zamykam pętlę aby przejść do Temperatura :-)
}
// ---- funkcja pobiera nazwę wybranej opcji ----------------------------------------------------------
void co_wybrano(MenuUseEvent used)
{
if(start==0) // jeśli obsługujemy menu (start=0)
{
Serial.println("-----------------------------------------------------------------------------------");
Serial.print("Wybrano opcje: < "); // komunikat o tym co wybrano
Serial.print(used.item.getName()); // funkcja getName() zwraca nazwę wybranej opcji
Serial.println(" > To tutaj wstawisz akcje do obslugi tej opcji.");
Serial.println("Na przyklad: if(used.item.getName()==\"W1_ON\") runAkcja_W1();");
Serial.println("... gdzie runAkcja_W1() to funkcja obslugi tego zdarzenia :-)");
Serial.println("-----------------------------------------------------------------------------------");
// poniżej przykładowa obsługa wszystkich opcji Menu :
if(used.item.getName()=="T zal.")Tz=ustawTemp("T zal.",Tz,10,40.0,0.2); // obsługa temp. załącznia
if(used.item.getName()=="T wyl.")Tw=ustawTemp("T wyl.",Tw,10,40.0,0.2); // obsługa temp. wyłączenia
if(used.item.getName()=="Czas_zal")GMz=ustawCzas("Oswietl","Czas zal.",GMz,10); // obsługa czasu zal.
if(used.item.getName()=="Czas_wyl")GMw=ustawCzas("Oswietl","Czas wyl.",GMw,10); // obsługa czasu zal.
if(used.item.getName()=="Wentylator 1")stW1=ustawWent(1); // obsługa wentylatora 1
if(used.item.getName()=="Wentylator 2")stW2=ustawWent(2); // obsługa wentylatora 2
if(used.item.getName()=="Wentylator 3")stW3=ustawWent(3); // obsługa wentylatora 3
if(used.item.getName()=="Timer_ON")TGMz=ustawCzas("Timer","Czas zal.",TGMz,10); // obsługa Timer ON
if(used.item.getName()=="Timer_ON")TGMw=ustawCzas("Timer","Czas wyl.",TGMw,10); // obsługa Timer OFF
}
}
// ---- funkcja identyfikuje aktualną wybraną opcję oraz poprzedni stan --------------------------------
void co_zmieniono(MenuChangeEvent changed)
{
if(changed.to.getName()=="MenuRoot") start=1; // jeśli root to wracamy do obsługi programu głównego
else // poniżej komunikaty kontrolne o tym co było i co wybrano
{
start=0;
Serial.print("Zmiana z: "); //
Serial.print(changed.from.getName()); // skąd (z jakiej opcji)
Serial.print(" na: ");
Serial.println(changed.to.getName()); // dokąd (do jakiej opcji)
}
}
// ---- odczyt klawiatury (tutaj 4 klawisze: Dalej, Plus ,Minus i OK) -----------------------------------
int czytaj() // wersja z klawiaturą modułu LCD Keypad Schield
{
int pinAnalog=0;
int stan_Analog = analogRead(pinAnalog);delay(30);//Serial.println(stan_Analog);
if (stan_Analog > 1000) return -1; // dla wartosci poza zakresem
if (stan_Analog < 50) return 0; // w prawo
if (stan_Analog < 150) return 1; // do gĂłry
if (stan_Analog < 300) return 2; // w dół
if (stan_Analog < 500) return 3; // w lewo
if (stan_Analog < 700) return 4; // OK
return -1; // nic nie wcisnieto
/*
Uwaga!!! Te wartości dla stan_Analog mogą się różnić dla różnych wykonań (klonów tego modułu)
Należy je dobrać doświadczalnie przez odczyt wartości na A0 (funkcja analogRead(A0)).
*/
}
// --- przykładowa funkcja program główny ----------------------------------------------------------------
void program_glowny() // tutaj Twój program wykonuje swoją pracę niezależnie od MENU
{
/*
To tutaj umieszczasz:
- odczyt danych z czujników
- reakcje na przekroczenie temperatury
- wszystkie ważne funkcje wykonywane przez program
*/
Serial.println("=== WYKONUJE PROGRAM GLOWNY ====");
obsluga_menu(); //aby w każdej chwili móc przerwać program i przejść do ustawień menu
}
// --- funkcja do obsługi menu ---------------------------------------------------------------------------
void obsluga_menu()
{
switch(czytaj())
{
case 0:menu.moveRight();
break;
case 1:menu.moveUp();
break;
case 2:menu.moveDown();
break;
case 3:menu.moveLeft();
break;
case 4:menu.use();
break;
}
delay(100); // kosmetyka (dobrać doświadczalnie czas dla autopowtarzania)
}
// -------------------------------------------------------------------------------------------------------
void setup()
{
menuSetup(); // przygotowanie menu do pracy
Serial.begin(9600); // konfiguracja dla Seriala
}
// -------------------------------------------------------------------------------------------------------
void loop() // ma tylko 3 linijki kodu :-)
{
if(start==1) program_glowny(); // jeśli start=1 wykonuje się nasz program
else obsluga_menu(); // jeśli naciśniemy klawisz (tutaj Minus lub DOWN - uruchamiamy menu)
/*
Jeśli chciałbyś aby inny klawisz był odpowiedzialny za przechodzenie pomiędzy Program a Menu,
to musisz uzyć innej funkcji klasy MenuBackend w miejscu tworzenia menu, czyli zamiast:
menu.getRoot().add(miTemperatura);
... użyj na przykład: menu.getRoot().addRight(miTemperatura); lub menu.getRoot().addLeft(miTemperatura);
*/
delay(20); // kosmetyka
}
// === koniec ============================================================================================
// --- funkcja nastawy Temperatury -----------------------------------------------------------------------
float ustawTemp(char s[10], float t, float vmin, float vmax, float skok)
{
Serial.print("Ustawienie: ");Serial.print(s);Serial.print(" = ");Serial.println(t);
int x=czytaj();
while(x!=4)
{
if(x==1){t+=skok;if(t>vmax)t=vmax;}
if(x==2){t-=skok;if(t<vmin)t=vmin;}
x=czytaj();
Serial.print("Ustawienie: ");Serial.print(s);Serial.print(" = ");Serial.println(t);
delay(120);
}
Serial.println("---------------------------------------------------------");
Serial.print("< USTAWIONO ");Serial.print(s);Serial.print(" = ");Serial.print(t);Serial.println(" >");delay(100);
Serial.println("---------------------------------------------------------");
return t;
}
// --- funkcja nastawy Czasu ------------------------------------------------------------------------------
int ustawCzas(char op[14],char s[10],int tt, int skok)
{
int g=tt/60;
int m=tt%60;
Serial.print("Ustawienie: ");Serial.print(s);Serial.print(" = ");Serial.print(g);Serial.print(":");Serial.println(m);
int x=czytaj();
while(x!=4)
{
if(x==1){tt+=skok;if(tt>23*60+50)tt=0;}
if(x==2){tt-=skok;if(tt<0)tt=23*60+50;}
x=czytaj();
g=tt/60;
m=tt%60;
Serial.print("Ustawienie: ");Serial.print(s);Serial.print(" = ");Serial.print(g);Serial.print(":");Serial.println(m);
delay(100);
}
Serial.println("---------------------------------------------------------");
Serial.print("< USTAWIONO ");Serial.print(s);Serial.print(" = ");Serial.print(g);Serial.print(":");
Serial.print(m);Serial.println(" >");
Serial.println("---------------------------------------------------------");
delay(1500);
return tt;
}
// ---- funkcja nastawy Wentylatora -------------------------------------------------------------------------
int ustawWent(int nr)
{
int s;
if(nr==1)s=stW1;if(nr==2)s=stW2;if(nr==3)s=stW3;
Serial.print("Ustawienie: Wentylator ");Serial.print(nr);Serial.print(": stan = ");Serial.println(s);
int x=czytaj();
while(x!=4)
{
if(x==1){s=!s;}
if(x==2){s=!s;}
x=czytaj();
Serial.print("Ustawienie: Wentylator ");Serial.print(nr);Serial.print(": stan = ");Serial.println(s);
delay(120);
}
Serial.println("---------------------------------------------------------");
Serial.print("< USTAWIONO ");Serial.print("Wentylator ");Serial.print(nr);Serial.print(": stan = ");Serial.print(s);
Serial.println(" >");
Serial.println("---------------------------------------------------------");
delay(100);
return s;
}
//-----------------------------------------------------------------------------------------------------------
Na końcu, za loop-em umieściłem funkcje do obsługi ustawień temperatury i czasu.
Z założenia każda z nich czyta stan klawiatury i dopóki nie wciśnięto OK (tutaj wartość =4), dopóty reagujemy na zmiany klawiszy UP-DOWN (prawo-lewo, czy Plus-Minus... jak kto woli).
Do pełni szczęścia brakuje jeszcze zapisu wartości do EEPROM-a no i całego programu głównego, ale to już zadanie dla autora projektu :-)
Trzeba jeszcze zamienić Seriale na obsługę wyświetlacza LCD - a tu może być pomocny mój poprzedni post:
Sandbox 4 :-)
Pozdrawiam