Skocz do zawartości

Menu z możliwością ustawiania daty za pomocą klawiatury


Felgrip

Pomocna odpowiedź

Dzien dobry, 

Mam pewien problem z budowa menu, ogólnie chciałem zrobić  menu które wyświetla mi dane na wyświetlaczu LCD, parametry z czujników i możliwość dodania daty, godziny z klawiatury. Problem polega na tym ze przy dodawaniu np dnia program dodaje mi tylko pierwszy znak który nacisnę na klawiaturze, po następnym naduszeniu klawisza zmienia wartość, a chciałbym żeby zapisywało poprzednie znaki.

void ustawienieDnia(String a,String b,int c,char klawisz)
{
        
       if (klawisz && klawisz != 'A' && klawisz != 'B' && klawisz != 'C' && klawisz != 'D' && klawisz != '#' && klawisz != '*'){
          lcd.print(klawisz);
           a = String(klawisz);
           
         //b.concat(a);
          a.length();
          c = a.toInt();      
                   
          Serial.println(c);
          
       }
       
}

 Próbowałem  cos zakombinować z komenda length, lecz nie za bardzo wiem jak to ugryźć ;/ 

 

Link do komentarza
Share on other sites

@Felgrip witam na forum 🙂

Każdy klawisz wciskany na klawiaturze jest odczytywany niezależnie. Układ "nie wie", że to pierwsza z dwóch cyfr itd. W najprostszej wersji musisz samodzielnie dorobić taki mechanizm. Zakładając, że chodzi o liczby dwucyfrowe mógłbyś to zrobić następująco (to tylko ogólna idea, bo jest tam kilka haczyków):

  • Jeśli wciśnięto klawisz i zmienna pomocnicza równa się 0 to:
    • Odczytujesz cyfrę i zapisujesz ją jako wynik
    • Zwiększasz zmienną pomocniczą o 1
  • Jeśli wciśnięto klawisz i zmienna pomocnicza równa się 1 to:
    • Wcześniejszy wynik mnożysz razy 10 (aby przesunąć wartość z jedności na dziesiątki)
    • Odczytujesz cyfrę i dodajesz ją do wyniku (otrzymujesz wtedy liczbę dwucyfrową)
    • Zwracasz dwucyfrową wartość
  • Pomogłeś! 1
Link do komentarza
Share on other sites

Próbowałem zrobić według tego co mi na pisałeś, lecz napotkałem problem taki że po po wciśnięciu przycisku widzi mi pierwszego ifa, po czym zamiast się zatrzymać i poczekać na następne wciśnięcie klawisza leci dalej i wpisuje mi liczbę np. 11, 33 itd. możliwe jest jest to przez moją nieuwagę nie jestem za dobry w programowaniu i pewnie nie rozumiem pewnych rzeczy.😄 Próbowałem to zrobić jeszcze na switchu ale tu znowu nie widziało mi naciśniętego klawisza. Myślałem jeszcze nad zrobieniu tablic dla wyboru danego dnia, miesiąc ale myślę ze problem leży gdzie indziej. Nie mam pomysły na to. Jeżeli maci jakieś poradniki czy kursy gdzie mógłbym  się podszkolić, chętnie skorzystam.😀

Link do komentarza
Share on other sites

@SzpondeRR czy jesteś tą samą osobą, która założyła ten temat? Pytam, ponieważ pierzesz z jakiegoś innego konta. Jeśli tak, to daj znać, które konto ma zostać aktywne - połączę je.

Wracając do tematu - pokaż swój kod, to łatwiej będzie pomóc 🙂

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)


Konto Felgrip może zostać, do tego drugiego zapomniałem hasła już jakiś czas temu dlatego założyłem drugie, w sumie nawet nie wiem dlaczego post został napisany z tego starego konta , Jeżeli chodzi o kod wrzucę całości, możliwe ze problem leży w innym miejscu.

#include <LiquidCrystal.h>
#include <Keypad.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3' , 'A'},
  {'4','5','6' , 'B'},
  {'7','8','9' , 'C'},
  {'*','0','#' , 'D'}
};
byte rowPins[ROWS] = {50, 51, 52, 53};  //Piny, do których podłączamy wyprowadzenia od rzędów
byte colPins[COLS] = {46, 47, 48 , 49}; //Piny, do których kolumn wyprowadzenia od rzędów
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
bool lock = 1;
bool lock1 = 1;
int A = 0;
int B = 0;
int C = 0;
String string1 = String(); 
String string2 = String(); 
String string3 = String(); 
String string4 = String(); 
String string5 = String(); 
String cyfra1,cyfra2,cyfra3,cyfra4,cyfra5;
int dzien, miesiac, rok, godzina, minuta;
void setup()
{
  Serial.begin(9600);
  lcd.begin(16, 2);              
  lcd.setCursor(0, 0);
  lcd.print("Projekt Trakera"); 
}
void loop()
{
            
   char klawisz = keypad.getKey();
  
  
  switch (A)               
  {
    case 0: // poruszanie  do góry
    if(lock == 1)
      {
        
        lcd.clear();
      lcd.home();
      lock = 0;
      lcd.print("projekt trakera");
      lcd.setCursor(0, 1);
      lcd.print("BY Rafal & Damian");
      }
      if (klawisz == 'A'){
      A++;
      }
        break;
      
    case 1: // poruszanie do dołu
      if (lock == 0){
        
        
          lcd.clear();
          lcd.home();
          lock = 1;
          lcd.print("Ustawienie czasu");
      } 
      switch (C) //  posaczefolne parametry
      {
        case 0:
        if (lock1 == 1){
        lock1 = 0;
        }
        if(klawisz == 'C'){
        C++;
        }
        break;
      
        case 1:
        
        if (lock1 == 0){
            lcd.clear();
            lcd.print("Dzien :");
            lcd.setCursor(0,1);
            lock1 = 1;
            
          }
      ustawienieDnia(dzien,klawisz);
     
      if(klawisz == 'C')
        C++;
        
        if (klawisz == 'D')
        C--;
       
        break;
     
        case 2:
        if(lock1 == 1){
          lcd.clear();
            lcd.print("Miesiac :");
            lcd.setCursor(0,1);
            lock1 = 0;
        }
        ustawienieDnia(cyfra2,string2,miesiac,klawisz);
        if(klawisz == 'C'){
        C++;
        }
        if (klawisz == 'D')
        C--;
       
        break;
        case 3:
        if(lock1 == 0){
          lcd.clear();
            lcd.print("Rok :");
            lcd.setCursor(0,1);
            lock1 = 1;
        }
        ustawienieDnia(cyfra3,string3,rok,klawisz);
        if(klawisz == 'C'){
        C++;
        }
        if (klawisz == 'D')
        C--;
                  
        break;
        case 4:
         if(lock1 == 1){
          lcd.clear();
            lcd.print("Godzina :");
            lcd.setCursor(0,1);
            lock1 = 0;
         }
         ustawienieDnia(cyfra4,string4,godzina,klawisz);
         if(klawisz == 'C'){
        C++;
        }
        if (klawisz == 'D')
        C--;
         
         break;
         case 5:
          if(lock1 == 0){
          lcd.clear();
            lcd.print("Minuta :");
            lcd.setCursor(0,1);
            lock1 = 1;
          }
          ustawienieDnia(cyfra5,string5,minuta,klawisz);
          
        if (klawisz == 'D')
        C--;
        if(klawisz == '*')
        
        
        
          break;
         
      }                                                             // koniec switcha C
        
        if (klawisz == 'A')
        A++;
        if (klawisz == 'B')
        A--;
       break;
    case 2:
      if(lock == 1){
        lcd.clear();
        lcd.print("parametry");
        lock = 0;
        
      }
      if (klawisz == 'A')
        A++;
        if (klawisz == 'B')
        A--;
       break;
      
    case 3:
      {
        lcd.clear();
        lcd.print("3");
      }
        break;
      
        
    case 4:
      {
        break;
      }
    case 5:
      {
        break;
      }
      
  }
}
void ustawienieDnia(int c,char klawisz)
{
  String liczba1,liczba2; String cyfra, cyfra1; int liczbaWpisana; bool pomocnicza = 0;
        
        
         
          
           if (pomocnicza == 0)
            pomocnicza++;
            if(klawisz && klawisz != 'A' && klawisz != 'B' && klawisz != 'C' && klawisz != 'D' && klawisz != '#' && klawisz != '*'){
          
            
          lcd.print(klawisz);
          
          liczba1 = String(klawisz);
          cyfra.length(liczba1);
          
          liczbaWpisana = cyfra.toInt(); 
          Serial.println(liczbaWpisana);
          
          
          
          
         }
         
          
          if (pomocnicza == 1)
          pomocnicza = 0;
          if ( klawisz && klawisz != 'A' && klawisz != 'B' && klawisz != 'C' && klawisz != 'D' && klawisz != '#' && klawisz != '*'){
           
           
            lcd.print(klawisz);
            liczba2 = String(klawisz);
            cyfra1.concat(liczba2);
            c = cyfra1.toInt()+(liczbaWpisana*10);
            Serial.println(c);
           
            
            
                 
          }
                 
         }

 

Nie wiem dlaczego po wpisaniu pierwszej liczby program nie czeka na podanie następnej liczby tylko leci dalej, próbowałem również zamiast ifa, na switchu zrobić podobny warunek ale efekt był jeszcze gorszy bo nie widziało żadnego wciśniętego przypisku, program pisany na szybko dlatego może być kapkę nieczytelny 

Edytowano przez Felgrip
Źle dodany kod programu.
Link do komentarza
Share on other sites

12 godzin temu, Felgrip napisał:

program pisany na szybko dlatego może być kapkę nieczytelny 

No faktycznie, lepiej chyba usiąść do tego na spokojnie. Na początek stwórz nowy szkic i spróbuj w nim napisać tylko ten jeden fragment, który będzie zmieniał jedną wartość - pomiń na razie całe menu. Skup się na ustawianiu wartości. Tak będzie łatwiej naprawiać kod. Jak całość zadziała to dopiero będzie sens obudowywać to resztą kodu i całym menu - przy okazji wyjdą pewnie również jakieś inne problemy, ale będzie wiadomo, że podstawowa część działa poprawnie 🙂

Link do komentarza
Share on other sites

Bardzo sobie komplikujesz tymi cyferkami na klawiaturze. Do zmiany opcji menu w aucie wystarcza 1 przycisk. Co ciekawe w czasie obsługi menu komputer pokładowy dalej obsługuje wszystkie elementy samochodu, nie jest odcinany zapłon, wtrysk paliwa, czy możliwość otwarcia blokady drzwi, bo wszedłeś ustawić zegarek. Kocioł mi nie przestaje sterować wentylatorem, bo wszedłem w menu sprawdzić temperaturę zewnętrzną.

Nie ma co się umartwiać jednym przyciskiem, jak już masz ich 16, ale prościej byłoby ograniczyć ich funkcje do IN/OUT/+/-. Na pewno w czasie obsługi menu program nie powinien się tu zatrzymywać, to tylko tak może wyglądać na ekranie. 

Można np. w loop podzielić sobie całość na 3 sekcje, obsługa odczytów i wyjść A, wyświetlanie wartości na ekranie B, wyświetlanie menu C. Normalnie program powinien działać po drodze AB. Jeśli jakikolwiek przycisk zostanie dotknięty to przełączasz zmienną z 0 na 1 i dzięki niej nie wchodzisz w sekcję B, a zamiast tego wchodzisz w C. Oczywiście program tu nie stoi, wchodzi tu, robi coś lub niewiele, wychodzi, przechodzi przez sekcję A, pomija wyświetlanie wartości B i wchodzi w C. I tak w kółko drogą AC. W menu zlicza czas od ostatniego dotknięcia klawiatury, jeśli minie np. 20s to znaczy, że ktoś zasłabł, zszedł, ma coś pilniejszego do robienia i nie ma sensu tu dłużej wchodzić, przełącza zmienną z 1 na 0 i program działa dalej lecąc drogą AB. Oczywiście ani w B ani w C program nie drukuje nic na LCD częściej niż to jest potrzebne. Jeśli jest jakaś nowa informacja do wyświetlenia, albo minęła 1s od ostatniego wydruku to można wydrukować, a inaczej to po co, program się zapoci ciągłym wysyłaniem danych niepotrzebnie zabierając czas. Więc tu najważniejszy jest pomiar czasu.

Żeby nie było, że w A ciągle coś robi, tu też powinno być ustalone dla każdej czynności, jak często jest niezbędne robienie czegoś, robienie tych rzeczy tak często jak trzeba i nie częściej, by jak najszybciej ponownie wykonać te pilne rzeczy. Więc przede wszystkim mierzenie czasu, czy już trzeba coś zrobić.

Jeśli program wszedł w C to oczywiście drukuje nowy stan i przy pierwszym wejściu tylko sobie zanotuje czasy, ustawi się na pierwszym elemencie menu i wychodzi, przy drugim sprawdzi czy wciśnięto jakiś przycisk, jak tak to coś zrobi, jak nie to tylko sprawdzi czy upłynęła sekunda, jak upłynęła sekunda to ją zliczy++, jak zliczy++>20, to wszystko tu wyzeruje i przełączy na B. Jak jednak zauważy przycisk IN to w kontekście miejsca gdzie jest, np. na menu0 wejdzie w edycję zmiennej menu0, przy następnych wejściach będzie wiedział, że tu jesteś bo sobie zapisał w zmiennej lokalnej static, że jest na pozycji menu0 i w drugiej że menu jest aktywne, wczyta do zmiennej pomocniczej int wartość menu0, jak przy kolejnym wejściu zauważy wciśnięcie + lub - to wyzeruje zliczanie czasu bezczynności w menu i zrobi akcję zmienna++ albo zmienna--, jak program będzie umiał obsługiwać długie wciśnięcie przycisku to nawet zmienna+=10 albo zmienna-=10, a potem i o 100. Jak znowu ktoś wciśnie IN, to te zmiany zapisze do menu0, jak ktoś jednak wciśnie OUT to program to porzuci zwalniając aktywność menu, a jak w ogóle zaniecha dalszych działań na 20s to program się wycofa, wyzeruje menu i przejdzie na drogę AB. Tak samo jak nie jest aktywna żadna pozycja menu wciśnięcie OUT spowoduje wyzerowanie zmiennych menu i powrót na drogę AB. Większość rzeczy można w menu zapisać w int, godzina i minuty dnia, można je zliczać 0-23, 0-59, albo w jednym int jako 0-1439, bo tyle jest różnych minut w ciągu doby (1440). Ktoś potrzebuje wyświetlić potem liczbę h:m to wystarczy minuty/60:minuty%60, sprintf to ładnie sformatuje by był to napis typu 00:00.

sprintf(napis,"%02d:%02d ",minuty/60,minuty%60,); - napis to powinna być cała linia do wyłania na LCD, nie będzie problemu jakiś artefaktów.

Jak  + - zostanie wciśnięty w kontekście nieaktywnego menu to program przesunie pozycję menu. 

Z kalendarzem można zrobić podobnie, jest prosty algorytm do wyguglania by ustalić czy rok jest przestępny, można sobie zapisać start na rok 2020, bo po co się bardziej cofać w czasie, rok ma 365 lub 366 dni, miesiąc ma 28, 29, 30 lub 31 dni, zmienna int wystarczy na zapis daty przez kolejnych 40 lat. I tak trzeba mieć tablicę z miesiącami by nie ustawić 31 listopada czy 30 luty, ale może tu faktycznie byłaby zbyt duża gimnastyka i prościej zrobić rok w bajcie, a tylko dni i miesiące w int.

Temperaturę z dokładnością do 0.01 (+/-160,00oC, większy zakres też, tylko już w int32_t)  też można zapisać w int, histerezę. Ty to możesz pokazać na menu jako 14.45oC, ale w zmiennej to będzie 1445 tylko wydrukowane sprintf tuż przed pokazaniem na ekran jako temp/100.temp%100.

A jak już ogarniesz, że wszystko (prawie) może być int to jako menu zrobisz sobie tablice int, przez index tablicy wczytasz tekst danej pozycji  z tablicy tekstów i zmienną do jej przechowywania z tablicy int -proste menu jednopoziomowe.

Można mieć też tablice funkcji jeśli zmienne w menu muszą być obsługiwane w bardziej finezyjny sposób niż ++/--.

No i sekcja B, jak jeszcze nie wiesz co tu przede wszystkim trzeba robić, to tak, trzeba mierzyć czas, by nie robić nic częściej niż jest to niezbędne.

No i jak teraz patrzę na twój program, to nigdzie nie mierzysz czasu. 

Z Google znajdziesz pewnie gotowce do tworzenia menu. Pierwsze co robię to test migania led, jeśli po wejściu w opcje menu moja testowa led przestaje migać co 100ms to taka biblioteka leci do kosza. Są menu na tablicach, w strukturach i inne wynalazki. Super jak jeszcze całość jest we flash.

Wg mnie jest to jeden z trudniejszych tematów w Arduino. Dużo prościej jest wysłać wszystkie parametry do programu linijką tekstu z terminala przez USB, albo z telefonu przez Bluetooth.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Udało mi się znaleźć znaleźć  pośrednie rozwiązanie  Wystarczyło dodać kolejne casy aby wpisać pierwsza i druga liczbę. Pytanie czy jest możliwość wpisania wartości dnia w jednym case ?  

#include <LiquidCrystal.h>

#include <Keypad.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3' , 'A'},
  {'4','5','6' , 'B'},
  {'7','8','9' , 'C'},
  {'*','0','#' , 'D'}
};
byte rowPins[ROWS] = {50, 51, 52, 53};  //Piny, do których podłączamy wyprowadzenia od rzędów
byte colPins[COLS] = {46, 47, 48 , 49}; //Piny, do których kolumn wyprowadzenia od rzędów

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
bool lock = 1;
bool lock1 = 1;
int A = 0;
int B = 0;
int C = 0;



int dzien, miesiac, rok, godzina, minuta;
int liczba_Wpisana; // zmienna potrzeba wyliczenia dnia

void setup()
{
  Serial.begin(9600);
  lcd.begin(16, 2);              
  lcd.setCursor(0, 0);
  lcd.print("Projekt Trakera"); 
}

void loop()
{
 // lcd.setCursor(9, 1);           
  //lcd.print(millis() / 1000);    
  


  //lcd.setCursor(0, 1);           
   char klawisz = keypad.getKey();
  
  
  switch (A)               
  {
    case 0: // 
    if(lock == 1)
      {
        
        lcd.clear();
      lcd.home();
      lock = 0;
      lcd.print("projekt trakera");
      lcd.setCursor(0, 1);
      lcd.print("BY Rafal & Damian");
      }
      if (klawisz == 'A'){
      A++;
      }
        break;
      
    case 1: // 
      if (lock == 0){
        
        
          lcd.clear();
          lcd.home();
          lock = 1;
          lcd.print("Ustawienie czasu");
      } 
      switch (C) //  wybór opcji z menu
      {
        case 0:
        if (lock1 == 1){
        lock1 = 0;
        }
        if(klawisz == 'C'){
        C++;
        }
        break;
      
                              case 1: //"dzien" pierwsza liczba
        
        if (lock1 == 0){
            lcd.clear();
            lcd.print("Dzien pierwsza liczba :");
            lcd.setCursor(0,1);
            lock1 = 1;
            
          }
      ustawienieDnia(klawisz);
     
      if(klawisz == 'C')
        C++;
        
        if (klawisz == 'D')
        C--;

       
        break;
                                  case 2: //"dzien" druga liczba
        if (lock1 == 1){
           lcd.clear();
            lcd.print("Dzien druga liczba :");
            lcd.setCursor(0,1);
            lock1 = 0;
      }
      ustawienie_Dnia1(klawisz,dzien);
      if(klawisz == 'C')
        C++;
        
        if (klawisz == 'D')
        C--;
        break;
      } // switch C
  } // switch A
} // loop

void ustawienieDnia(char klawisz)
{
  String liczba1; String cyfra;
        
        
         
          
           
            if(klawisz && klawisz != 'A' && klawisz != 'B' && klawisz != 'C' && klawisz != 'D' && klawisz != '#' && klawisz != '*'){
          
            
          lcd.print(klawisz);
          
          liczba1 = String(klawisz);

          cyfra.concat(liczba1);
          
          liczba_Wpisana = cyfra.toInt()*10; 
          Serial.println(liczba_Wpisana); // liczba wpisana
          return liczba_Wpisana;
          
          
}
}
  void ustawienie_Dnia1(char klawisz, int b) 
  {
      String liczba; String cyfra;     
         
          if ( klawisz && klawisz != 'A' && klawisz != 'B' && klawisz != 'C' && klawisz != 'D' && klawisz != '#' && klawisz != '*'){
           
           
            lcd.print(klawisz);
            liczba = String(klawisz);
            cyfra.concat(liczba);
            b = cyfra.toInt() + liczba_Wpisana; // b - liczba dnia zapisana jako dziesiątka
            
            Serial.println(b);
Cytat

No i jak teraz patrzę na twój program, to nigdzie nie mierzysz czasu. 

Ogólnie to piszę prace automatyzacji stacji fotowoltaicznej i potrzebna jest mi możliwość ustawiania daty aby zaprezentować ze w dany dzień i o danej godzinie panele będą się ustawiały prostopadle do słońca, a do mierzenia czasu mam dołożony moduł czasu rzeczywistego według którego panele w trybie automatycznym będą się poruszały. Dzięki za post, trochę rozjaśniło mi to sytuację i możliwe ze za jakiś czas jeszcze poprawie menu

Link do komentarza
Share on other sites

8 godzin temu, Felgrip napisał:

Wystarczyło dodać kolejne casy aby wpisać pierwsza i druga liczbę. Pytanie czy jest możliwość wpisania wartości dnia w jednym case ?  

Zanim pójdziesz dalej to poświęć trochę czasu, aby uporządkować formatowanie w tym programie - jak tego nie zrobisz to za jakiś czas sam się pogubisz. Nawet tutaj wyżej brakuje na końcu program się "urywa". Jak nie chcesz robić tego ręcznie to skorzystaj chociaż z opcji automatycznego formatowania w edytorze.

Zastanów się też ogólnie ile jeszcze rzeczy będzie później chciał tam ustawiać, bo może się okazać, że te klawiatura (w obecnej formie) będzie tylko utrudnieniem - gdybyś zdecydował się na 5 przycisków (typu zwiększ/zmniejsz/dalej/wstecz/zatwierdź) zamiast klawiatury to te programy byłyby właściwie dużo prostsze.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.