Kod: Zaznacz cały
// ============= MenuBackend tutorial ===============================================
#include <MenuBackend.h> // dołączenie biblioteki
//#include <LiquidCrystal.h> // obsługa wyświetlacza LCD
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
int led = 13;
LiquidCrystal_I2C lcd(0x27,20,4);
// --- definiujemy dla LCD własne znaki strzałek: dół, lewo, prawo, gora-dół i powrót ---
uint8_t arrowUpDown[8] = {
0x4,0xe,0x15,0x4,0x15,0xe,0x4};
uint8_t arrowDown[8] = {
0x4,0x4,0x4,04,0x15,0xe,0x4};
uint8_t arrowRight[8] = {
0x0,0x4,0x2,0x1f,0x2,0x4,0x0};
uint8_t arrowLeft[8] = {
0x0,0x4,0x8,0x1f,0x8,0x4,0x0};
uint8_t arrowBack[8] = {
0x1,0x1,0x5,0x9,0x1f,0x8,0x4};
//LiquidCrystal lcd(8,9,4,5,6,7); // definicja pinów dla LCD (sprawdź piny w swoim LCD)
volatile int zm =-1; // to dla kontroli zmiany stanu klawiatury
volatile int x=-1; // zmienna pomocnicza
volatile int stan_Analog; // wartość na wejściu Analogowym dla klawiaturki analogowej
char *linia1; // pierwsza linia wyświetlanego tekstu na LCD
char *linia2; // druga linia wyświetlanego tekstu na LCD
// --- tworzymy wszystkie opcje Menu: ---------------------------------------
// de facto tworzymy obiekty klasy MenuItem, które dziedziczą po klasie MenuBackend
MenuBackend menu = MenuBackend(menuUseEvent,menuChangeEvent); // konstruktor
// (" ")
MenuItem P1 = MenuItem("TestAAA",1);
MenuItem P11 = MenuItem("ON",2);
MenuItem P12 = MenuItem("OFF",2);
MenuItem P2 = MenuItem("TestBBB",1);
MenuItem P21 = MenuItem("Test1",2);
MenuItem P22 = MenuItem("Test2",2);
/* --- Teraz pozycjonujemy menu ( zgodnie z ustawieniem podanym powyżej) ------------
add - dodaje w pionie, addRight - dodaje w poziomie z prawej , addLeft dodaje z lewej
*/
void menuSetup() // funkcja klasy MenuBackend
{
menu.getRoot().add(P1); // ustawiamy korzeń Menu, czyli pierwszą opcję
P1.add(P11);
P11.add(P12);
P11.addLeft(P1);
P12.addLeft(P1);
P12.add(P11);
P1.addRight(P2);
P2.addLeft(P1);
P2.add(P21);
P21.add(P22);
P21.addLeft(P2);
P22.addLeft(P2);
P22.add(P21);
P2.addRight(P1);
}
// ----------- uff... nareszcie :-) -----------------------------------------------------------------------
void menuUseEvent(MenuUseEvent used) // funkcja klasy MenuBackend - reakcja na wciśnięcie OK
// tutaj właśnie oddajemy menu na rzecz akcji obsługi klawisza OK
{
//Serial.print("wybrano: ");
//Serial.println(used.item.getName()); // do testów, potem niepotrzebne
// --- ponizej kilka przykładów obsługi opcji -----------
// przykładowa reakcja na wcisnięcie klawisza OK w opcji Otworz :
if (used.item.getName() == "ON") // Uwaga - dokładnie taki sam ciąg " Otworz" jak w menu !!!
// bo przecież getName() pobiera nazwę
{
lcd.setCursor(1,0);
lcd.print(" Turn it ON! "); // info
digitalWrite(led,HIGH);
delay(1000);
//digitalWrite(led,LOW); // na 2 sekundy pin 0 otrzymał stan wysoki
// czyli np. otworzyły się drzwi
//delay(1000);
lcd.setCursor(1,0);
lcd.setCursor(1,0);
lcd.print(linia1); //poprzedni stan LCD
}
if (used.item.getName() == "OFF") // Uwaga - dokładnie taki sam ciąg " Otworz" jak w menu !!!
// bo przecież getName() pobiera nazwę
{
lcd.setCursor(1,0);
lcd.print(" Turn it OFF! "); // info
//digitalWrite(led,HIGH);
//delay(1000);
digitalWrite(led,LOW); // na 2 sekundy pin 0 otrzymał stan wysoki
// czyli np. otworzyły się drzwi
delay(1000);
lcd.setCursor(1,0);
lcd.print(" ");
lcd.setCursor(1,0);
lcd.print(linia1); //poprzedni stan LCD
}
// A teraz coś ambitniejszego :-), bo przekazujemy sterowanie klawiaturką do innej procedury,
// w tym przykładzie programik czeka aż ustawisz jakąś temperaturę i po wciśnięciu OK wraca do pętli głównej
if (used.item.getName() == " Temperatura") // dokładnie taki sam ciąg " Temperatura"
{
int temp=21; // przykładowo 21 st. C
lcd.setCursor(0,0);
lcd.write(7); // wyswietlamy nasz symbol strzałki góra-dół
lcd.print(" ");
lcd.setCursor(1,0);
lcd.print("Ust.temp. = "); // tekst dla użytkownika
lcd.setCursor(13,0);
lcd.print(temp); // wyświetlamy akt. temperaturę
int akcja=-1;
delay(1000); // zmienna pomocnicza, sterująca dla petli while
// jesli nie puścisz klawisza OK w ciągu 1 sek. to powrót do menu
while(akcja!=4) // ta pętla trwa tak długo aż wciśniesz klawisz OK
{
zm=-1;
akcja=czytaj_1(0);//delay(300); // odczyt stanu klawiatury - funkcja czytaj_1 lub czytaj_2 lub czytaj_3
// opis poniżej przy 3 różnych definicjach funkcji czytaj
if(zm!=akcja) // ruszamy do pracy tylko wtedy gdy zmienił sie stan klawiatury
{
if (akcja==1) {
temp++;
if(temp>99)temp=99;
lcd.setCursor(13,0);
lcd.print(temp);
delay(300);
}
// jesli akcja=1 (czyli wciśnieto klawisz w górę to zwiększono temperaturę
// ustawiono max próg i wyświetlono obecną temperaturę
if(akcja==2) {
temp--;
if(temp<10)temp=10;
lcd.setCursor(13,0);
lcd.print(temp);
delay(300);
}
// jesli akcja=2 (czyli wciśnieto klawisz w dół to mniejszono temperaturę
// ustawiono min próg i wyświetlono obecną temperaturę
if(akcja==4) // jeśli wciśnieto OK
{
lcd.setCursor(0,0);
lcd.print("*Temperatura OK");
delay(2000); // pokazujemy OK przez 2 sek.
lcd.setCursor(1,0);
lcd.print(" "); // czyścimy linię
lcd.setCursor(1,0);
lcd.print(linia1); // odtwarzamy poprzedni stan na LCD
}
}
}
zm=akcja; // aktualizacja zmiennej zm, po to aby reagować tylko na zmiany stanu klawiatury
// tu WAŻNY MOMENT - kończy się pętla while i zwracamy sterowanie do głównej pętli loop()
}
// a tutaj obsługa pozostałych opcji :-)
// ...
// ...
}
// --- Reakcja na wciśnięcie klawisza -----------------------------------------------------------------
void menuChangeEvent(MenuChangeEvent changed) // funkcja klasy MenuBackend
{
/* tak naprawdę to tylko tutaj przydaje się ów shortkey i służy przede wszystkim do wzbogacenia menu
o symbole strzałek w zależności co wybrano. Wszystko co tutaj się wyprawia jest pokazywane na LCD.
*/
int c=changed.to.getShortkey(); // pobieramy shortkey (1,2,3, lub4)
lcd.clear(); // bez komentarza
lcd.setCursor(0,0);
if(c==1) // jeśli to menu głowne (shortkey=1) to:
{
lcd.write(3); // strzałka w lewo
strcpy(linia1,changed.to.getName()); // tworzymy napis w pierwszej linii
lcd.print(linia1); // wyświetlamy ją
lcd.setCursor(19,0);
lcd.write(4); // strzałka w prawo
lcd.setCursor(0,1);
lcd.write(5); // strzałka w dół
lcd.setCursor(19,1);
lcd.write(5); // strzałka w dół
}
if(c==2) // jeśli to podmenu dla dziecka - (shortkey=2) to:
{
lcd.print("*"); // rysujemy gwiazdkę
strcpy(linia2,changed.to.getName()); // tworzymy napis w pierwszej linii
lcd.print(linia1); // wyświetlamy ją
lcd.setCursor(19,0);
lcd.print("*"); // gwiazdka
lcd.setCursor(0,1);
lcd.write(6); // druga linia i strzałka powrotu (arrowBack)
lcd.print(changed.to.getName()); // wyświetlamy nazwe "dziecka"
lcd.setCursor(19,1);
lcd.write(7); // strzałka góra-dół
}
if(c==3) // jeśli dziecko ma dziecko - (shortkey =3) to:
{
lcd.print("*"); // gwiazdka
strcpy(linia2,changed.to.getName()); // kopiujemy akt. nazwe opcji menu do zmiennej linia2
lcd.print(linia1); // i wyświetlamy pierwszą linię
lcd.setCursor(19,0);
lcd.print("*"); // gwiazdka
lcd.setCursor(0,1);
lcd.write(6); // druga linia i strzałka arrowBack
lcd.print(changed.to.getName()); // wyświetlamy wnuka w drugiej linii
lcd.setCursor(19,1);
lcd.write(4); // strzałka w prawo bo są wnuki
}
if(c==4) // jeśli to wnuk (shortkey =4) to:
{
lcd.print("*"); // gwaizdka
lcd.print(linia2); // w pierwszej linii wyświetlamy dziecko ( czyli rodzica wnuka)
lcd.setCursor(19,0);
lcd.print("*"); // gwaizdka
lcd.setCursor(0,1);
lcd.write(6); // druga linia i strzałka arrowBack
lcd.print(changed.to.getName()); // wyświetlamy wnuka
lcd.setCursor(19,1);
lcd.write(7); // strzałka góra-dół
}
}
/* --- ponżej funkcja odczytująca stan klawiatury -------------------------------------------
przygotowałem 3 różne wersje:
1) dla klawiaturki analogowej z shielda LCDanalogKey firmy DFRobot
2) dla joysticka ( 2 wejscia Analogowe i 1 pin cyfrowy )
Uwaga dla tej wersji opcji musisz dopisać w funkcji setup konfigurację dla pin, np. tak:
pinMode(1,INPUT);digitalWrite(1,HIGH);
3) dla 5-ciu pojedynczych przycisków ( potrzeba 5 pinów cyfrowych)
Uwaga dla tej wersji opcji musisz dopisać w funkcji setup konfigurację dla pinów, np. tak:
pinMode(1,INPUT);digitalWrite(1,HIGH);
pinMode(2,INPUT);digitalWrite(2,HIGH);
pinMode(3,INPUT);digitalWrite(3,HIGH);
pinMode(11,INPUT);digitalWrite(11,HIGH);
pinMode(12,INPUT);digitalWrite(12,HIGH);
*/
// --- wersja dla klawiatury 5-cio przyciskowej DFRobot --------------------------------------
volatile int czytaj_1(int analog)
{
int stan_Analog = analogRead(analog);
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 < 333) return 2; // w dół
if (stan_Analog < 510) return 3; // w lewo
if (stan_Analog < 745) return 4; // OK
return -1; // nic nie wcisnieto
}
// --- wersja dla joysticka (2 wejscia analogowe + pin cyfrowy -------------------------------
int czytaj_2(int poziom, int pion, int pinD)
{
// poziom - nr wejścia analogowego do którego podłączona jest manetka joysticka dla ruchu lewo-prawo
// pion - nr wejścia analogowego do którego podłączona jest manetka joysticka dla ruchu góra-dół
// pinD - nr pinu cyfrowego do którego podłączony jest przycisk OK w joysticku
int stan1= analogRead(pion);
{
delay(60);
if(stan1>0)stan1=(stan1+50)/1024+1;
}
int stan2= analogRead(poziom);
{
delay(60);
if(stan2>0)stan2=(stan2+50)/1024+1;
}
int stanD=digitalRead(pinD);
if(stanD==LOW) return 4; // OK
if(stan1==0) return 2; // w dół
if(stan1==2) return 1; // do gĂłry
if(stan2==0) return 3; // w lewo
if(stan2==2) return 0; // w prawo
return -1; // nic nie wcisnieto
}
// --- wersja dla 5-ciu przycisków cyfrowych --------------------------------------------------
// dla przykładu jeśli wykorzystujesz piny: 1,2,3,11 i 12 to wołasz : czytaj_2(1,2,3,11,12)
int czytaj_3(int gora, int lewo, int ok, int prawo,int dol)
// gora - nr pinu cyfrowego do którego podłączony jest przyciski góra
// lewo - nr pinu cyfrowego do którego podłączony jest przyciski lewo
// ok - nr pinu cyfrowego do którego podłączony jest przyciski OK
// prawo - nr pinu cyfrowego do którego podłączony jest przyciski prawo
// dol - nr pinu cyfrowego do którego podłączony jest przyciski dół
{
if(digitalRead(gora)==LOW) return 1;
if(digitalRead(lewo)==LOW) return 3;
if(digitalRead(ok)==LOW) return 4;
if(digitalRead(prawo)==LOW) return 0;
if(digitalRead(dol)==LOW) return 2;
return -1;
}
// ============================================================================================
//
void setup()
{
linia1=new char[20];
linia2=new char[20];
Serial.begin(9600);
//lcd.begin(16, 2); // inicjacja LCD
lcd.init();
lcd.backlight();
lcd.createChar(3,arrowLeft);
lcd.createChar(4,arrowRight);
lcd.createChar(5,arrowDown);
lcd.createChar(6,arrowBack);
lcd.createChar(7,arrowUpDown);
/* tu przykładowe piny cyfrowe dla 3 wersji funkcji czytaj_3(1,2,3,11,12)
pinMode(1,INPUT);digitalWrite(1,HIGH);
pinMode(2,INPUT);digitalWrite(2,HIGH);
pinMode(3,INPUT);digitalWrite(3,HIGH);
pinMode(11,INPUT);digitalWrite(11,HIGH);
pinMode(12,INPUT);digitalWrite(12,HIGH);
*/
pinMode(0,OUTPUT);
//digitalWrite(0,LOW); // do testów
menuSetup(); // funkcja klasy MenuBackend - tu tak naprawdę tworzymy nasze menu
menu.moveDown(); // idziemy do pierwszej opcji - PLIK, moveDown bo pierwotnie byliśmy w root
pinMode(led, OUTPUT); // moje do testów led na pin 13
}
// --- I nadszedł czas na neverending story :-) --------------------------------------------
void loop()
{
x=czytaj_1(0);
delay(30); // odczytujemy stan klawiatury:
/*
Ja używam funkcji czytaj_1() bo mam akurat klawiaturkę podpiętą pod A0
Jeśli masz inna klawiaturkę to użyj funkcji czytaj_2 lub czytaj_3 - patrz opis
Ponadto musisz pamietać że w funkcji obsługo klawisza OK - menuUseEvent(MenuUseEvent used)
także musisz użyć odpowiedniej wersji funkcji czytaj !!!
*/
if(zm!=x) // jesli była zmiana stanu to :
{
switch(x) // sprawdzamy co nacisnieto
{
case 0:
menu.moveRight();
break; // jesli naciśnięto klawisz w Prawo to przesuń menu w prawo
case 1:
menu.moveUp();
break; // menu do góry
case 2:
menu.moveDown();
break; // menu w dół
case 3:
menu.moveLeft();
break; // menu w lewo
case 4:
menu.use();
break; // wciśnięto OK więc skok do funkcji menuUseEvent(MenuUseEvend used)
// to w tej funkcji właśnie obsługujemy nasze Menu, tu sprawdzamy
// jaką opcję wybrano i tutaj tworzymy kod do obslugi zdarzenia.
}
}
zm=x; // przypisanie zmiennej zm wartości x po to, aby dluższe wciskanie tego
// samego klawisza nie powodowało ponownej generacji zdarzenia.
// program reaguje na zmianę stanu klawiatury.
}
// === KONIEC ===========================================================