• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Sandbox 3 - Budujemy własne MENU
#1
Witam 
W tej wizycie w piaskownicy wyciągniemy z wiaderka temat wielokrotnie poruszany na różnych forach i sporo z nas ma z nim małe problemy :-)
Mianowicie chodzi o MENU. Jak zrobić proste a jednocześnie funkcjonalne MENU?
Kilka lat temu umieściłem na majsterkowo.pl obszerny post omawiający bibliotekę MenuBackend, z czym to się je, jak to wykorzystać i takie tam pierdoły :-)
Po postach do mnie wracających zorientowałem się, że mimo iż bardzo się starałem, to jednak ta biblioteka nie do końca dociera do wyobraźni, a przynajmniej nie jest taka prosta w użyciu. W każdym razie co dla jednego jest podłogą, dla innego może być sufitem :-)
Dobra koniec belferskiego tonu. "Przejdźmy od słów do czynów. Chciałbym powiedzieć parę słów..." (cyt. film Rejs:-)
Na początek proponuję przykładowe Menu, prawie podobne do tego z IDE Arduino:
Kod:
String s[50]={     // tablica wszystkich opcji (tutaj przesadziłem z tym 50, bo jest ich 31)
 "PLIK","EDYCJA","SZKIC","NARZEDZIA","POMOC",                   // poziom 0 MENU GŁÓWNE
 "<<<-","Nowy","Otworz","Zapisz","Zamknij",                     // poziom 1 Submenu dla PLIK
 "<<<-","Kopiuj","Wkej","Wytnij","Szukaj","Zamien",             // poziom 2 Submenu dla EDYCJA
 "<<<-","Sprawdz","Wgraj","Export","Import",                    // poziom 3 Submenu dla SZKIC
 "<<<-","Archiwum","Port","Plytka","Programator","Wypal",       // poziom 4 Submenu dla NARZEDZIA
 "<<<-","Samouczek","Pytanie","O nas"};                         // poziom 5 Submenu dla POMOC
Jak widać składa się z MENU głównego: PLIK EDYCJA SZKIC NARZEDZIA POMOC, i każda z tych opcji posiada swoje SUBMENU. W sumie jest 6, określmy to  poziomów. Wszystkich opcji w tym przykładowym MENU jest 31. Umieszczone w tablicy String s[50].
Sterowanie MENU zaimplementujemy za pomocą trzech przycisków: UP, DOWN i OK.
Przcisku UP i DOWN (lub jak wolisz prawo - lewo) służą do poruszania się po MENU a przycisk OK wybiera daną opcje. 
Naturalnie w programie każdą z tych opcji będziemy chcieli obsłużyć, ale o tym potem. Na razie zadowolimy się możliwością nawigowania po MENU i wybierania akcji do wykonania. Potem w loop-ie sobie za pomocą najbardziej lubianego przeze mnie duetu: switch-case obsłużymy nasze wybory :-)
Skąd program ma wiedzieć w którym miejscu menu aktualnie jesteśmy i co wybrano?
Do tego celu posłużą nam jeszcze dwie tablice oraz kilka zmiennych:
Kod:
int Min[6]={0,5,10,16,21,27};   // tablica położeń dla pierwszej opcji dla danego poziomu
int Max[6]={4,9,15,20,26,30};   // tablica położeń dla ostatniej opcji dla danego poziomu
volatile int ak;                // numer aktualnej opcji
volatile int poziom;            // numer aktualnego poziomu menu
int min,max;                    // min i max dla danego poziomu, czyli pierwsza i ostatnia opcja
int pop=-1;                     // zmienna pomocnicza do sprawdzenia czy nastąpiła zmiana w MENU
Tablica Min[6] jest tablica indeksów pierwszych opcji dla każdego poziomu, czyli PLIK ma 0, każdy powrót "<<<-" w kolejnych poziomach to indeksy kolejno: 5,10,16,21,27 - czyli de facto indeksy tablicy String s[50].
Podobnie jest z tablica Max[6] - gdzie są indeksy ostatnich opcji dla każdego poziomu. 
Stąd właśnie teraz program wie, że główne menu to indeksy 0-4, że submenu dla SZKIC to indeksy 10-15 itd.
OK. Nawigację mamy z grubsza ogarniętą. Zmienne ak i poziom , min i max służą do identyfikacji tych indeksów, a zmienna pomocnicza pop służy wyłącznie do prezentacji dla Seriala, bo na nim będziemy pokazywać to menu.

Opis działania:
Poniższy przykład jest opatrzony dość szczegółowym komentarzem. Dla prezentacji samego
MENU wykorzystujemy tu komunikację po Serialu, ale bez problemu można ten kod
łatwo zaadoptować na wyświetlacz LCD.
Klawiszami UP - DOWN poruszamy się po poszczególnych opcjach, a klawiszem OK
zatwierdzamy wybór. Symbol "<<<-" oznacza powrót do głównego menu.   
Testy:
- Podepnij 3 buttony pod piny 2,3,4 swojego Arduino (DOWN, UP i OK). Drugi pin każdego buttona do masy.
- Skopiuj cały kod do Twojego IDE.
- Wgraj na Twoje Arduino.
- Odpal Serial-a i obserwuj co się dzieje jak bawisz się buttonami.

Pozostaje jeszcze kwestia obsłużenia naszych opcji. Za to odpowiada ten fragment kodu:
Kod:
switch(co())
 {
 case 6:      // funkcja obsługi opcji "Nowy"
   break;
 case 7:     //  funkcja obsługi opcji "Otworz"
   break;
 // itd .... pozostałe funkcje obsługi .........  
 }
.... to tutaj właśnie trzeba to wszystko obsłużyć :-)

To całe MENU stanowi tylko przykład zastosowania w programie. Możesz na tej bazie tworzyć swoje własne MENU.
Najważniejsza jest poprawność indeksów w tablicach Min i Max, ale myślę, że dość łatwo można zorientować się o co biega.
Poniżej cały kod programu:
Kod:
/*  Proste MENU dla Arduino ...by wojtekizk@warcaby.lh.pl
-------------------------------------------------------------------------------------------
Opis działania:
Za pomocą 3 przycisków: UP, DOWN i OK budujemy dośc spore menu.
W tym przykładzie nasze głowne MENU ma 5 opcji, a każda z opcji ma swoje
SUBMENU. W sumie mamy 31 opcji do wyboru. Naturalnie potem w programie każdy
taki wybór trzeba obsłuzyć np. w konstrukcji switch - case, ale to juz drugorzędna sprawa.
Masz tu przykład jak budować sobie takie nawet spore menu.
Poniższy przykład jest opatrzony dość szczegółowym komentarzem. Dla prezentacji samego
MENU wykorzystujemy tu komunikację po Serialu, ale bez problemu można ten kod
łatwo zaadoptować na wyświetlacz LCD.
Klawiszami UP - DOWN poruszamy się po poszczególnych opcjach, a klawiszem OK
zatwierdzamy wybór. Symbol "<<<-" oznacza powrót do głównego menu.
--------------------------------------------------------------------------------------------
Instrukcja:
1) 3 MIKROSWITCHE podepnij do pinów 2,3,4 Twojego Arduino, drugi biegun do masy.
2) Wgraj ten szkic na swoje Arduino
3) Odpal Serial i patrz co się dzieje jak będziesz bawił się przyciskami :-)
*/
// --- definicje przycisków ------------------------------------
#define UP 3       // przycisk  UP na Pin3
#define DOWN 2     // przycisk  DOWN na pinie 2
#define OK 4       // przycisk  OK na pinie 4
// --- zmienne: ------------------------------------------------
String s[50]={     // tablica wszystkich opcji (tutaj przesadziłem z tym 50, bo jest ich 31)
 "PLIK","EDYCJA","SZKIC","NARZEDZIA","POMOC",                   // poziom 0 MENU GŁÓWNE
 "<<<-","Nowy","Otworz","Zapisz","Zamknij",                     // poziom 1 Submenu dla PLIK
 "<<<-","Kopiuj","Wkej","Wytnij","Szukaj","Zamien",             // poziom 2 Submenu dla EDYCJA
 "<<<-","Sprawdz","Wgraj","Export","Import",                    // poziom 3 Submenu dla SZKIC
 "<<<-","Archiwum","Port","Plytka","Programator","Wypal",       // poziom 4 Submenu dla NARZEDZIA
 "<<<-","Samouczek","Pytanie","O nas"};                         // poziom 5 Submenu dla POMOC
 int Min[6]={0,5,10,16,21,27};   // tablica położeń dla pierwszej opcji dla danego poziomu
 int Max[6]={4,9,15,20,26,30};   // tablica położeń dla ostatniej opcji dla danego poziomu
volatile int ak;                  // numer aktualnej opcji
volatile int poziom;              // numer aktualnego poziomu menu
int min,max;                      // min i max dla danego poziomu, czyli pierwsza i ostatnia opcja
int pop=-1;                        // zmienna pomocnicza do sprawdzenia czy nastąpiła zmiana w MENU
// ---- funkcja co wybrano ----------------------------------------
int co()            //funkcja zwraca wartość równą indeksowi tablicy s (lub -1)
{
max=Max[poziom];    // określamy granicę przesuwania menu dla klawisza UP
min=Min[poziom];    // określamy granicę przesuwania menu dla klawisza UP
if(digitalRead(DOWN)==LOW){delay(40);if(digitalRead(DOWN)==LOW) {ak--;if(ak<min)ak=min;}}  // jeśli DOWN
if(digitalRead(UP)==LOW){delay(40);if(digitalRead(UP)==LOW) {ak++;if(ak>max)ak=max;}}      // jeśli UP
if(digitalRead(OK)==LOW){delay(40);if(digitalRead(OK)==LOW)                                // jeśli OK
 {
 if(poziom ==0 && ak==Min[0]){poziom=1;ak=Min[1]+1;return -1;}            // takie tam sztuczki :-)        
 if(poziom ==0 && ak>Min[0]){poziom=ak+1;ak=Min[poziom]+1;return -1;}     // takie tam sztuczki :-)
 if(poziom>0 && ak>Min[poziom]){return ak;}                               // takie tam sztuczki :-)
 if(poziom>0 && ak==Min[poziom]){ak=poziom-1;poziom=0;return -1;}         // takie tam sztuczki :-)
 }
}
return -1;                                // jak nic nie naciśnięto to jednak coś trza zwrócić   :-)
}
// --- funkcja do prezentacji MENU na Serialu --------------------------
void pokazSerial()
{
 for(int i=Min[poziom];i<=Max[poziom];i++)    // wyświetlam wszystkie aktualne opcje
   {
     if(i==ak) {Serial.print(" [ ");Serial.print(s[i]);Serial.print(" ] ");} // jeśli ta opcja jest aktywna
                                                                  // to wyświetam ją w nawiasie kwadratowym
     else Serial.print(s[i]);                                     // jeśli nie to bez nawiasu
     Serial.print(" ");                                           // odstęp
   }
   Serial.println();                                              // nowa linia
}
// ---------------------------------------------------------------------
void setup()
{
Serial.begin(9600);            // inicjalizacja Seriala
pinMode(DOWN,INPUT_PULLUP);    // konfiguracja pinów dla przycisków
pinMode(UP,INPUT_PULLUP);      // konfiguracja pinów dla przycisków
pinMode(OK,INPUT_PULLUP);      // konfiguracja pinów dla przycisków
ak=0; poziom=0;                // parametry początkowe MENU
max=Max[poziom];               // index dla ost. pozycji menu
min=Min[poziom];               // index dla pierwszej pozycji menu
}
// === neverending story ===============================================
void loop()
{
 //  --- dla testów pokazujemy raport na Serialu : ---------------
 if(co()!=-1)
 {
   Serial.print("Wybrano klawisz OK --- Wykonuje Akcje dla opcji:  ");
   Serial.println(s[ak]);   // wyświetlam komunikat o podjętej akcji
 }
 //  --- ale  w programie korzystamy z konstrukcji switch - case ----
 //  --- de facto to tu trzeba obsłuzyć wszystkie opcje :-)
 /*
 switch(co())
 {
 case 6:      // funkcja obsługi opcji "Nowy"
   break;
 case 7:     //  funkcja obsługi opcji "Otworz"
   break;
 // itd .... pozostałe funkcje obsługi .........  
 }
  */
 if(pop!=ak) {pokazSerial();pop=ak;}  // aby nie śmiecić na serialu, wyświetlam tylko zmiany :-)
 delay(120);                          // aby był czas na oderwanie palucha od przycisku :-)
                     // ten delay dobrać doświadczalnie, bo osoby z Parkinsonem mają refleks :-)
}
// === KONIEC ===========================================================
...lub w załączniku

I to by było na tyle...
Pozdrawiam


Załączone pliki
.zip   MyMENU.zip (Rozmiar: 2.43 KB / Pobrań: 179)
 
Odpowiedź
#2
Witam
Jestem poczatkującym w dziedzinie arduino i ogólnie programowania mikrokontrolerów.
buduję powoli lampę, którą chciałbym sterować poprzez arduino. Potrzebuję do tego jakiegos menu, które wyswietlane byłoby na lcd wbudowanym w lampie. Powyższe działa dobrze i może udało by się je przystosowac do mojej koncepcji ale za żadne skarby nie potrafię przenieść go na lcd.
Niestety jestem za cienki, więc proszę o pomoc, jakieś sugestie i porady. Głupia sprawa wszystko jest podane na tacy i nie potrafię z tego skorzystać Sad
 
Odpowiedź
#3
(03-13-2016, 23:40)samoogon napisał(a): Witam
Jestem poczatkującym w dziedzinie arduino i ogólnie programowania mikrokontrolerów.
buduję powoli lampę, którą chciałbym sterować poprzez arduino. Potrzebuję do tego jakiegos menu, które wyswietlane byłoby na lcd wbudowanym w lampie. Powyższe działa dobrze i może udało by  się je przystosowac do mojej koncepcji ale za żadne skarby nie potrafię przenieść go na lcd.
Niestety jestem za cienki, więc proszę o pomoc, jakieś sugestie i porady. Głupia sprawa wszystko jest podane na tacy i nie potrafię z tego skorzystać Sad
Nie chce sie wyglupic gdyz tez z Arduino bawie sie kila dni zaledwie...
Ale wyswietlilem na LCD to menu dopisujac w sekcji #include:

Kod:
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display
Nastepnie dalej w kodzie dodalem lcd.clear() bo bez tego nic nie mozna bylo odczytac :

Kod:
void pokazSerial()
{
lcd.clear();
for(int i=Min[poziom];i<=Max[poziom];i++)    // wyświetlam wszystkie aktualne opcje
  {
 
I zamienilem wszytkie:
Kod:
serial.print
serial.println
Analogicznie na:
Kod:
lcd.print
lcd.println
wiecej nie wiem, dopiero kombinuje jak zrobic "dynamiczny" index MENU itd. Ale chyba mnie przerosnie to cale Arduino ;p
 
Odpowiedź
#4
Dla poczatkujacego to MENU nie jest oczywiste ani intuicyjne. Takie jest moje zdanie bowiem przeczytalem dokladnie opis dzialania zamieszczony tutaj, sciagnalem kod, wgralem do Nano dodajac modyfikacje ustawien sprzetowych i uruchomilem. Oczywiscie zgodnie z opisem MENU dzialalo poprawnie z wyswietlaniem danych na emulatorze monitora w programie IDE. Problemy zaczely sie dopiero przy probie wykonania wlasnej wersji na podstawie wzorca. Wedlug mojej opinii kod nie jest napisany intuicyjnie i dlatego do wielu rzeczy doszedlem dopiero jak go sformatowalem inaczej, w sposob przejrzysty kazda linia osobno. Samo definiowanie poziomow i ich zawartosci nie stanowi problemu oczywiscie dopoki wszystko wyswietlamy na "monitorze". Sporo czasu zajelo mi wojowanie z wyswietlaniem MENU na 16x2 LCD. I to nie jest takie proste jak to pisal przedpiszca, ze wystarczy zamienic Serial.print na lcd.print. Po takiej zmianie na wyswietlaczu pojawia sie kaszana bowiem w zupelnie inny sposob nalezy przedstawiac informacje na wyswietlaczu LCD ze wzgledu na jego ograniczenia. W opisie znajduje sie informacja ze z latwoscia mozna to MENU dostosowac do wykonywania dzialan a nie tylko wyswietlania na monitorze korzystajac z polecenia switch/case. Prawie mi sie udalo z jednym wyjatkiem. Otoz na podstawie informacji z internetu wykonalem program oczekujacy na informacje z serial portu (virtual port USB), przetwarzajacy ta informacje na polecenie dla modulu AD9850 (przypominam ze buduje generator sterowany Nano) wlaczajace generowanie przekazanej wartosci czestotliwosci i oczekujacej na kolejne dane z nowymi wartosciami. Tego podprogramu nie udalo mi sie do konca uruchomic w swich/case poniewaz po wybraniu tej opcji z MENU program oczekuje na wpis z serial portu ale go nie przetwarza wyswietlajac jednoczesnie wartosc przekazanej i uruchomionej czestotliwosci. Przetwarzanie i przekazanie do wykonania wpisanej czestotliwosci nastepuje dopiero po wcisnieciu klawisza OK na 3 przyciskowej klawiaturze i tak za kazdym razem jak podam przez serial nowa wartosc czestotliwosci do uruchomienia to jest ona przetwarzana dopiero po wcisnieciu OK.
Kolejna sprawa do ustawienie  czasu drgan zestykow przyciskow. Znajduje sie ono w 2 miejscach i jeszcze nie udalo mi sie ustalic ktore jest istotne.
Ponizej zalaczam kod troche przydlugi ale moze komus sie przyda prawie kompletny gotowiec:

Kod:
#include <DDS.h>
// Instantiate the DDS...
DDS dds(5, 4, 3, 2);
#include <LiquidCrystal.h>
//Instatiate LCD
LiquidCrystal lcd(11, 10, 9, 8, 7, 6);
int ledpin = 13;

// --- definicje przycisków ------------------------------------
#define UP A3       // przycisk  UP na Pin A3
#define DOWN A1     // przycisk  DOWN na pinie A1
#define OK A2       // przycisk  OK na pinie A2
String s[25]={     
 "Serial","Zapper","Presety",                   // poziom 0 MENU GŁÓWNE
 "<<<-","Uruchom",                     // poziom 1 Submenu dla Serial
 "<<<-","10 kHz","30 kHz","70 kHz","100 kHz",             // poziom 2 Submenu dla Zapper
 "<<<-","Detox","Dental","Tinitus","Prostate", };                  // poziom 3 Submenu dla Presety
// tablica wszystkich opcji (tutaj przesadziłem z tym 50, bo jest ich 31)
 int Min[6]={0,3,5,10};   // tablica położeń dla pierwszej opcji dla danego poziomu
 int Max[6]={2,4,9,14};   // tablica położeń dla ostatniej opcji dla danego poziomu
volatile int ak;                  // numer aktualnej opcji
volatile int poziom;              // numer aktualnego poziomu menu
int min,max;                      // min i max dla danego poziomu, czyli pierwsza i ostatnia opcja
int pop=-1;                        // zmienna pomocnicza do sprawdzenia czy nastąpiła zmiana w MENU
unsigned long czas;            //zmienna pomocnicza funkcji genzap
unsigned long freqgen;         //zmienna pomocnicza funkcji genzap
char Name[10];                 // zmienna pomocnicza dla funkcji wykonaj
int n();                       // zmienna pomocnicza dla funkcji wykonaj
unsigned long freq=(0);          //zmienna pomocnicza dla funkcji serial
#define TEXT_LEN 12              //zmienna pomocnicza dla funkcji serial
char odczytfreq[TEXT_LEN+1] = ""; //zmienna pomocnicza dla funkcji serial
char Str[12];                     //zmienna pomocnicza dla funkcji serial
String odczyt;                    //zmienna pomocnicza dla funkcji serial
// ---- funkcja co wybrano ----------------------------------------
int co()            //funkcja zwraca wartość równą indeksowi tablicy s (lub -1)
{
max=Max[poziom];    // określamy granicę przesuwania menu dla klawisza UP
min=Min[poziom];    // określamy granicę przesuwania menu dla klawisza UP
if(digitalRead(DOWN)==LOW){delay(100);if(digitalRead(DOWN)==LOW)
{ak--;if(ak<min)ak=min;}}  // jeśli DOWN
if(digitalRead(UP)==LOW){delay(100);if(digitalRead(UP)==LOW)
{ak++;if(ak>max)ak=max;}}      // jeśli UP
if(digitalRead(OK)==LOW){delay(100);if(digitalRead(OK)==LOW)      // jeśli OK
 {
 if(poziom ==0 && ak==Min[0]){poziom=1;ak=Min[1]+1;return -1;}         
   // takie tam sztuczki :-)        
 if(poziom ==0 && ak>Min[0]){poziom=ak+1;ak=Min[poziom]+1;return -1;}  
   // takie tam sztuczki :-)
 if(poziom>0 && ak>Min[poziom]){return ak;}                            
   // takie tam sztuczki :-)
 if(poziom>0 && ak==Min[poziom]){ak=poziom-1;poziom=0;return -1;}      
   // takie tam sztuczki :-)
 }
}
return -1;                                // jak nic nie naciśnięto to jednak coś trza zwrócić   :-)
}
// --- funkcja do prezentacji MENU na Serialu --------------------------
void pokazSerial()
{
 for(int i=Min[poziom];i<=Max[poziom];i++)    // wyświetlam wszystkie aktualne opcje
   {
     if(i==ak) {Serial.print(" [ ");Serial.print(s[i]);Serial.print("] ");} // jeśli ta opcja jest aktywna
                                                                  // to wyświetam ją w nawiasie kwadratowym
     else Serial.print(s[i]);                                     // jeśli nie to bez nawiasu
     Serial.print(" ");                                           // odstęp
   }
   Serial.println();                                              // nowa linia
}
// ---------------------------------------------------------------------
// funkcja prezentacji MENU na LCD
void pokazlcd()
{
 for(int i=Min[poziom];i<=Max[poziom];i++)    // wyświetlam wszystkie aktualne opcje
   {
     if(i==ak)
     {
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print(s[i]);
  //      lcd.print(ak);
  //      lcd.print(poziom);
      
      } // jeśli ta opcja jest aktywna
                                                                  // to wyświetam ją w nawiasie kwadratowym
    // else
    // lcd.setCursor(0,1);
    // lcd.print(s[i]);                                     // jeśli nie to bez nawiasu
     //lcd.print(" ");                                           // odstęp
   }
   //lcd.println();                                              // nowa linia
}
/*{
  lcd.clear();
  lcd.print(s[ak]);  
  lcd.print(ak);
  lcd.print(poziom);
}*/
// funkcja generowania zalozonych czestotliwosci zappera
void genzap(unsigned long freqgen, unsigned long czas)
{
 lcd.clear();
 lcd.print("Zapper ");
 lcd.print(s[ak]);
 digitalWrite(ledpin, HIGH);
 dds.setFrequency(freqgen);
 delay(czas);
 digitalWrite(ledpin, LOW);
 dds.init();
 lcd.setCursor(0,1);
 lcd.print("Koniec");  
}
//funkcja generowania presetow
void wykonaj(char Name[10], int n, unsigned long freq[])
{
   for (int i=0; i<n; i++)
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(Name);
  lcd.print(" ");
  lcd.print(i);
  digitalWrite(ledpin, HIGH);
  dds.setFrequency(freq[i]);
  lcd.setCursor(0, 1);
  lcd.print(freq[i]);
  lcd.print(" Hz");
  delay(180000);
  if (i == n);
  {
    digitalWrite(ledpin, LOW);
    dds.init();
    lcd.clear();
    lcd.print("Koniec");
  }
}
}
void setup()
{
lcd.begin(16,2);
lcd.clear();  
Serial.begin(9600);            // inicjalizacja Seriala
pinMode(DOWN,INPUT_PULLUP);    // konfiguracja pinów dla przycisków
pinMode(UP,INPUT_PULLUP);      // konfiguracja pinów dla przycisków
pinMode(OK,INPUT_PULLUP);      // konfiguracja pinów dla przycisków
ak=0; poziom=0;                // parametry początkowe MENU
max=Max[poziom];               // index dla ost. pozycji menu
min=Min[poziom];               // index dla pierwszej pozycji menu
dds.init();

}
// === neverending story ===============================================
void loop()
{
 if(co()!=-1)
 {
  // Serial.print("Wybrano klawisz OK --- Wykonuje Akcje dla opcji:  ");
  // Serial.println(s[ak]);   // wyświetlam komunikat o podjętej akcji
 }
 //  --- ale  w programie korzystamy z konstrukcji switch - case ----
 //  --- de facto to tu trzeba obsłuzyć wszystkie opcje :-)
//  if(pop!=ak) {pokazSerial();pop=ak;}  // aby nie śmiecić na serialu, wyświetlam tylko zmiany :-)

  if(pop!=ak) {pokazlcd();pop=ak;}    
   delay(150);          
 

 switch(co())
 {
 case 4:  // funkcja obsługi opcji "Serial - Uruchom"
 {
lcd.clear();
     lcd.print("Waiting ?");
  Serial.begin(9600); //Uruchomienie komunikacji
  while (!Serial) // wait for serial port to connect.
  {
    ;
  }
   
  if(Serial.available() > 0)  //Czy Arduino odebrano dane
 {
    odczyt = Serial.readStringUntil("\n");
     Serial.println(odczyt);
    odczyt.toCharArray(odczytfreq, 12);
     Serial.println(odczytfreq);
   freq=atol(odczytfreq);
   Serial.println(freq);
    lcd.clear();
     lcd.setCursor(0, 0);
  lcd.print("Frequency: ");
  lcd.setCursor(0, 1);
    lcd.print(freq);
    lcd.print(" Hz");
   dds.init();
    dds.setFrequency(freq);
    digitalWrite(ledpin, HIGH);
      }
  }

 break;
 case 6:     //  funkcja obsługi opcji "Zapper - 10kHz"
 {
  genzap(10000,180000);
 }
 break;
 case 7:      // funkcja obslugi opcji "Zapper - 30kHz"
 {
 genzap(30000,180000);
 }
 break;
 case 8:      //funkcja obslugi opcji "Zapper - 70kHz"
 {
 genzap(70000,180000);
 }
 break;
 case 9:       // funkcja obslugi opcji "Zapper - 100kHz"  
  {
 genzap(100000,180000);
 }
 break;
 case 11:      // funkcja obslugi opcji detox
 {
 unsigned long freq[] = {
33408, 41984, 45568, 49152, 40000, 50816, 48640, 56320, 50368, 48064,
46528, 43264, 40640, 33408, 59520, 56832, 38912, 39168, 37888, 37376,
31129, 30822, 42434, 40960, 32071, 51609};
wykonaj("Detox", 26, freq);
 }
 break;
 case 12:
 {
 unsigned long freq[] = {
58160, 43520, 34720, 50368, 32000, 48640, 46592, 30720, 41728, 59520,
46528, 50368, 56320, 42240, 42624, 44160, 46528, 50176, 50368, 51200,
49920, 58880, 31968, 39824, 30720, 50176, 40640, 40960, 33152, 33376,
35008, 43840, 30720, 49152, 41360, 48000, 57600, 49600, 35008, 33376,
33152, 53248, 51328, 49664, 46528, 43840, 41600, 41344, 38400, 49152,
385000, 362000, 342000, 349000, 378000, 381000, 318000, 373000, 368000, 52500,
90000, 234250, 842000, 937410, 85540, 175000, 225360, 575830, 73300, 95750,
269710, 355080, 20000, 47500, 95310, 210500, 475950, 527000};
wykonaj("Dental", 78, freq);
 }
 break;
 case 13:
 {
 unsigned long freq[] = {
20000, 65000, 207460, 479930, 527000, 749000, 986220, 118330, 209180, 321000,
544100, 631170, 705000, 88500, 125680, 240000, 470000, 592500, 625230, 723010,
87500, 175160, 322060, 476500, 667000, 742000, 985670};  
 wykonaj("Tinitus", 27, freq);
 }
 break;
 case 14:
 {
unsigned long freq[] = {
32800, 56320, 49600, 51328, 50368, 46528, 59520, 40960, 38461, 34032,
32128, 59520, 40000, 50368, 44160, 42624, 32000, 48640, 37376, 36864,
41600, 38400, 36000, 34048, 43520, 46592, 52224, 48640, 33792, 31744,
152300, 328920, 424210, 482130, 502930, 553700, 591420};
wykonaj("Prostate", 37, freq);
 }
 break;
 }
 }

// === KONIEC ===========================================================
Czy ktos ma jakis pomysl jak uruchomic serial-uruchom aby nie trzeba bylo za kazda zmiana czestotliwosci naciskac OK?
Kod oczywiscie dziala za wyjatkiem tej jednej opcji.
Poczatki zawsze sa trudne :-)
 
Odpowiedź
#5
Nie przeglądałem kodu z braku czasu, ale przede wszystkim obsługę strumienia zrób nie na ifie
if(Serial.available() > 0){} bo to ci się wykona tylko raz i wraca do nasłuchiwania klawiszy

spróbuj tak:
Kod:
while (Serial.available() > 0){}

a w funkcji wstaw obsługę klawisza, albo wysyłaj znak wyjścia do menu z komputera, a w kodzie zasymuluj wciśnięcie klawisza:
Kod:
jeśli znak== jakisznak
pinMode(OK,OUTPUT);
digitalWrite(OK,LOW);
pinMode(OK,INPUT);


a w setupie OK bez pullupa.
 
Odpowiedź
#6
Ten kod umieszczony w osobnym skrypcie dziala bez problemow bowiem jest umieszczony w sekcji loop(). Po przeniesieniu do switch/case jest problem ze potrzebny jest przyciskOK aby przyjac znak i przetworzyc.
Kod dzialajacy w osobnym skrypcie wyglada nastepujaco:

Kod:
#include <LiquidCrystal.h>
#include <DDS.h>
unsigned long freq=(0);  
#define TEXT_LEN 12
char odczytfreq[TEXT_LEN+1] = "";
char Str[12];
String odczyt;
// Instantiate the DDS...
DDS dds(5, 4, 3, 2);
//Instatiate LCD
LiquidCrystal lcd(11, 10, 9, 8, 7, 6);

void setup() {
   // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
     lcd.print("Waiting ?");
  Serial.begin(19200); //Uruchomienie komunikacji
   while (!Serial) {
    ;
    // wait for serial port to connect. Needed for native USB
 
   }
}
 
void loop()
{
  if(Serial.available() > 0) { //Czy Arduino odebrano dane
    //Jeśli tak, to odczytujemy je do znaku końca linii i zapisz w zmiennej
    odczyt = Serial.readStringUntil("\n");
   //  Serial.println(odczyt);
    odczyt.toCharArray(odczytfreq, 12);
   //  Serial.println(odczytfreq);
   freq=atol(odczytfreq);
   Serial.println(freq);
    lcd.clear();
     lcd.setCursor(0, 0);
  lcd.print("Frequency: ");
  lcd.setCursor(0, 1);
    lcd.print(freq);
    lcd.print(" Hz");
   dds.init();
    dds.setFrequency(freq);
      }
}

W tej postaci kazde przekazanie nowej czestotliwosci za posrednictwem monitora portu szeregowego uruchamia nowa przekazana czestotliwosc.
Umieszczenie programu w czesci switch/case cos blokuje przetwarzanie. Aha W kodzie sa kontrolne komendy wyswietlania w oknie monitora portu szeregowego.
Poczatki zawsze sa trudne :-)
 
Odpowiedź
#7
Wydaje mi sie ze calosc "case 4" trzeba zamknac w petle warunkowa z wyjsciem poprzez klawisz OK w taki sposob ze przekazywanie nowych wartosci czestotliwosci bedzie sie dzialo dopoki nie nacisne klawisza OK aby wyjsc z podprogramu.
Pare chwil potem:
Uzylem moze nieelganckiego rozwiazania ale skutecznego czyli goto label plus delay. Odpowiednio umieszczone powoduja, ze funkcja dziala jak powinna tylko nie da sie z niej elegancko wyjsc ale to jest mi niepotrzebne poniewaz jesli generator jest sterowany z PC poprzez serial (usb) to dziala tak az do resetu. A po resecie moge wybrac inne funkcje.
I po paru godzinach:
dodalem jeszcze jedna opcje warunkowa z goto label i wychodze z podprogramu naciskajac przycisk DOWN.
Przydaje sie wprawa w pisaniu polecen batch file pod DOS ;-)
Na tym koncze ten temat i dziekuje za pomoc.
Poczatki zawsze sa trudne :-)
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości