Rotary Encoder mit Wemos D1 mini

Hey Leute

Bin derzeit am Basteln mit meinem Wemos D1 mini und habe eine kleine Steuerung erschaffen mit der ich meine Beleuchtung Zeitlich Steuern kann. Jetzt habe ich zum einfachen Einstellen der Werte provisorisch drei einzelne Knöpfe eingebaut aber das Navigieren durch das Menü mit seinen Untermenüs ist recht frimelig.

Ich würde gerne einen Rotary Encoder (EC11) verwenden. Habe da paar rum liegen.
Jetzt habe ich es zwar geschafft diesen Endoder mithilfe von ErriezRotaryFullStep.h zum laufen zu bringen aber sobald ich alles in meiner Steuerung unterbringe liefert der Encoder keine Werte mehr (Zyklus passt anscheinend nicht zum auslesen).

Habe mich jetzt schon durch mehrere Themen gewälzt und sehe da einfach nicht mehr durch.

Ist es sinnvoller den Encoder über Interrupt auszulesen oder sollte ich lieber einen extra Arduino Pro mini /Wemos D1 mini zum Auslesen verwenden.

bin auf beiden gebieten noch Neuling.

Hallo,
das kommt mir seltsam vor. Du schreibst ja nicht genau was der Encoder machen soll, aber eigentlich willst Du mit dem Ding doch nur rauf und runter zählen. Und das nicht mal schnell. Also wenn Du im Rest Deines Sketches auf delay() verzichtest hast, sollte es doch keine Probleme geben. (Sangt mir meine Glaskugel).

Heinz

Mit der Standard Encoder-lib habe ich persönlich bei encodern mit mechanischen Kontakten schlechte Erfahrungen gemacht. Immer wenn ich die Drehrichtung umgekehrt habe wurden ein zwei Impulse verkehrt gezählt.

Die NewEncoder-lib benutzt eine Tabelle die sämtliche Zustände - auch so Zwischenzustände die bei Drehrichtungsumkehr an "ungünstiger" Stelle gemacht werden korrekt zählt. Die NewEncoder-Lib benutzt interrupts.

Am Wemos-Mini (=ESP98266) hat man mehr interrupts zur Verfügung als an einem Standard Arduino-Uno. Das was du beschreibst hört sich aber schon nach ungünstiger Programmierung an.
Wie wäre es wenn du mal deinen code so postest:

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

vgs

Danke für die schnellen Antworten.

Ja das habe ich vergessen zu schreiben Der Encoder ist nur zum Zählen da. also je nachdem ob ich halt nach links oder rechts drehe wird in dem Menü wo ich gerade bin ne einStellung geändert (So wie bei einem 3D Drucker wo man zwei Menüebenen hat und man im Untermenü den Punkt Temperatur hat wo man dann mit dem Encoder den Wert ändert.

Das mit dem Delay muss ich noch mal durchschauen aber ich programmiere eigentlich selten mit Delay.

Das mit der anderen Lib schaue ich mir bei Gelegenheit noch mal an das wäre vllt hilfreich. hoffentlich verstehe ich dann das Interrupt auch besser.

Der Code ist ziemlich lange. Aber hier mal die Loop und die wichtigen Funktionen

void loop() {
 rotaryState = rotary.read();
 if ((rotaryState > 0) || (rotaryState < 0)) {
     Serial.print(rotaryState);
     Serial.print("/");
     counter = counter + rotaryState;
     Serial.println(counter);
 }
   DateTime now = rtc.now();
 if (now.hour() == 3) {
   Sommer(); // Ermittelt ob Sommerzeit oder icht
 }
 button();  // Its für Encoder und Ausgänge schreiben zuständig
 //Wetter(); // Sendet Wetter an Webserver
 Menu();  // Navigation durch das Menü
 OLED();  // Anzeigewerte Im OLED Display
 Licht_1(); // Steuerung des Licht
 server.handleClient();
 //--------------------------------------------------------------------------------------------------------------------------------
 t = bme.temp();
 h = bme.hum();
 pa = bme.pres()*10;
}
void button() {
 // Read rotary state
 rotaryState = rotary.read();
 if (digitalRead(ROTARY_BUTTON_PIN) == 0) {
     // Reset count when rotary button is down
     if (ok[1] == 0) {
       ok[0] = 1;
     }else if (ok[0] == 1) {
       ok[0] = 0;
     }
   } else {
     ok[1] = 0;
   }

 if (pinD[4][1] == 1) { //Reserve
   pinD[4][2] = 0;
   pinD[4][3] = 1;
   digitalWrite(16, HIGH);
 } else if (pinD[4][2] == 1) {
   pinD[4][3] = 1;
   digitalWrite(16, HIGH);
 }else if (pinD[4][1] == 0 && pinD[4][2] == 0) {
   pinD[4][3] = 0;
   digitalWrite(16, LOW);
 }
 if (pinD[3][1] == 1) { // Beleuchtung ( pinD[3][1] von Licht_1// pinD[3][2] vom Webserver
   pinD[3][2] = 0;
   pinD[3][3] = 1;
   digitalWrite(D3, HIGH);
 } else if (pinD[3][2] == 1) {
   pinD[3][3] = 1;
   digitalWrite(D3, HIGH);
 } else if (pinD[3][1] == 0 && pinD[3][2] == 0) {
   pinD[3][3] = 0;
   digitalWrite(D3, LOW);
 }
 if (pinD[8][2] == 1) { // Impuls für ein Garagentor
   pinD[8][2] = 0;
   pinD[8][3] = 0;
   startTime = millis();
   while(millis() < (startTime + runTime)){
     digitalWrite(D8, HIGH);
   }
 } else if (pinD[8][2] == 0 && millis() > (startTime + runTime) ) {
   pinD[8][3] = 0;
   digitalWrite(D8, LOW);
 }
}
//----------------------------------------------------------------------------------------------------------
void Wetter(){
 int bar = bme.pres()*10;
Serial.println("\nStarting connection to server...");
 //Ausgabe ueber serielle Verbindung
 if (client.connect(host, 80)) {
   Serial.println("connected to server");
   Serial.println(host);
   client.print("GET http://api.weathercloud.net/set/wid/WID/key/KEY/temp/");  // /index.html durch gewuenschte Unterseite ersetzen (index.html = Startseite)
   client.print(bme.temp()*10);
   Serial.println(bme.temp()*10);
   client.print("/hum/");
   client.print(bme.hum());
   client.print("/bar/");
   client.println(bar);
   Serial.println(bme.pres());
   Serial.println(bar);
   }
}
//--------------------------------------------------------------------------------------------------------------------------------
void Menu(){
 rotaryState = rotary.read();
 if (ebenen[3] == 1) {   //Menu 1 & 2
   if (ebenen[2]== 1 && ebenen[1] == 1 && ok[0] == 1) {
     ebenen[1] = 2;
   }
   if (ebenen[2] == 1 && ebenen[1] > 1) {
     if ((rotaryState > 0) || (rotaryState < 0)) {
       ebenen[1] = ebenen[1] + rotaryState;
     } else if (ebenen[1] > 2 && ok[0] == 1) {
       ebenen[2] = 2;
     }
   }
   if (ebenen[2] == 2 ) {
     if ((rotaryState > 0) || (rotaryState < 0)) {
       ebenen[1] = ebenen[1] + rotaryState;
     } else if (ok[0] == 1) {
       ebenen[2] = 1;
     }
   }
   if (ebenen[2] > 2 ) {
     if ((rotaryState > 0) || (rotaryState < 0)) {
       ebenen[1] = ebenen[1] + rotaryState;
     } else if (ok[0] == 1) {
       ebenen[3] = 2;
     }
   }
 } else {                //Menu 3 (Referenswerte also Uhrzeiten und Helligkeit)
 switch (ebenen[1]) { 
void Licht_1() {
 adc3 = ads.readADC_SingleEnded(3);
 DateTime now = rtc.now();
 float Stunden_n = now.hour() + Sommer();
 float Minuten_n = now.minute();
 float Uhrzeit_n = Minuten_n +(Stunden_n*100);
 Zeite[2] = Zeite[1]+(Zeite[0]*100);      // Früh an
 Zeite[5] = Zeite[4]+(Zeite[3]*100);      // Früh aus
 Zeite[8] = Zeite[7]+(Zeite[6]*100);      // Abend an
 Zeite[11] = Zeite[10]+(Zeite[9]*100); //Abend aus
 for (int i = 3; i < (durchschnitt + 3); i++) { Messung von 2000 Messwerten und ermittelt          Durchschnitt
   if (i == 3) {
     hell[1] = 0;
   }
   hell[i] = (adc3 * multiplier); // adc3 = Analogwert vom Sensor 
   hell[1] = hell[1] + hell[i];
   hell[2] = hell[1]/durchschnitt;
 }
 if (Uhrzeit_n >= Zeite[2] && Uhrzeit_n <= Zeite[5]) {
   if (hell[2] <= hell[0]) {  // hell[0] = Schaltschwelle 


     pinD[3][1] = 1;
   }
   if (hell[2] >= hell[0] + 100) {
     pinD[3][1] = 0;
   }
 } else if (Uhrzeit_n >= Zeite[8] && Uhrzeit_n <= Zeite[11]) {
   if (hell[2] <= hell[0]) {
     pinD[3][1] = 1;
   }
 } else {
   pinD[3][1] = 0;
 }
}
//--------------------------------------------------------------------------------------------------------------------------------
int Sommer() {  // ermitteln ob Sommer oder Winterzeit
 DateTime now = rtc.now();
 int year = now.year();
 int month = now.month();
 int day = now.day();
 int hour = now.hour();
 int minute = now.minute();
 if (month<3 || month>10) {return 0;} // keine Sommerzeit in Jan, Feb, Nov, Dez
 if (month>3 && month<10) {return 1;} // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
 if (month==3 && (hour + 24 * day)>=(1 + minute + 24*(31 - (5 * year /4 + 4) % 7)) || month==10 && (hour + 24 * day)<(1 + minute + 24*(31 - (5 * year /4 + 1) % 7))) {
   return 1;
 } else {
  return 0;
 }
}

Hallo

hab jetzt nur mal kurz drüber gesehen, aber die while schleife blokiert ja so den Ablauf. Wenn Du in der Zeit am Encoder drehst bekommst Du das oben wo gezählt wird ja nicht mit.
Zudem solltst Du die Abfragen mit millis() grundsätzlich ändern sonst geht das bei einem überlauf von millis schief.

if( millis() - startTime > runTime)

erzeugt keinen Fehler.

Heinz

while-schleifen mit denen auf Zeit gewartet wird konterkarieren nicht-blockierendes Timing.

Die library NewEncoder ist sehr einfach zu benutzen. Dazu muss man noch nicht einmal interrupts verstehen, sie werden im Hintergrund benutzt.

Das einzige was man verstehen muss ist, dass der Encoder an IO-pins angeschlossen werden muss die Interrupt-fähig sind. Das ist aber beim ESP8266 für die meisten IO-pins der Fall.

hier ein Demo-Code
Das Abfragen des Encoders-Zählerstandes passiert in functio PrintEncoderVal()

#include "NewEncoder.h"

#define WeMosD1 5
#define WeMosD2 4

// Use FULL_PULSE for encoders that produce one complete quadrature pulse per detnet, such as: https://www.adafruit.com/product/377
// Use HALF_PULSE for endoders that produce one complete quadrature pulse for every two detents, such as: https://www.adafruit.com/product/377
// NewEncoder encoder(IO_Pin_A, IO_Pin_B, MinValue, MaxValue, InitialValue, HALF_PULSE); //HALF_PULSE FULL_PULSE
// On an ESP8266 WeMos D1 Mini all IO-Pins except GPIO15 and GPIO16 can be used
// GPIO2 is usable but has the onbard-LED connected
// GPIO0 can be used but will block flashing
// most usable IO-Pins: 4,5,12,13,14
// the interrupt based detection will catch all pulses
// but for a good user-experience polling the value should be done every 100 to 250 ms. 
NewEncoder myEncoder(WeMosD1, WeMosD2, -20, 20, 0, FULL_PULSE);

int16_t currentValue;


void PrintFileNameDateTime() {
  Serial.println("Code running comes from file ");
  Serial.println(__FILE__);
  Serial.print("  compiled ");
  Serial.print(__DATE__);
  Serial.print(" ");
  Serial.println(__TIME__);
}


boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false;            // not expired
}

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}



void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();
  int16_t value;

  Serial.println(F("Starting"));
  if (!myEncoder.begin()) {
    Serial.println(F("Encoder Failed to Start. Check pin assignments and available interrupts. Aborting."));
    while (1) {
    }
  } else {
    value = myEncoder;
    Serial.print(F("Encoder Successfully Started at value = "));
    Serial.println(value);
  }
}

void PrintEncoderVal() {
  currentValue = myEncoder.getValue();
  Serial.print(F("Encoder: "));
  Serial.println(currentValue);
}

void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 100);

  if ( TimePeriodIsOver(MyTestTimer, 250) ) {
    PrintEncoderVal();
  }
}

//ESP8266 WeMos D1 Mini Pinout
//
//                           antenna
//                       RST|    LED| TX = GPIO1
//           Analog 3.3V A0 |       | RX = GPIO3
//     not usable GPIO16 D0 |       | D1 = GPIO5 (I2C-SCL
// (SPI-Clock SCK)GPIO14 D5 | WeMos | D2 = GPIO4 (I2C-SDA)
//     (SPI-MISO) GPIO12 D6 | D1    | D3 = GPIO0 (Pullup) if connected during upload upload won't work
//      (SPI-MOSI)GPIO13 D7 | Mini  | D4 = GIOP2 LED Pullup
//     not usable GPIO15 D8 |       | GND
//                      3.3V|_______| 5V
//                             USB

vgs

Hallo,
ich kann dir nur empfehlen, die Library und den Testsketch (oder ein Beispiel aus der Lib) von StefanL38 zu verwenden.
Da gibt es keine Probleme und du wirst sehr schnell dein Projekt weiter führen können.

Hey Leute

Danke für eure Hilfe ich habe gerade mit dem Demo script rumgespielt und es funktioniert.
Das ist jetzt meckern auf hohem Nivea aber kann die Lib auch einen änderungswert ausgeben?
Also wenn mit euerm Beispiel experimentiere bekomme ich ja nen Wert zwischen -20 & 20 (bzw. ich ändere diese beiden werde)
kann man sich da auch nur die Änderung angeben lassen? Also für jedes Drehen ne zahl zwischen 1-3 in + und -

Wenn ich das Menü Wechsel beginnt bei mir ja jedesmal der Counter von vorne und ich kann zuvor nicht sagen wie weit ich zählen möchte.

Danke für eure Hilfe schon mal im Voraus :grinning:

Leider verstehe ich nicht genau, was du machen möchtest.
In der Lib kann das wohl nicht funktionieren, vermute aber, dass du es selbst programmieren kannst, so dass deine Anforderung danach funktionieren kann.

Naja ich habe aktuell ein Menü

  1. Startbildschirm
  2. Zurück
  3. Uhrzeiten
    1. Zurück
    2. Früh an
      1. Uhrzeit Früh an ( 6:00)
    3. Früh aus
      1. Uhrzeit Früh aus ( 7:00)
    4. Abend an
      1. Uhrzeit Abend an ( 19:00)
    5. Abend aus
      1. Uhrzeit Abend aus ( 22:00)
  4. Helligkeit
    1. Helligkeitsschwelle
      1. Schwellwert (100)
  5. Messungsanzahl
    1. Durchschnittsmenge
      1. Anzahl Messungen (2000)
  6. ...

Das Menü besteht aus einem Array zur Navigation

wenn ich auf dem Startbildschirm bin kann ich mit drehen vom Encoder ins 1. Hauptmenü.
-> Uhrzeiten ; Helligkeit; Messungsanzahl; ...

wenn ich da jetzt z.B. bis zu den Uhrzeiten möchte drehe ich zwei mal nach +
so komme ich im Menüpunkt 3.
wenn ich dort mit Knopfdruck bestätigen bin ich im Untermenü Uhrzeiten und möchte wieder bei 1 anfangen mit Zählen um dort ernst bis zum gewünschten Menüpunkt zu kommen.

Das ist doch auch machbar.
Du kennst doch an jeder Position den aktuellen Stand (Zahl der getätigten Pulse) und ziehst den Wert von deiner Zählvariablen ab und bist wieder bei 0.
Das machst du immer wo du es brauchst.

Hallo Klingedoler,

Die plus-Minus 20 sind einstellbare Grenzwerte. Wenn man in eine Richtung immer weiter dreht dann kann man einen Grenzwert einstellen.

die NewEncoder-Lib hat auch Funktionen downClick und upClick

Die liefern pro Impuls genau einmal den Wert true sonst false
viele Grüße Stefan

Das mit dem auf 0 zurück rechnen ist mir schon durch den Kopf geschwirrt wird aber schwer wenn man nicht weiß wie weit man drehen kann.

Aktuell habe ich einige Werte die ich in Summe auf 18000 Drehen kann und da ist das Menü nicht berücksichtigt.

Aktuell spiele ich bisl mit dem downClick und upClick rum

Vielen Danke

Da gibt es viele Möglichkeiten welche davon dann am geschicktesten zu deiner Menü-Funktionalität passt könnte man erst sagen wenn du mal dein Programm postest und sofern das ziemlich kryptisch mit vielen Arrays funktioniert auch noch eine Erklärung mitlieferst wie es funktioniert.

Du hast die Menüstruktur beschrieben. Aber wie sieht die Interaktion mit dem Benutzer aus? Hast du eine Art Markierzeichen das anzeigt in welcher Zeile man sich befindet?

Durch Drehen am Knopf wählt man die Zeile aus und dann wird ein Knopf gedrückt um den Menüpunkt auszuwählen.

Ein Konzept wäre vom Encoder wird einfach nur abgefragt linksherum oder rechtsherum am Knopf gedreht. Das wäre Upclick/Downclick und dann wird jeweils eine eigene Variable des Unter-Untermenüs eins rauf oder runtergezählt und dann das Menü neu ausgegeben mit der Kennzeichnung welcher Menüpunkt jetzt angewählt ist.

Beim Einstellen der Uhrzeiten genauso. Es gibt eine Variable Stunden die läuft von 0-23 im Kreis und eine für Minuten die läuft von 0-59 im Kreis. Immer dann wenn Maximum erreicht ist zurücksetzen auf 0, Wenn Minimum erreicht ist auf Maximum setzen.

Hm das wiederum könnte man in eine function reinsetzen der man als Parameter Min und Max übergibt.

Die function gibt den aktuellen Zählerstand zurück.
Wenn der Zählerwert größer gleich 1000 ist bleibt man in der Schleife zum Einstellen der Stunden/Minuten drin wenn der Zählerwert kleiner 1000 ist bedeutet das Einstellmodus Stunden/Minuten verlassen.

Beispiel: Stunden einstellen
Steht aktuell auf 7 soll auf 21 gestellt werden

function gibt 1007 zurück (>1000 = einstellen)
Man dreht nach rechts
1008
1009
1010...
1021 Taste zum Bestätigen verlassen wird gedrückt
function gibt 21 zurück
if (Rückgabe < 1000)
springe zu Minuten
negativen Rückgabewert könnte man als Abbruch geänderte Zahl nicht speichern benutzen.

Die andere Variante ist der function vier Parameter zu übergeben
Min,
Max,
einen Pointer auf die einzustellende Variable und
einen Pointer auf eine Statusvariable

mit der Statusvariable wird gesteuert ob man weiter einstellen will oder ob man bestätigt / abbgebrochen hat und zur nächsten Eingabe wechseln möchte.

Wenn ich die Funktionalität so allgemein beschreibe kannste dir das in etwa vorstellen wie man das programmiert? oder haste jetzt ein sich abwechselnd nach links / nach rechts drehendes Fragezeichen im Kopf?

viele Grüße Stefan

Hey Leute Danke für eure vielen hilfreichen Vorschläge.

Ja das habe ich allerdings :sweat_smile:

Hier mal die Funktion die mein Menü auf dem OLED ausgibt

void OLED(){
  DateTime now = rtc.now();
  display.clearDisplay();
  switch (ebenen[3]) {
    case 1:switch (ebenen[1]) {
      case 1:switch (ebenen[2]) {
              case 1: display.setCursor(40,20);
                      display.print("Home");
                      display.setCursor(35,40);
                      display.print(now.hour() + Sommer());
                      display.print(" : ");
                      if (now.minute() < 10) {
                        display.print("0");
                      }
                      display.print(now.minute());
                      if (pinD[7][1] == 1) {
                        display.setCursor(110,15);
                        display.print("^");
                      }
                      if (!bme.begin() || ! rtc.begin()){
                        display.setCursor(10,60);
                        display.print("No");
                        if (!bme.begin() ) {
                          display.setCursor(30,60);
                          display.print(" BME");
                        }if (! rtc.begin()) {
                          display.setCursor(70,60);
                          display.print(" RTC");
                        }

                      }


              break;
      }
      break;
      case 2:switch (ebenen[2]) {
              case 1: display.setCursor(05,15);
                      display.print("^");
                      display.setCursor(20,15);
                      display.print("zurueck");//<--
                      display.setCursor(20,30);
                      display.print("Uhrzeiten");
                      display.setCursor(20,45);
                      display.println("Helligkeit");
                      display.setCursor(20,60);
                      display.println("Durchschnitt");
              break;
      }
      break;
      case 3:switch (ebenen[2]) {
              case 1: display.setCursor(20,15);
                      display.print("zurueck");
                      display.setCursor(05,30);
                      display.print(">");
                      display.setCursor(20,30);
                      display.print("Uhrzeiten");//<--
                      display.setCursor(20,45);
                      display.println("Helligkeit");
                      display.setCursor(20,60);
                      display.println("Durchschnitt");
              break;
              case 2: display.setCursor(05,15);
                      display.print("^");
                      display.setCursor(20,15);
                      display.print("zurueck");//<--
                      display.setCursor(20,30);
                      display.print("Morgens an");
                      display.setCursor(20,45);
                      display.println("Morgens aus");
                      display.setCursor(20,60);
                      display.println("Abends an");
                      display.setCursor(20,75);
                      display.println("Abends aus");
              break;
              case 3: display.setCursor(20,15);
                      display.print("zurueck");
                      display.setCursor(05,30);
                      display.print(">");
                      display.setCursor(20,30);
                      display.print("Morgens an");//<--
                      display.setCursor(20,45);
                      display.println("Morgens aus");
                      display.setCursor(20,60);
                      display.println("Abends an");
                      display.setCursor(20,75);
                      display.println("Abends aus");
              break;
              case 4: display.setCursor(20,15);
                      display.print("zurueck");
                      display.setCursor(20,30);
                      display.print("Morgens an");
                      display.setCursor(05,45);
                      display.print(">");
                      display.setCursor(20,45);
                      display.println("Morgens aus");//<--
                      display.setCursor(20,60);
                      display.println("Abends an");
                      display.setCursor(20,75);
                      display.println("Abends aus");
              break;
              case 5: display.setCursor(20,0);
                      display.print("zurueck");
                      display.setCursor(20,15);
                      display.print("Morgens an");
                      display.setCursor(20,30);
                      display.println("Morgens aus");
                      display.setCursor(05,45);
                      display.print(">");
                      display.setCursor(20,45);
                      display.println("Abends an");//<--
                      display.setCursor(20,60);
                      display.println("Abends aus");
              break;
              case 6: display.setCursor(20,0);
                      display.print("zurueck");
                      display.setCursor(20,15);
                      display.print("Morgens an");
                      display.setCursor(20,30);
                      display.println("Morgens aus");
                      display.setCursor(20,45);
                      display.println("Abends an");
                      display.setCursor(05,60);
                      display.print(">");
                      display.setCursor(20,60);
                      display.println("Abends aus");//<--
              break;
            }
      break;
      case 4:switch (ebenen[2]) {
              case 1: display.setCursor(20,15);
                      display.print("zurueck");
                      display.setCursor(20,30);
                      display.print("Uhrzeiten");
                      display.setCursor(05,45);
                      display.print(">");
                      display.setCursor(20,45);
                      display.println("Helligkeit");//<--
                      display.setCursor(20,60);
                      display.println("Durchschnitt");
              break;
            }
      break;
      case 5:switch (ebenen[2]) {
              case 1: display.setCursor(20,0);
                      display.print("zurueck");
                      display.setCursor(20,15);
                      display.print("Uhrzeiten");
                      display.setCursor(20,30);
                      display.println("Helligkeit");
                      display.setCursor(05,45);
                      display.print(">");
                      display.setCursor(20,45);
                      display.println("Durchschnitt");//<--
                      display.setCursor(20,60);
                      display.println("Info");
              break;
            }
      break;
      case 6:switch (ebenen[2]) {
              case 1: display.setCursor(20,0);
                      display.print("zurueck");
                      display.setCursor(20,15);
                      display.print("Uhrzeiten");
                      display.setCursor(20,30);
                      display.println("Helligkeit");
                      display.setCursor(20,45);
                      display.println("Durchschnitt");
                      display.setCursor(05,60);
                      display.print(">");
                      display.setCursor(20,60);
                      display.println("Info");//<--
              break;
              case 2: display.setCursor(05,15);
                      display.print("^");
                      display.setCursor(20,15);
                      display.print("zurueck");//<--
                      display.setCursor(20,30);
                      display.print("IP");
                      display.setCursor(20,45);
                      display.println("SSID");
                      display.setCursor(20,60);
                      display.println("Letzter Start");
              break;
              case 3: display.setCursor(20,15);
                      display.print("zurueck");
                      display.setCursor(05,30);
                      display.print(">");
                      display.setCursor(20,30);
                      display.print("IP");//<--
                      display.setCursor(20,45);
                      display.println("SSID");
                      display.setCursor(20,60);
                      display.println("Letzter Start");
              break;
              case 4: display.setCursor(20,15);
                      display.print("zurueck");
                      display.setCursor(20,30);
                      display.print("IP");
                      display.setCursor(05,45);
                      display.print(">");
                      display.setCursor(20,45);
                      display.println("SSID");//<--
                      display.setCursor(20,60);
                      display.println("Letzter Start");
              break;
              case 5: display.setCursor(20,15);
                      display.print("zurueck");
                      display.setCursor(20,30);
                      display.print("IP");
                      display.setCursor(20,45);
                      display.println("SSID");
                      display.setCursor(05,60);
                      display.print(">");
                      display.setCursor(20,60);
                      display.println("Letzter Start");//<--
              break;
            }
      break;

    }
    break;
    case 2: switch (ebenen[1]) {
              case 3: switch (ebenen[2]) {
                        case 3: display.setCursor(20,25);
                                display.print("Morgen an");
                                display.setCursor(50,50);
                                display.print(Zeite[0]);
                                display.print(":");
                                display.print(Zeite[1]);
                                display.setCursor(40,60);
                                display.print("---");
                        break;
                        case 4: display.setCursor(20,25);
                                display.print("Morgen aus");
                                display.setCursor(50,50);
                                display.print(Zeite[3]);
                                display.print(":");
                                display.print(Zeite[4]);
                                display.setCursor(40,60);
                                display.print("---");
                        break;
                        case 5: display.setCursor(20,25);
                                display.print("Abend an");
                                display.setCursor(50,50);
                                display.print(Zeite[6]);
                                display.print(":");
                                display.print(Zeite[7]);
                                display.setCursor(40,60);
                                display.print("---");
                        break;
                        case 6: display.setCursor(20,25);
                                display.print("Abend aus");
                                display.setCursor(50,50);
                                display.print(Zeite[9]);
                                display.print(":");
                                display.print(Zeite[10]);
                                display.setCursor(40,60);
                                display.print("---");
                        break;
              }
              break;
              case 4: switch (ebenen[2]) {
                case 2: display.setCursor(25,15);
                        display.print("Schwelle");
                        display.setCursor(25,30);
                        display.print(hell[0]);
                        display.setCursor(20,45);
                        display.print("Lichtwert");
                        display.setCursor(50,60);
                        display.print(hell[2]);
                  break;
              }
              break;
              case 5: switch (ebenen[2]) {
                case 2: display.setCursor(20,30);
                        display.print("Durchschnitt");
                        display.setCursor(50,50);
                        display.print(durchschnitt);
                break;
              }
              break;
              case 6: switch (ebenen[2]) {
                case 3: display.setCursor(20,25);
                        display.print("IP");
                        display.setCursor(50,50);
                        //display.print(IP);
                break;
                case 4: display.setCursor(20,25);
                        display.print("SSID");
                        display.setCursor(50,50);
                        //display.print(ssid);
                break;
                case 5: display.setCursor(20,25);
                        display.print("Letzter Start");
                        display.setCursor(50,50);
                        //display.print(RST);
                break;
              }
              break;
    }
    break;
    case 3: switch (ebenen[1]) {
              case 1: switch (ebenen[2]) {
                case 1: display.setCursor(25,15);
                        display.print("Temperatur");
                        display.setCursor(25,30);
                        display.print(bme.temp());
                        display.setCursor(20,45);
                        display.print("Druck");
                        display.setCursor(50,60);
                        display.print(bme.pres());
                break;
              }
              break;
              case 3: switch (ebenen[2]) {
                        case 3: display.setCursor(20,25);
                                display.print("Morgen an");
                                display.setCursor(50,50);
                                display.print(Zeite[0]);
                                display.print(":");
                                display.print(Zeite[1]);
                                display.setCursor(65,60);
                                display.print("---");
                        break;
                        case 4: display.setCursor(20,25);
                                display.print("Morgen aus");
                                display.setCursor(50,50);
                                display.print(Zeite[3]);
                                display.print(":");
                                display.print(Zeite[4]);
                                display.setCursor(65,60);
                                display.print("---");
                        break;
                        case 5: display.setCursor(20,25);
                                display.print("Abend an");
                                display.setCursor(50,50);
                                display.print(Zeite[6]);
                                display.print(":");
                                display.print(Zeite[7]);
                                display.setCursor(65,60);
                                display.print("---");
                        break;
                        case 6: display.setCursor(20,25);
                                display.print("Abend aus");
                                display.setCursor(50,50);
                                display.print(Zeite[9]);
                                display.print(":");
                                display.print(Zeite[10]);
                                display.setCursor(65,60);
                                display.print("---");
                        break;
              }
              break;
              case 4: display.setCursor(25,15);
                      display.print("Schwelle");
                      display.setCursor(25,30);
                      display.print(hell[0]);
                      display.setCursor(20,45);
                      display.print("Lichtwert");
                      display.setCursor(50,60);
                      display.print(adc3 * multiplier);
                      display.setCursor(95,15);
                      display.print("*10");
              break;
              case 5: display.setCursor(20,30);
                      display.print("Durchschnitt");
                      display.setCursor(50,50);
                      display.print(durchschnitt);
                      display.setCursor(95,15);
                      display.print("*10");
              break;
    }
    break;
  }

  display.display();
}

und Nochmal der Code für das Navigieren im Menü

void Menu(){
  if (ebenen[3] == 1) {
    if (ebenen[2]== 1 && ebenen[1] == 1 && ok[0] == 1) {
      ebenen[1] = 2;
    }
    else if (ebenen[2] == 1 && ebenen[1] > 1) {
      if (click != 0) {
        ebenen[1] = ebenen[1] + click;
      }else if (ebenen[1] > 2 && ok[0] == 1 && ebenen[1] != 4 && ebenen[1] != 5) {
        ebenen[2] = 2;
      }else if ((ebenen[1] == 4 || ebenen[1] == 5) && ebenen[2] == 1) {
        if (ok[0] == 1) {
          ebenen[2] = 2;
          ebenen[3] = 2;
        }
      }
    }
    else if (ebenen[2] == 2 && ebenen[1] > 1 ) {
      if (click != 0) {
        ebenen[2] = ebenen[2] + click;
      } else if (ok[0] == 1 ) {
        ebenen[2] = 1;
      }
    }
    else if (ebenen[2] > 2 && ebenen[1] > 2) {
      if (click != 0) {
        ebenen[2] = ebenen[2] + click;
      } else if (ok[0] == 1) {
        ebenen[3] = 2;
      }
    }
  } else {                //Menu 3 (Referenswerte)
  switch (ebenen[1]) {
    case 1: switch (ebenen[2]) {
      case 1: switch (ebenen[3]) {
        case 2: if (ok[0] == 1) {
                  ebenen[3] = 1;
                }
      }
      break;
    }
    break;
    case 3: switch (ebenen[2]) {
      case 3: switch (ebenen[3]) {
                case 2: if (ok[0] == 1) {
                          ebenen[3] = 3;
                        }
                        if ((click > 0 && Zeite[0] <24)|| (click < 0 && Zeite[0] > 0) ) {
                          Zeite[0] = Zeite[0] + click;
                        }
                break;
                case 3: if (ok[0] == 1) {
                          ebenen[3] = 1;
                        }
                        if ((click != 0> 0 && Zeite[1] <60)|| (click != 0< 0 && Zeite[1] > 0) ) {
                          Zeite[1] = Zeite[1] + click;
                        }
                break;
              }

      break;
      case 4: switch (ebenen[3]) {
                case 2: if (ok[0] == 1) {
                          ebenen[3] = 3;
                        }
                        if ((click != 0> 0 && Zeite[3] <24)|| (click != 0< 0 && Zeite[3] > 0) ) {
                          Zeite[3] = Zeite[3] + click;
                        }
                break;
                case 3: if (ok[0] == 1) {
                          ebenen[3] = 1;
                          ebenen[2] = 1;
                        }
                        if ((click != 0> 0 && Zeite[4] < 60)|| (click != 0< 0 && Zeite[4] > 0) ) {
                          Zeite[4] = Zeite[4] + click;
                        }
                break;
              }
      break;
      case 5: switch (ebenen[3]) {
                case 2: if (ok[0] == 1) {
                          ebenen[3] = 3;
                        }
                        if ((click != 0> 0 && Zeite[6] <24)|| (click != 0< 0 && Zeite[6] > 0) ) {
                          Zeite[6] = Zeite[6] + click;
                        }
                break;
                case 3: if (ok[0] == 1) {
                          ebenen[3] = 1;
                          ebenen[2] = 1;
                        }
                        if ((click != 0> 0 && Zeite[7] <60)|| (click != 0< 0 && Zeite[7] > 0) ) {
                          Zeite[7] = Zeite[7] + click;
                        }
                break;
              }
      break;
      case 6: switch (ebenen[3]) {
                case 2: if (ok[0] == 1) {
                          ebenen[3] = 3;
                        }
                        if ((click != 0> 0 && Zeite[9] <24)|| (click != 0< 0 && Zeite[9] > 0) ) {
                          Zeite[9] = Zeite[9] + click;
                        }
                break;
                case 3: if (ok[0] == 1) {
                          ebenen[3] = 1;
                        }
                        if ((click != 0> 0 && Zeite[10] <60)|| (click != 0< 0 && Zeite[10] > 0) ) {
                          Zeite[10] = Zeite[10] + click;
                        }
                break;
              }
      break;
    }       // Uhrzeiten
    break;
    case 4:switch (ebenen[3]) {
                case 2: if (ok[0] == 1) {
                          ebenen[3] = 3;
                        }
                        if ((click != 0> 0) || (click != 0< 0 && hell[0] > 0) ) {
                          hell[0] = hell[0] + click;
                        }
                break;
                case 3:if (ok[0] == 1) {
                          ebenen[3] = 1;
                          ebenen[2] = 1;
                          pinD[7][1] = 0;
                        }
                        if ((click != 0> 0) || (click != 0< 0 && hell[0] > 0) ) {
                          hell[0] = hell[0] + click * 10;
                        }
                break;
              }   //Helligkeit
    break;
    case 5: switch (ebenen[3]) {
              case 2:if (ok[0] == 1) {
                      ebenen[3] = 3;
                     }
                    if ((click != 0> 0) || (click != 0< 0 && durchschnitt > 0) ) {
                      durchschnitt = durchschnitt + click;
                    }
                break;
              case 3:if (ok[0] == 1) {
                      ebenen[3] = 1;
                      ebenen[2] = 1;
                     }
                    if ((click != 0> 0) || (click != 0< 0 && durchschnitt > 0) ) {
                      durchschnitt = durchschnitt + click * 10;
                    }
                break;
            }
          break;//Info
  }
}
}

Aha.

noch mehr oha

Also gibt es schon eine funktionierende Navigation durch all diese Menüs, Untermenüs und Unter-Unter-Menüs?

Dann muss doch nur noch das bisherige Tastendrücken auf das Drehen des Encoders angepasst werden.

Ich werde mich jetzt bestimmt nicht so tief reinkniehen dass ich verstehe was es bedeutet wenn

ebenen[3]) {
                case 2: if (ok[0] == 1) {
                          ebenen[3] = 3;
                        }

sind.

ebene[3] usw. sind dermaßen nichtssagend - ne mach ich nicht.
Wenn es hier jemanden gibt dessen Lieblingshobby das Analysieren von dieser Art Kryptographie ist: Ran die Buletten!

Haste das selbst geschrieben? Meinste da blickste in einem halben Jahr noch durch?

Das mag ja auf eine bestimmte Art effizient sein Arrays zu verwenden
aber statt beschreibender Bezeichner einfach Zahlen verwenden das ist nur was für Zahlenmemory-Künstler.

Ich bin

char Erfinde_Laaange_SELBSTerklaernde_Bezeichner_Kuenstler

vgs

Ja am Menü hat bereits vor dem umrüsten funktioniert.
Ich habe mittlerweile versucht den Encoder einzubinden und scheine einigermaßen erfolg zu haben.

Die Verwendung von diesem einen Menü Array ist für mich selbsterklärend da jede Menüebene einer ebene im Array entspricht also
Hauptmenü ist ebenen[1]
Das Untermenü ist demzufolge ebenen[2]
und die Parameter liegen in der ebenen[3]

Das dient der dem Navigieren in dem Parameter
Ich stelle in dem Fall erst die Stunden und wenn ich ok Drücke komme ich zu den Minuten. Danach komme ich mit ok wieder uns Untermenü.

Ich komme damit erstaunlich gut zurecht und tüftel jetzt auch schon über ein halbes Jahr an dem Gesamtsystem

Ja und an der Stelle würde ich coden

void Menu(){
  if (ebenen[Parameter] == NameDesParameters) {
    if (ebenen[Untermenue] == NameDesMenues && ebenen[Hauptmenu] == NameDesMenues && ok[0] == 1) {
      ebenen[Untermenue] = NameDesUntermenue

Wenn man jetzt meine allgemeinplatznamen wie "NameDesUntermenue" durch einen passenden Namen ersetzt
erklärt sich alles von selbst

OK[0] die "0" könnte man auch durch einen selbsterklärenden Namen ersetzen. Ebenso was "1" bedeutet

Noch sinnvoller wäre statt eines arrays mit Ebene 1 bis 3
Menue1 und Menue2 zu haben und die Parameter in einen Array Parameter zu packen.

Aber das bleibt dir überlassen ob du das so umstricken willst.
Ich vermute mal wenn du mal ein halbes Jahr nicht mehr am Programm gerarbeitet hast dann wird es schwierig sich wieder an alle Details was ist Ebene[1] == 4 usw. zu erinnern.

vgs

Ich weiß jetzt nicht ob ich das was du mir empfiehlst richtig verstanden habe aber wenn ich deinem Tipp folgen möchte kann ich dann weiterhin mit Switch case arbeiten??

Habe vor einem Jahr einen LED Würfel gebaut und habe dort festgestellt das die Lösung mit switch Case deutlich schneller als if ist
sonst klingt deine Befürchtung Plausibel wenn ich keine Kommentare einfüge

Mein Plan ist sowieso das Programm wenn alles zu meiner Zufriedenstellung funktioniert aufzuräumen da wären ja paar Umstrukturierungen sinnvoll

Ja switch case funktioniert auch mit lauter Symbolnamen. Die Symbolnamen werden vom Compiler wieder in Zahlen übersetzt. Und bei Variablen wird der aktuelle Inhalt genommen. Konstanten werden auch wieder zur Zahl.

Welche Datenstruktur da am meisten Sinn macht weiß ich nicht. Dazu müsste ich den Gesamtablauf und die Gesamtfunktionalität kennen.

vgs