Go Down

Topic: Projekt: LCDMenuLib - LCD Menü mit mehreren Ebenen (4Bit/I2C/ShiftReg/...) (Read 93711 times) previous topic - next topic

Jomelo

Projekt: LCDMenuLib (LCDML)
Diese Dokumentation wird gerade erstellt, es existiert nur der erste Beitrag


 Aktuellste Version
Library:  Version 2.00 [20.06.2015]     Download
Doku: [21.06.2015]

Beschreibung:
Mit der LCDMenuLib kann ein Menü mit mehreren Ebenen erstellt werden. Aber nicht nur dass, die Lib bietet die Möglichkeit Menüfunktionen und Hintergrundfunktionen logisch voneinander zu trennen. Dazu gibt es die Displayebene und die Backendebene.
Auf der Displayeben wird das Menü angezeigt. Diese kann maximal 254 Menüelemente enthalten, welche sich in verschiedenen Ebenen nach dem Vorbild einer Baumstruktur anordnen lassen. Sprich es gibt einen Stamm, von dem verschiedene Äste (Sub Menüs) abgehen. Dieses Modell wird auch Nested Set Model genannt. Der Stamm des Menüs wird beim Anlegen der Lib generiert, alle Äste sind konfigurierbar. Werden in einer Ebene mehr Elemente verwendet als auf dem Display angezeigt werden können, wird ein Scrollbalken eingeblendet. Der Inhalt einer Menüfunktion wird nur dann aktualisiert, wenn ein Aktion ausgeführt wird. Eine Aktion kann das Drucken eines Buttons sein oder aber ein Trigger. Trigger können auf eine feste Zeit konfiguriert werden, so dass die Menüfunktion in einem Intervall von XX Millisekunden aktualisiert wird.  In der Menüfunktion sollte wenn möglich nur der Inhalt für das Display stehen oder die Verarbeitung der Buttons stattfinden. Es sollte hier niemals die „delay(x)" Funktion verwendet werden.
Hintergrundfunktionen, z.B. das Einsammeln von Daten über den Ethernet-Anschluss oder die Serielle Schnittstelle finden im Backendsystem statt unabhängig davon welcher Menüpunkt gerade aktiv ist. Im Backendsystem können Funktionen angelegt werden, die dauerhaft in einem Intervall laufen. Z.B. alle 5000 Millisekunden die Raumtemperatur auslesen.
Die Lib erzwingt eine Trennung des Display und des Backensystems, so dass mehr Ordnung beim Programmaufbau gegeben ist. Dies ermöglicht eine einfachere Wartung, nicht alles muss in einer Datei erstellt werden.
In den folgenden Kapiteln wird ein einfacher Einstieg in die Lib gegeben.

Wichtiges vorweg:
  • Falls ihr in eurem Programm die  „delay(x)" Funktion verwenden solltet, beantworte ich keine Fragen dazu. (Schaut euch bitte das „Blink without delay" Bespiel oder die Beispiel die bei der Lib dabei sind  an.
  • Ich beantworte keine Fragen per PN, zur Lib. Stellt eure Fragen bitte im Forum als Beitrag allen zur Verfügung, dann können auch alle von einer Lösung profitieren.

Inhaltsverzeichnis:
  • 1. Allgemein
  • 1.1.   Features
  • 1.2.    Bilder
  • 2. Displaysystem (Menüfunktionen)
  • 2.1.   Einleitung
  • 2.2.   Inbetriebnahme des ersten Beispiels
  • 2.3.   Anlegen von eigenen Menüfunktionen
  • 2.4.   Steuerungsmöglichkeiten (seriell, analog, digital, encoder, keypad, eigene)
  • 2.5.   Schnittstellen mit externen Libs(4bit / 8bit, i2c, shift register, doglcd)
  • 2.6.   alle existierenden Displayfunktionen
  • 3. Backendsystem (Hintergrundfunktionen)
  • 3.1.   Einleitung
  • 3.2.   Inbetriebnahme eines Beispiels
  • 3.3.   Anlegen von eigenen Backendfunktionen
  • 4. Beispiele
  • 4.1.   In der Lib enthalten
  • 4.2.   Von Usern erstellt
  • 5. Anhang
  • 5.1.   Links zu interessanten Projekten
  • 5.2.   Makros / Preprocessor / If in kurz
  • 5.3    Tester


1.1 Features
  • 254 Menüpunkte maximal (meistens begrenzt der Ram die Anzahl)
  • 254 Menüpunkte pro Ebene möglich / keine Begrenzungen bei der Ebenen Anzahl
  • Trennung von Struktur- und Funktionsebene durch mehrere Tabs
  • Leitfaden für den sauberen Programmaufbau / saubere Strukturierung
  • Ansteuerung über mindestens 3 Taster / Funktionen (up, down, enter), Encoder, Keypad
  • maximal 6 Taster werden unterstützt. (up, down, enter, quit/back, left, right)
  • Ansteuerung z.B. auch über Drehgeber oder andere Möglichkeiten möglich
  • InitScreen aktivierbar, dieser wird nach X Sekunden und/oder zu Beginn angezeigt
  • Scrollbalken aktivierbar
  • Scrollbalken wird nur angezeigt, wenn mehr Menüelemente wie Zeilen im Display vorhanden sind
  • Cursor Position wird gespeichert, nachdem eine Ebene zurückgegangen wird
  • Möglichkeit direkt zwischen Menüelementen hin und her zu springen
  • Möglichkeit die Menüelement ID abzufragen
  • normale LiquidCrystal Lib wird unterstützt
  • mit einer neueren LiquidCrystal Lib wird auch I2C und andere Schnittstellen unterstützt. Die folgende Lib wird benötigt: LiquidCrystal New 1.2.1 (funktioniert nur mit Arduino 1.0x. Für 1.6.x wird die Beta Version der externen Lib benötigt
  • DogLCD Unterstützung
  • Menüpunktbezeichnungen werden im Flash Speicher abgelegt
  • Funktioniert mit allen Arduino Version ab 1.0.xx
  • Windows / Linux / Mac
  • Es gibt ein Backendsystem für Hintergrundaufgaben, z.B. das Einsammeln von Messdaten
  • Es können maximal 255 Backendfunktionen angelegt werden
  • Backendfunktionen können in Gruppen zusammengefasst werden. Diese Gruppen lassen sich gleichzeitig stoppen oder Starten.
  • es werden keine graphischen Displays unterstützt


1.2 Bilder










Download          |          <-- erster Beitrag          |          weiter -->


Jomelo

Menufunktionen anlegen / Callback Funktionen

Alle Funktionen die nicht "FUNC" heißen werden vom Menü als Callback Funktionen aufgerufen. Diese Funktionen müssen angelegt werden. In dem Vorgegebenen Beispiel befinden sich ein paar dieser Funktionen im dritten Tab "LCDML_function". Jede Funktion muss mit dem gleichen Gerüst, welches unten anhand einer Dummy Funktion beschrieben wird, aufgebaut werden.
Code: [Select]

void FUNC_dummy(void)
  {  
    /* --------- INIT ---------
     * Initialisierung dieser Funktion
     * wird nur einmal beim Start dieser Funktion ausgefuert
     * danach nur erneut, wenn die Menu Funktion verlassen wurde
     * wenn keine Variablen initialisiert werden müssen, kann diese
     * Funktion anstatt mit if(!LCDML.FuncInit()) ....     mit
     * LCDML.FuncInit();  aufgerufen werden    
     */  
    if(!LCDML.FuncInit())
    {
      /* Init Function */          
    }
    /* --------- LOOP ----------
     * Hier sollte der Code stehen der ständig neu geladen wird
     * z.B. eine Uhrzeit oder änliches.
     */    
    
    /* --------- STOP  ---------      
     * LCDML.FuncEnd(direct, enter, up, down, left, right)
     * Falls in dieser Funktion keine Variablen zurückgesetzt werden
     * müssen, kann diese Funktion auch vereinfacht mit LCDML.FuncEnd(0, 1, 1, 1, 1, 1);
     * aufgerufen werden. Die Endbedingungen können durch 1 aktiviert oder 0 deaktiviert  
     * werden
     * Wenn alles 0 ist, hängt das gesammte Programm in dieser Funktion fest
     */
    if(LCDML.FuncEnd(0, 1, 1, 1, 1, 1))
    {
    /* Bei allen Parameter gilt bei '0': nichts machen.
      * Parameter 'direct':
      * Die Funktion wird direkt beendet ohne auf weitere Ereignisse zu warten
      * Parameter 'enter', 'up', 'down', 'left', 'right':
      *   Wenn z.B. 'enter' = 1 ist, muss einmal die Enter Taste gedrückt werden,
      *   damit die Funktion beendet wird.
      *   Wenn z.B. 'enter' = 2 ist, muss zweimal die Enter Taste gedrückt werden,
      *   damit die Funktion beendet wird.
      * Dieses gilt bei den anderen Buttons 'up', 'down', ... genauso.
      */

      /* Falls noch Variablen zurückgesetzt werden müssen, bevor diese Funktion
       * verlassen wird, kann dies in dieser If Schleife geschehen
       */
    }    
  }

angelegt werden.
Der Funktionsaufruf erfolgt automatisch, sobald der Menüpunkt mit "Enter" aufgerufen wird. Im Beispiel sind drei Funktionen hinterlegt, die Beispielcode beinhalten.


zu 8. Unterstützende Funktionen:
Delays würden den Programmablauf stören und zu unerwarteten Problemen führen. Aus diesem Grund wurden eine Hilf Funktionen hinzugefügt, die dies vermeiden soll.
Code: [Select]

// Delay without Delays
// Variable global anlegen unter  "Globale Variables"
unsigned long g_timer_xxBezeichnung = 0;

// In der Menufunktion
if(LCDML.Timer(g_timer_xxBezeichnung, 500)) {
  //quellcode wird nur alle 500 ms einmal ausgeführt
}

Wenn man mehrere Timer in verschiedenen Menu Funktionen benötigt, sollte man nicht für jede Funktion eine eigene unsigned long Variable anlegen, sondern die Timer z.B.  g_timer_func_1, g_timer_func_2  nennen und in mehreren Funktionen verwenden. Dies spart pro Variable 4Byte Ram.

Abfragen ob ein Button betätigt wurde:
Code: [Select]

if(LCDML.checkButtons()) {
  //irgend ein Button wurde betätigt
}


zu 9. Steuerungsmöglichkeiten:
Das jetzige Beispiel sieht die Steuerung über die Serielle Schnittstelle mit den Tasten  'a'=links, 's'=down, 'w'=up, 'd'=right, 'e'=enter und 'q' für quit/back/exit  vor (Button mode = 0). Alternative kann das Menü über eine Tastatur die über eine geschickte Widerstandswahl an einen analogen Eingang angeschlossen ist bedient werden. Hier können auch beliebige andere Steuerungsmöglichkeiten vorgesehen werden. Folgende Möglichkeiten wurden schon im Forum gesehen:
  • über eine IR Fernbedienung
  • mit einem KeyPadShild
  • über Netzwerk

Für die Entwicklung einer eigenen Steuerung gibt es die folgenden Funktionen:
Code: [Select]

LCDML.Button_enter();
LCDML.Button_up_down_left_right(_LCDMenuLib_button_up);
LCDML.Button_up_down_left_right(_LCDMenuLib_button_down);
LCDML.Button_up_down_left_right(_LCDMenuLib_button_left);
LCDML.Button_up_down_left_right(_LCDMenuLib_button_right);      
LCDML.Button_quit();

Im Beispiel befindet sich der Code ganz unten im ersten Tab. z.B. bei  ButtonMode_analog()

Die Ansteuerung mit LCDMenu_ButtonAnalog beinhaltet folgenden Code:
Code: [Select]

/* analog menu control */
void LCDMenuLib_control_analog()
{
  uint16_t value = analogRead(0);  // analogpin for keypad

  #define _BUTTON_analog_enter_min     850     // Button Enter
  #define _BUTTON_analog_enter_max     920  
  #define _BUTTON_analog_up_min        520     // Button Up
  #define _BUTTON_analog_up_max        590  
  #define _BUTTON_analog_down_min      700     // Button Down
  #define _BUTTON_analog_down_max      770  
  //optional if menu element "back" exists, look at FUNC_back in functions tab
  #define _BUTTON_analog_enable_quit   1
  #define _BUTTON_analog_back_min      950     // Button Back
  #define _BUTTON_analog_back_max      1020  
  //optional if needed
  #define _BUTTON_analog_enable_lr     1
  #define _BUTTON_analog_left_min      430     // Button Left
  #define _BUTTON_analog_left_max      500  
  #define _BUTTON_analog_right_min     610     // Button Right
  #define _BUTTON_analog_right_max     680  
      
  if(LCDML.Timer(g_LCDMenuLib_press_time, _LCDMenuLib_cfg_press_time)) {
    if(value >= _BUTTON_analog_enter_min && value <= _BUTTON_analog_enter_max) {        // control enter
      LCDML.Button_enter();
    }  
    else if(value >= _BUTTON_analog_up_min && value <= _BUTTON_analog_up_max) {      // control up
      LCDML.Button_up_down_left_right(_LCDMenuLib_button_up);
    }
    else if(value >= _BUTTON_analog_down_min && value <= _BUTTON_analog_down_max) {   // control down
      LCDML.Button_up_down_left_right(_LCDMenuLib_button_down);
    }    
    else if(value >= _BUTTON_analog_left_min && value <= _BUTTON_analog_left_max && _BUTTON_analog_enable_lr == 1) {   // control left
      LCDML.Button_up_down_left_right(_LCDMenuLib_button_left);
    }
    else if(value >= _BUTTON_analog_right_min && value <= _BUTTON_analog_right_max && _BUTTON_analog_enable_lr == 1) { // control right
      LCDML.Button_up_down_left_right(_LCDMenuLib_button_right);
    }
        
    if(value >= _BUTTON_analog_back_min && value <= _BUTTON_analog_back_max && _BUTTON_analog_enable_quit == 1) {          // control quit
      LCDML.Button_quit();
    }
  }
}


Wenn ihr z.B. nur mit vier Tastern (hoch, runter, links, rechts) euer Menü steuern wollt, dann passt die Funktion an und bindet die Änderung unter einem neuen Funktionsnamen in der Loop Schleife oberhalb der LCDMenuLib_loop() ein. Rechts kann auch = Enter sein und  Links = Quit. Die Standard Variante mit 6 Buttons wird von einem Makro in der Lib erzeugt. Eigene Anpassungen sollten kein Problem darstellen.

zu 10. Weitere Funktionen um gewisse Dinge Abzufragen:
Code: [Select]

LCDMenuLib_IS_reStartTime();   // restart initscreen wait time
LCDMenuLib_IS_startDirect(); // start initscreen direct
LCDMenuLib_getActiveFuncId() // get active function/menu element id

LCDML.getLayer()  // get the layer where the menu is now
LCDML.getInitScreenActive()  //



Ich hoffe dieses Tutorial hilft euch weiter.

Download: LCDMenuLib

Yeahuno

läuft mit ein paar Veränderungen  :D DANKE !!!!

Quote
// Einstellungen für das verwendete LCD (20x4)  
 #define _LCD_cols                          16
 #define _LCD_rows                          2

// Pin Belegung für das LCD
 #define _LCD_PIN_rs                        12
 #define _LCD_PIN_e                         11
 #define _LCD_PIN_dat4                      5
 #define _LCD_PIN_dat5                      4
 #define _LCD_PIN_dat6                      3
 #define _LCD_PIN_dat7                      2
 
// Der Button mode gibt an wie die Tastatur (Tastenfeld) angeschlossen werden sollen
// 0 = Keine Buttons verwenden (Steuerung über Serialmonitor)
//     (w = up, a = left, s = down, d = right, q = back, e = enter)
//    

// Der Button mode gibt an wie die Tastatur (Tastenfeld) angeschlossen werden sollen
// 0 = Keine Buttons verwenden (Steuerung über Serialmonitor)
//     (w = up, a = left, s = down, d = right, q = back, e = enter)
//     
// 1 = Einen Eingang und Auswertung über Bereiche
// 2 = Für jeden Button einen Eingang
  #define _BUTTON_MODE                       0




kurti

Hallo Jomelo,
allerherzlichsten Dank für die Projektvorstellung.

Gruss
Kurti
Zitat Jurs: falsche Verkabelung ist sowieso immer wenig förderlich für das Funktionieren der Hardware



hier könnte Ihre Werbung stehen

helix1

Hallo,

"WProgram.h" muss durch "arduino.h" ersetzt werden. Habe lange gesucht bevor ich als Neuling herausgefunden habe.
Gruss
helix1

Jomelo

Update:
- Ich habe die Library auch für die Arduino Version 1.0.1 brauchbar gemacht.

michael_x

Super, Jomelo.

Eine Frage zum Verständnis:
Du erzeugst Objekte vom Typ Menu, arbeitest aber meist mit den char* auf deren Texte. Hat das einen Grund ?
Falls der gleiche Text in verschiedenen Menu Objekten (z.B. auf verschiedenen Ebenen oder in verschiedenen Zweigen) auftaucht, bist du sicher, dass die zwei #define Anweisungen zwei unterschiedliche char* adressieren?

Code: [Select]
#define _LANG_MENU_setting1_2                     "Einstellungen"
#define _LANG_MENU_setting3_2                     "Einstellungen"

Menu Item1_2    (_LANG_MENU_setting1_2);
Menu Item3_2    (_LANG_MENU_setting3_2);

char * tmp =  _LANG_MENU_setting1_2;  // z.B.

if (tmp  == _LANG_MENU_setting3_2 ) {
// eine sicher nicht gewollte eventuelle Optimierung des Compilers
// wenn man hier landet
}





Für Uno (oder noch kleinere Arduinos), oder wenn der Arduino neben der Menu System Bedienung nebenbei noch möglichst viele dynamische Daten zwischenspeichern soll und/oder einen ganzen SD card block im RAM halten soll, oder ...,

... wäre es noch superer, wenn die konstanten Menü-Texte aus dem Flash genommen würden ...


Jomelo

Du erzeugst Objekte vom Typ Menu, arbeitest aber meist mit den char* auf deren Texte. Hat das einen Grund ?
Ich habe das damals so gewählt, da ich dann die einzelnen Menü Ebenen mir über die Serielle Schnittstelle auch direkt ausgeben lassen konnte.
Außerdem war es zum damaligen Zeitpunkt leichter texte miteinander zu vergleichen (vom Verständnis her).

Falls der gleiche Text in verschiedenen Menu Objekten (z.B. auf verschiedenen Ebenen oder in verschiedenen Zweigen) auftaucht, bist du sicher, dass die zwei #define Anweisungen zwei unterschiedliche char* adressieren?
So wie in deinem Beispiel funktioniert der Aufruf nicht. Ich nutze dazu einen array in dem jeweils der Name der nächst höheren Ebene steht. "funcname"

Beispiel:
Code: [Select]

#define _LANG_MENU_setting1_2                     "Einstellungen"
#define _LANG_MENU_setting3_2                     "Einstellungen"

Menu Item1_2    (_LANG_MENU_setting1_2);
Menu Item3_2    (_LANG_MENU_setting3_2);

char * tmp =  _LANG_MENU_setting1_2;  // z.B.

void BACK_SelectMenuFunction(void)
  {
    char *tmp;
      // Selbsthaltung der ausführenden Funktion falls gesetzt
      // HIER NICHTS ÄNDERN
      if(func_loop_name != NULL) {
        tmp = func_loop_name;
      } else {
        tmp = lcd_display.curfuncname;
      }         
       
      // AB HIER KÖNNEN ÄNDERUNGEN GEMACHT WERDEN
     
      //Nur Menupunkte die Ausgeführt werden können sollten hier drin stehen
      if(tmp == _LANG_MENU_setting1_2 && lcd_display.funcname[1] == "Ebene 1")
      {
               
      }
      else if(tmp == _LANG_MENU_setting3_2 && lcd_display.funcname[2] == "Ebene 2")
      {
               
      }

Die Bezeichnungen der Ebene stimmen zwar in dem Beispiel nicht, aber das Prinzip sollte deutlich werden.
Und zur Adressverwaltung vermute ich, dass die Inhalte nicht an der gleichen Stelle liegen, da sie auch in unterschiedlichen Objekten angelegt werden.

Die Erweiterung mit dem Flashspeicher ist eine gute Idee. Damit werde ich mich mal beschäftigen. Für mein damaliges Projekt reichte der Ram aus.



offtopic

Hallo Jomelo,
erstamals Vielen Dank für deine tolle Arbeit :)
Bei mir zeigt es leider keine Pfeile nach oben und nach unten, nur die Ziffern 0 (Pfeil nach oben?) und 1 (Pfeil nach unten?),
habe schon versucht was zu machen, aber als Anfänger komme ich nicht weiter =(
Ist es auch möglich dass, erstmal zB. Datum und Zeit angezeigt werden und erst beim OK drücken spring es ins Menü?
Grüße
Jurek

Jomelo

Hi,

das die Pfeile nicht angezeigt werden, liegt vermutlich am verwendeten Display oder aber daran, dass schon zuviele Benutzerdefinierte Zeichen für das Display belegt sind.

Du kannst das Display im Programm immer löschen und für eigene Zwecke verwenden.
Sobald du "lcd_display.display(); "  aufrufst, sollte das Menü wieder erscheinen.


offtopic

Hi,
leider komme ich nicht weiter...
Wenn ich über lcd.write() im loop die Pfeile anzeige funktioniert das, aber im Programm selbst nicht.
Ich habe ein UNO R3 und ein LCD Keypad shield von DFRobot. Mein IDE ist 1.0.1
Code: https://www.dropbox.com/s/ebh4pj9ou12608a/Kirys_menu.txt
An welche Stelle muss ich in meinem Beispiel die display_RTC() setzen?
Wenn ich das in loop mache überlappen sich der Zeit und das Menü  :~
Bitte um Hilfe

offtopic

Hallo,
gute Nachrichten  :)
dank den Tipp von Jamelo ist mir gelungen die Pfeile anzuzeigen.
Folgendes habe ich verändert:
in der Datei LCDMenu2.cpp
Zeilen von 199 bis 210, print auf write und die HEX weg
Code: [Select]

            if(curloc == 0) {
                lcd->setCursor((cols-1),(rows-1));
                lcd->write(arrow_down);
            }
            else if(curloc == j) {
                lcd->setCursor((cols-1),0);
                lcd->write(arrow_up);
            }
            else {
                lcd->setCursor((cols-1),0);
                lcd->write(arrow_up);

                lcd->setCursor((cols-1),(rows-1));
                lcd->write(arrow_down);

und in void setup()
Code: [Select]

lcd.createChar(0,arrow_up);
lcd.createChar(1,arrow_down);   


und dann funktioniert zumindest bei mir  ;)

offtopic

Ich verzweifle langsam, was ist an dem Code falsch :(
es funktionier einfach nicht
Code: [Select]

/* ===============================================
* SET DATE
* ===============================================
*/
void set_Date(char *func_name)
  {
    //CONTROL_refresh_button();
    t = rtc.getTime(); // Get data from the DS1307
    int tag, monat, jahr, pos;
    if (!CONTROL_set_func_active(func_name))
    {
      pos=0;
      tag=t.date;
      monat=t.mon;
      jahr=t.year;
      Serial.print(tag);
      Serial.print(monat);
      Serial.print(jahr);
      lcd.clear();
      lcd.setCursor(3,0);
      lcd.write("Set   date");
      lcd.setCursor(3,1);
      if (tag<10){lcd.print("0");}
      lcd.print(tag);
      lcd.write(".");
      if (monat<10){lcd.print("0");}
      lcd.print(monat);
      lcd.write(".");
      lcd.print(jahr);
    }
    if (menu_button_down == 1 && pos==0) //set tag-
      {
        if ((tag>1) && (tag<=31))
          {
            Serial.print(tag);
            Serial.print(" down ");
            delay(250);
            tag--;
            Serial.print(tag);
            menu_button_down=0;
            if (tag<10) {lcd.setCursor(3,1);lcd.print("0");lcd.print(tag);}
            else {lcd.setCursor(3,1);lcd.print(tag);}
            lcd.setCursor(3,1);
            lcd.blink();
          }
      }
    if (menu_button_up == 1 && pos==0)  //set tag+
      {
        if ((tag<31) && (tag>=1))
          {
            Serial.print(tag);
            Serial.print(" up ");
            delay(250);
            tag++;
            Serial.print(tag);
            menu_button_up=0;
            if (tag<10) {lcd.setCursor(3,1);lcd.print("0");lcd.print(tag);}
            else {lcd.setCursor(3,1);lcd.print(tag);}
            lcd.setCursor(3,1);
            lcd.blink();
          }
      }
    if (menu_button_up == 1 && pos==1)  //set monat+
      {
        if ((monat<12) && (monat>=1))
          {
            Serial.print(monat);
            Serial.print(" up ");
            delay(250);
            monat++;
            Serial.print(monat);
            menu_button_up=0;
            if (monat<10) {lcd.setCursor(6,1);lcd.print("0");lcd.print(monat);}
            else {lcd.setCursor(6,1);lcd.print(monat);}
            lcd.setCursor(6,1);
            lcd.blink();
          }
      }
    if (menu_button_down == 1 && pos==1)  //set monat-
      {
        if ((monat<=12) && (monat>1))
          {
            Serial.print(monat);
            Serial.print(" down ");
            delay(250);
            monat--;
            Serial.print(monat);
            menu_button_down=0;
            if (monat<10) {lcd.setCursor(6,1);lcd.print("0");lcd.print(monat);}
            else {lcd.setCursor(6,1);lcd.print(monat);}
            lcd.setCursor(6,1);
            lcd.blink();
          }
      }
    if (menu_button_up == 1 && pos==2)  //set jahr+
      {
        if (jahr<2100 && jahr>=2000)
          {
            Serial.print(jahr);
            Serial.print(" up ");
            delay(250);
            jahr++;
            Serial.print(jahr);
            menu_button_up=0;
            lcd.setCursor(9,1);
            lcd.blink();
            lcd.print(jahr);
          }
      }
    if (menu_button_down == 1 && pos==2)  //set jahr-
      {
        if ((jahr<=2100) && (jahr>2000))
          {
            Serial.print(jahr);
            Serial.print(" down ");
            delay(250);
            jahr--;
            Serial.print(jahr);
            menu_button_down=0;
            lcd.setCursor(6,1);
            lcd.blink();
            lcd.print(jahr);
          }
      }
    if (menu_button_right == 1)
    {
      pos++;
      if (pos>3)
      {
        pos=0;
      }
    }
    // CONTROL_func_end (direct, enter, up, down, left, right)
    CONTROL_set_func_end(0, 1, 0, 0, 0, 0);
  }

Jomelo


offtopic

Es soll über LCD Display und  Keypad Shield Tasten das Datum einstellen.
Es fehlt noch am ende der Befehl
Code: [Select]

rtc.setDate(tag, monat, jahr);

ich wollte, sätzen des Datums mit enter bestätigen und auch beenden.
Wie etwa:
Code: [Select]

if (menu_button_enter == 1)
{
rtc.setDate(tag, monat, jahr);
CONTROL_set_func_end(0, 1, 0, 0, 0, 0);
}

Leider wenn ich diese Code ausführe passiert nichts, es werden keine tasten erfasst (außer back)
dafür habe ich mir die Ereignise im Serial anzeigen lassen. Es wird nichts angezeigt :(
Variable "pos" sagt ob ein Tag, Monat oder Jahr zu stellen ist (0 - Tag, 1 - Monat, 2 - Jahr) und dort soll auch der Blinkcursor stehen.
Tasten nach oben und nach unten sollen den jeweiligen Wert ändern.
Der Hauptcode kommt von deinem Beispiel, ich habe nur das Menü (läuft Prima) und die ausführende Funktionen verändert.
Gruß
offtopic

Go Up