LCD Menu, Analogwerte in Echtzzeit

Hallo Forum,

ich beschäftige, mich erst seit einiger Zeit mit dem Arduino und der Programmierung. Nun habe ich ein Problem, bei meinem ersten eigenen Projekt.

Ich lade mal den ganzen Code und beschreibe mein Problem, in dem Programmabschnitt wo ich Probleme habe.

Ich habe drei Poti. Ein Poti für Rot, ein Poti für Blau und ein Poti für Grün. Mit diesen Potis mache ich die Farbmischung bei einem LED Streifen. Das Funktioniert auch. Zeit gleich lasse ich mir den eingestellt Wert auf meinen LCD Bildschirm anzeigen (wo man sich durch ein Menu klickt), das funktioniert auch.

Nun mein Problem. Ich möchte gerne, wenn ich in dem Menu "LED Farbenwert" bin, das sich der Potiwert aktualisiert, wenn ich einen der Potis drehe. Also auf den aktuellen Wert.

Zur Zeit ist es so. Ich gehe in das Menu "LED Farbenwert" dort steht dann, der zuletzt eingestellt Wert. Wenn ich noch im Menu bin und an einem Poti drehe verändert sich nicht der Wert auf dem LCD und der LED Streifen verändert auch nicht seine Farbe. Erst nach 5 sec. wenn das Menu automatisch zum Anfang springt.

Die Funktion die Probleme macht ist "void action 1", denke ich.

Ich denke mal, es liegt am delay(). Soweit ich rausgefunden habe.

Mit millis() bekomme ich leider auch keinen verknüfitgen Code zu stande.

Vielleicht hat ja noch jemand eine Idee. Vielleicht die Abfrage der Farbmischung in einer neuen "Funktion" ???

Gerne, bin ich auch Tipps für meine Code dankbar um ihn besser oder schlanker zu machen. Ich lerne gerne neue Sachen dazu.

Hoffe es ist verständlich.

p.s.

diesen Code habe ich für das Menu verwendet und auf meine bedürfnisse angepasst.

Nun mein Code.

// ****************************************************************************
// constants won't change. They're used here to set pin numbers:
//                                INPUTS
// **************************************************************************** 

const int switch_1 = 22;      // the number of the switch pin
const int switch_2 = 23;    // the number of the switch pin
//const int switch_3 = 24;    // the number of the switch pin
//const int switch_4 = 25;
//const int relai1_ON = 26;   // the number of the relai NO
//const int relai2_ON = 27;   // the number of the relai NO
const int selectButton = 39;  //Taster vom Drehpoti

// ****************************************************************************
//                                ANALOG INPUTS
// ****************************************************************************

const int potiDimmer = A0;    // Schieberegler
const int potiMixing_R = A1;  // Drehpoti
const int potiMixing_G = A2;  // Drehpoti
const int potiMixing_B = A3;  // Drehpoti

// ****************************************************************************
//                                OUTPUTS
// ****************************************************************************

const int LED_1R = 35;
const int LED_1G = 34;
const int LED_1B = 36;
const int LED_2R = 37;
const int LED_2G = 49;
const int LED_2B = 48;
//const int LED_3R = 47;
//const int LED_3G = 46;
//const int LED_3B = 45;
//const int LED_4R = 44;
//const int LED_4G = 43;
//const int LED_4B = 42;
//const int relai1_A1 = 41;   // relai coil A1
//const int relai2_A1 = 40;   // relai coil A1
// ****************************************************************************
//                                VARIABLES will change
// **************************************************************************** 

int switchState1 =    0;         // variable for reading the switch status
int switchState2 =    0;         // variable for reading the switch status
int switchState3 =    0;         // variable for reading the switch status
int switchState4 =    0;         // variable for reading the switch status
int relaiState1 =     0;          // variable for reading the relai status
int relaiState2 =     0;          // variable for reading the relai status

int potiValve_Sch =   0;        // valve from Schieberegler
int potiValve_R =     0;          // valve from Poti
int potiValve_G =     0;          // valve from Poti
int potiValve_B =     0;          // valve from Poti

int valveMixing_R =   0;        // valve for mixing
int valveMixing_G =   0;        // valve for mixing
int valveMixing_B =   0;        // valve for mixing
int valveBrightness = 0;      // valve for Brightness


//unsigned long startTime = 0;
//unsigned long currentTime = 0;
//const unsigned long pause = 5000;

// ****************************************************************************
//                                LED Streifen
// ****************************************************************************
#include <Adafruit_NeoPixel.h>

#define LED_COUNT 130  //247
#define LED_PIN 2
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

// ****************************************************************************
//                                RFID
// ****************************************************************************

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN   5     // SPI Reset Pin    
#define SS_PIN    53    // SPI Slave Select 
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Instanz des MFRC522 erzeugen

byte M_uid[] = {0xFD, 0x49, 0x02, 0x89};     // Chip, Marcel, Farbe Grün
byte J_uid[] = {0xC0, 0x81, 0x2B, 0xA8};      //Karte, Janine, Farbe Pink

int M_uid_check = false;
int J_uid_check = false;

// ****************************************************************************
//                                LCD
// ****************************************************************************
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

int menu = 1;             //merkt sich in welchem menu wir gerade sind, startpunkt ist das erste menu

// ****************************************************************************
//                                KY-040
// ****************************************************************************

#define encoderPinA 19     //CLK
#define encoderPinB 18     //DT

volatile unsigned int encoderPos = 0;  // a counter for the dial
unsigned int lastReportedPos = 1;   // change management
static boolean rotating=false;      // debounce management

// interrupt service routine vars
boolean A_set = false;            
boolean B_set = false;

// ****************************************************************************
//                                DS3231 Uhr
// ****************************************************************************

#include "RTClib.h"

RTC_DS3231 rtc;



// ****************************************************************************
//                                Setup
// ****************************************************************************

void setup() {

// ****************************************************************************
//                                RFID
// ****************************************************************************
  Serial.begin(9600);     // Serielle Kommunikation mit dem PC initialisieren
  SPI.begin();         // Initialisiere SPI Kommunikation
  mfrc522.PCD_Init();  // Initialisiere MFRC522 Lesemodul

// ****************************************************************************
//                                LCD
// ****************************************************************************

  lcd.begin();
  //lcd.backlight();
  updateMenu();         // damit der bildschirm, erstmalig mit dem menu gefüllt wird.
  pinMode(encoderPinA, INPUT); 
  pinMode(encoderPinB, INPUT);
  pinMode(selectButton, INPUT_PULLUP);
  digitalWrite(encoderPinA, HIGH);  // turn on pullup resistors
  digitalWrite(encoderPinB, HIGH);  // turn on pullup resistors
  attachInterrupt(0, doEncoderA, CHANGE); // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(1, doEncoderB, CHANGE); // encoder pin on interrupt 1 (pin 3)

// ****************************************************************************
//                                LED
// ****************************************************************************

  strip.begin();

// ****************************************************************************
//                                DS3231 Uhr
// ****************************************************************************

  rtc.begin();

  //wenn Datum und Zeit nicht korrekt -> Datum/Zeit setzen
  //Jahr, Monat, Tag, Stunde, Minute, Sekunde
  //rtc.adjust(DateTime(2025, 4, 10, 17, 25, 30));

// ****************************************************************************
//                                PIN MODE
// ****************************************************************************

  pinMode(switch_1, INPUT);
  pinMode(switch_2, INPUT);
  //pinMode(switch_3, INPUT);
  //pinMode(switch_4, INPUT);
  //pinMode(relai1_ON, INPUT);
  //pinMode(relai2_ON, INPUT);
  
  pinMode(LED_1R, OUTPUT);
  pinMode(LED_1G, OUTPUT);
  pinMode(LED_1B, OUTPUT);
  pinMode(LED_2R, OUTPUT);
  pinMode(LED_2G, OUTPUT);
  pinMode(LED_2B, OUTPUT);
  //pinMode(LED_3R, OUTPUT);
  //pinMode(LED_3G, OUTPUT);
  //pinMode(LED_3B, OUTPUT);
  //pinMode(LED_4R, OUTPUT);
  //pinMode(LED_4G, OUTPUT);
  //pinMode(LED_4B, OUTPUT);
  //pinMode(relai1_A1, OUTPUT);
  //pinMode(relai2_A1, OUTPUT);

  //startTime = millis();
}

// ****************************************************************************
//                                Loop
// ****************************************************************************

void loop() { // Diese Funktion wird in Endlosschleife ausgeführt
  
// ****************************************************************************
//                                RFID
// ****************************************************************************

  // Nur wenn eine Karte gefunden wird und gelesen werden konnte, wird der Inhalt von IF ausgeführt
  // PICC = proximity integrated circuit card = kontaktlose Chipkarte
  if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial() ) {
    Serial.print("Gelesene UID:");
    for (byte i = 0; i < mfrc522.uid.size; i++) {
      // Abstand zwischen HEX-Zahlen und führende Null bei Byte < 16
      Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
      Serial.print(mfrc522.uid.uidByte[i], HEX);
    } 
    
    // UID Vergleichen mit M_uid
    M_uid_check = true;
    for (int j=0; j<4; j++) {
      if (mfrc522.uid.uidByte[j] != M_uid[j]) {
        M_uid_check = false;
      }
    }
  
    // UID Vergleichen mit J_uid
    J_uid_check = true;
    for (int j=0; j<4; j++) {
      if (mfrc522.uid.uidByte[j] != J_uid[j]) {
        J_uid_check = false;
      }
    }
  
    if (M_uid_check) {
      lcd.clear();
      lcd.print("Hallo M");
      // Fill along the length of the strip in various colors...
      colorWipe(strip.Color(  0, 255, 0), 50); // Blue
      //updateMenu();
    }
    
    if (J_uid_check) {
      lcd.clear();
      lcd.print("Hallo J");
      // Fill along the length of the strip in various colors...
      colorWipe(strip.Color(  255, 0, 255), 50); // Purple
      //updateMenu(); 
    }

    // Versetzt die gelesene Karte in einen Ruhemodus, um nach anderen Karten suchen zu können.
    mfrc522.PICC_HaltA();
    delay(1000);

    // Versetzt die gelesene Karte in einen Ruhemodus, um nach anderen Karten suchen zu können.
    mfrc522.PICC_HaltA();
    delay(1000);
  }

// ****************************************************************************
//                                KY-040
// ****************************************************************************

  if (!digitalRead(encoderPinA)){
    menu++;
    updateMenu();
    delay(100);   // fürs debouncen
    while (!digitalRead(encoderPinA));  // damit man nicht weiter scrollt, wenn man die taste zulande drückt
  }
  if (!digitalRead(encoderPinB)){
    menu--;
    updateMenu();
    delay(100);   // fürs debouncen
    while(!digitalRead(encoderPinB));    // damit man nicht weiter scrollt, wenn man die taste zulande drückt
  }
  if (!digitalRead(selectButton)){
    executeAction();
    updateMenu();
    delay(100);   // fürs debouncen
    while (!digitalRead(selectButton));   // damit man nicht weiter scrollt, wenn man die taste zulande drückt
  }

  rotating = true;  // reset the debouncer

// ****************************************************************************
//                                DS3231
// ****************************************************************************
/*
DateTime aktuell = rtc.now();

// Datum anzeigen
  lcd.setCursor(0, 0);
  //char Datum[] = "Datum: DD.MM.YY";
  char Datum[] = "DD.MM.YY";
  lcd.print(aktuell.toString(Datum));

  // Zeit anzeigen
  lcd.setCursor(4, 1);
  char Zeit[] = "hh:mm:ss";
  lcd.print(aktuell.toString(Zeit));

  // gemessene Temperatur in String umwandeln
  String Temperatur = String(rtc.getTemperature());
  // angelsächsische Schreibweise der Temperatur
  // . durch , ersetzen
  //Temperatur.replace(".", ",");
  lcd.setCursor(9, 0);
  // Sonderzeichen für ° = \337
  // Temperatur anzeigen
  //lcd.print("Temperatur: " + Temperatur + "\337C");
  lcd.print(Temperatur);
  lcd.print("\337C");
  
  //delay(1000);
*/
// ****************************************************************************
//                                sdfsf
// ****************************************************************************

  //Serial.println("Helligkeit");
  //Serial.println(valveBrightness);
  //Serial.println("Farbe ROT");
  //Serial.println(valveMixing_R);
  //Serial.println(potiValve_R);
  //Serial.println("Farbe GRUEN");
  //Serial.println(valveMixing_G);
  //Serial.println("Farbe BLAU");
  //Serial.println(valveMixing_B);


  // LED Streifen Dimmen
  potiValve_Sch = analogRead(potiDimmer);
  valveBrightness = map(potiValve_Sch, 0, 1023, 0, 255);
  //lcd.setCursor(2,0);       //position auf dem Display: 2 pixel von links, obere Reihe
  //lcd.print("Brightness:");
  //lcd.setCursor(6,1);       //position auf dem Display: 6Pixel von links, untere Reihe
  //lcd.print(valveBrightness);

  // LED Streifen Farbe Rot
  potiValve_R = analogRead(potiMixing_R);
  valveMixing_R = map(potiValve_R, 0, 1023, 0, 255);
  //lcd.setCursor(0,0);
  //lcd.print("R: ");
  //lcd.print(valveMixing_R);
  
  // LED Streifen Farbe Grün
  potiValve_G = analogRead(potiMixing_G);
  valveMixing_G = map(potiValve_G, 0, 1023, 0, 255);
  //lcd.setCursor(0,1);
  //lcd.print("G: ");
  //lcd.print(valveMixing_G);
  
  // LED Streifen Farbe Blau
  potiValve_B = analogRead(potiMixing_B);
  valveMixing_B = map(potiValve_B, 0, 1023, 0, 255);
  //lcd.setCursor(10,0);
  //lcd.print("B: ");
  //lcd.print(valveMixing_B);
  
  // read the state of the switch value:
  
  switchState1  = digitalRead(switch_1);
  switchState2  = digitalRead(switch_2);
  //switchState3  = digitalRead(switch_3);
  //switchState4  = digitalRead(switch_4);
  //relaiState1 = digitalRead(relai1_ON);
  //relaiState2 = digitalRead(relai2_ON);
  
  // check if the switch is on. If it is, the switchState is HIGH:
  if (switchState1 == HIGH) {
    // turn on:
    digitalWrite(LED_1G, HIGH);
    digitalWrite(LED_1R, LOW);
  } else {
    // turn off:
    digitalWrite(LED_1G, LOW);
    digitalWrite(LED_1R, HIGH);  
  }
  
  // LED Streifen an und Dimmen
  if (switchState2 == HIGH) {
    // turn on:
    digitalWrite(LED_2G, HIGH);
    digitalWrite(LED_2R, LOW);
  
    strip.fill(strip.Color(valveMixing_R, valveMixing_G, valveMixing_B),0, 130);
    strip.setBrightness(valveBrightness);
    strip.show();  // Send the updated pixel colors to the Hardware
  
   } else {
    // turn off:
    digitalWrite(LED_2G, LOW);
    digitalWrite(LED_2R, HIGH);

    strip.clear(); 
    strip.show();
    }


  //currentTime = millis();
}

// ****************************************************************************
//                                UNTERPROGRAMM LED STREIFEN
// ****************************************************************************


void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

// ****************************************************************************
//                                UNTERPROGRAMM LCD
// ****************************************************************************

// wird aus geführt, wenn ein button up oder down betätigt wurde
void updateMenu() {
  switch (menu) {
    case 0:
      menu = 1;
      break;
    case 1:
      lcd.clear();
      lcd.print(">LED Farbenwert");
      lcd.setCursor(0, 1);
      lcd.print(" LED Helligkeit");
      break;
    case 2:
      lcd.clear();
      lcd.print(" LED Farbenwert");
      lcd.setCursor(0, 1);
      lcd.print(">LED Helligkeit");
      break;
    case 3:
      lcd.clear();
      lcd.print(">Temperatur");
      lcd.setCursor(0, 1);
      lcd.print(" MenuItem4");
      break;
    case 4:
      lcd.clear();
      lcd.print(" Temperatur");
      lcd.setCursor(0, 1);
      lcd.print(">MenuItem4");
      break;
    case 5:
      menu = 4;
      break;
  }
}

// wird aufgerufen wenn die selecttaste gedrückt wurde
void executeAction() {
  switch (menu) {
    case 1:
      action1();
      break;
    case 2:
      action2();
      break;
    case 3:
      action3();
      break;
    case 4:
      action4();
      break;
  }
}

// das sind die aktion die passieren sollen 

void action1() {
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("R: ");
  lcd.print(valveMixing_R);
  lcd.setCursor(0,1);
  lcd.print("G: ");
  lcd.print(valveMixing_G);
  lcd.setCursor(10,0);
  lcd.print("B: ");
  lcd.print(valveMixing_B);
  delay(5000);
  

  /*
  //unsigned long startTime;
  //unsigned long currentTime;
  //const unsigned long pause =5000;
  //startTime = millis();
  //unsigned long currentTime = millis();
  if (currentTime - startTime >= pause){
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("R: ");
  lcd.print(valveMixing_R);
  lcd.setCursor(0,1);
  lcd.print("G: ");
  lcd.print(valveMixing_G);
  lcd.setCursor(10,0);
  lcd.print("B: ");
  lcd.print(valveMixing_B);

  startTime = currentTime;
  }
  */
}
void action2() {
  lcd.clear();
  lcd.setCursor(2,0);       //position auf dem Display: 2 pixel von links, obere Reihe
  lcd.print("Brightness:");
  lcd.setCursor(6,1);       //position auf dem Display: 6Pixel von links, untere Reihe
  lcd.print(valveBrightness);
  delay(5000);
}
void action3() {
  lcd.clear();
  lcd.print(">Executing #3");
  delay(1500);
}
void action4() {
  lcd.clear();
  lcd.print(">Executing #4");
  delay(1500);
}

// ****************************************************************************
//                                UNTERPROGRAMME KY-040
// ****************************************************************************

// Interrupt on A changing state
void doEncoderA()
{
  if ( rotating ) delay (1);  // wait a little until the bouncing is done
  if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
    A_set = !A_set;
    // adjust counter + if A leads B
    if ( A_set && !B_set ) 
      encoderPos += 1;
    rotating = false;  // no more debouncing until loop() hits again
  }
}

// Interrupt on B changing state, same as A above
void doEncoderB(){
  if ( rotating ) delay (1);
  if( digitalRead(encoderPinB) != B_set ) {
    B_set = !B_set;
    //  adjust counter - 1 if B leads A
    if( B_set && !A_set ) 
      encoderPos -= 1;
    rotating = false;
  }
}  



Ohne den Code wirklich zu analysieren, vermute ich, dass Deine delay Dir das Genick brechen. In Deiner action1 wartet er 5 Sekunden und in dieser Zeit tut sich nichts. An anderen Stellen sind auch noch welche.

Gruß Tommy

Hallo Tommy,

danke für deine Nachricht. Das habe ich vermutet.

Wollte gerne nochmal eine Bestätigung, da ich wenig bis keine Erfahrung habe.

Hast du einen Lösungsansatz. Oder vielleicht Stichwörter, wo ich dann googln könnte.

Wozu hast du denn die delays drin ?
Ein einfacher weg wäre, nach einer fertigen Einstellung zur Übernahme eine Taste drücken.

Moin @sccr ,

leider ist Dein Code schon alleine durch die vielen auskommentierten Anteile und die Struktur insgesamt nicht besonders übersichtlich ... :wink:

Da würde ich zunächst einmal ansetzen:

  • Löschen, was derzeit nicht benötigt wird
  • loop() aufräumen:
    • Eigenen Funktionsaufruf für die RFID-Abfrage
    • Eigenen Funktionsaufruf für die Encoder-Abfrage
    • Eigenen Funktionsaufruf für die Behandlung der Potis
    • usw.

Diese Funktionen sollten dann so gestaltet werden, dass

  • die zeitrelevanten flüssig bearbeitet werden können
  • und diejenigen, die nur bei Änderungen upgedated werden müssen, auch nur bei Änderungen aufgerufen werden

Gruß
ec2021

Das delay ist drin, damit ich mir die Wert anschauen kann. Ohne geht es nicht. Ziel ist es ja auch im Menu dann die eingestellten Werte live zu sehen.

Na ja, dazu braucht es nicht unbedingt delay, das wird besser erreicht, indem man die Anzeige nur bei Änderungen befüllt und dann z.B. Änderungen für eine bestimmte Zeit "verriegelt".

Das habe ich mir schon gedacht. :slight_smile: Wollte sie erst nochmal drin lassen. Wenn ich dann fertig bin kommen die raus. Es soll auch als kleine Erinnerung sein.

Ich weiß, das auch einige überflüssig sind.

Macht es nur für die Community schwieriger. :wink:

Na ja, auch für Dich ... Du kannst ja eine Kopie des Codes zur Erinnerung ablegen und mit einer bereinigten Version arbeiten.

Bei größeren Änderungen ist es oftmals am besten, den Code neu mit einem minimalen Gerüst aufzusetzen, zu testen und dann Stück für Stück die weiteren Funktionen hinzuzufügen ...

Das habe ich auch so gemacht, ich habe erst die einzelne Stücke auf einem Nano getestet und dann Stück für Stück auf einen Mega umgebaut.

Danke für den Tipp. Werde dann mehrer Version anlegen.

Rudimentär und mit der Brechstange:

  if (!digitalRead(selectButton))
  {
    updateMenu();
    delay(100);   // fürs debouncen
    while (!digitalRead(selectButton));   // damit man nicht weiter scrollt, wenn man die taste zulande drückt
  }
  else
  {
    executeAction();
  }

Das execute muss beim update des Menu noch abgeschaltet werden mit einer Variable "oldMenu".
Wenn die anders als menu ist, dann darf das ncht mehr aktuallisiert werden.

Und mit dem Button wird das wieder gleich gesetzt.

Du willst mehrere Dinge gleichzeitig machen und hast delay() im Code. Das funktioniert so nicht, aber das hast du schon gemerkt.

Du brauchst non-blocking code. Dazu musst du dich in Statemachines einlesen.

Eine Statemachine könnte in deinem Fall so aussehen:

Die Ellipsen sind die States in denen du sein kannst, die Pfeile sind Übergänge. Einen Übergang darfst du nur gehen, wenn die Bedingung über den Pfeil erfüllt ist. Wenn du einen Übergang gehst, musst du die Aktion unter dem Pfeil ausführen.

Starte Timer könnte so aussehen:

start = millis();

und Timeout? so:

isTimeot = (millis() - start) > timeout;
1 Like

Hallo Rintin. Von Statemachines hatte ich auch schon gelesen. Ich habe gedacht, das ist nicht passend. Dann werde ich mal auf die Suche danach gehen.

Oh doch, besonders wenn du keinen Task-Scheduler hast.

Encoder -> Statemachine die bei Drehung Events generiert.
Taster -> Statemachine zum debouncen und bei Klicks Events generiert.
Die Events gibst du dann in deine Menu-Statemachine rein...

Hallo Rintin. Vergleichst du eine StateMachine mit SwitchCase ? Wird das vielleicht auch sogennant ? Weil, SwichCase habe ich ja in meinem Programm und mache so meine LCD Menu Strucktur.

Ein Vergleich ist das sicher nicht. Aber Switch - Case kann ein Bestandteil einer StateMachine sein.
Wenn du dich da noch etwas weiter informieren möchtest, dann ist die Nachtwächtererklärung genau das Richtige für dich.
Oder auch Dies hier

Danke für die Info. Über den Nachtwächter bin ich schon mal gestolpert.

Ok, der sollte eigentlich als zweiter Link rein, zumal der auch im anderen Link auch verlinkt ist. Der erklärt mehr die Funktion von millis im Zusammenhang mit BlinkWithoutDelay. Ist aber für eine StateMachine (Endlicher Automat) unerlässlich.

Meine "Anleitung Ein Endlicher Automat entsteht" hat schon eine Menge Staub angesetzt. Ich hoffe, sie hat dennoch gelegentlich geholfen, eventuell auch in diesem Thema :blush:

Ich hab mal über Deinen Sketch geschaut...
Nachdem ich Deine Konstruktion für die Zählerei mit dem Encoder gesehen habe, hab ich mich an eine von mir gebaute Funktion erinnert.

Die hab ich mal bei Dir mit eingesetzt.
Wichtig: Du brauchst eine lib dazu - die ist im Code angegeben.

Und dann hab ich mal was gebaut, was ich mir da so dachte...
Eigentlich müsste das komplett überarbeitet werden.
Da fehlen noch so einige Dinge und es werden auf dem Display wilde Dinge passieren.
Aber irgendwie so....
Ich will erstmal nur wissen, ob das mit den RFID-Dingern klappt.

#include <Adafruit_NeoPixel.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"


#include <rotary.h> //https://github.com/CarlosSiles67/Rotary

//
constexpr uint8_t LED_COUNT {130};  //
constexpr uint8_t LED_PIN {2};
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

//
constexpr uint8_t RST_PIN {5};     // SPI Reset Pin
constexpr uint8_t SS_PIN  {53};    // SPI Slave Select
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Instanz des MFRC522 erzeugen


constexpr uint8_t cardNums {2};
constexpr uint8_t cardLen {4};
const byte uid[cardNums][cardLen] =
{
  {0xFD, 0x49, 0x02, 0x89},     // Chip, Marcel, Farbe Grün
  {0xC0, 0x81, 0x2B, 0xA8},     //Karte, Janine, Farbe Pink
};
const char uidName[cardNums] = {'M', 'J'};

//
constexpr uint8_t col {2};
constexpr uint8_t row {16};
LiquidCrystal_I2C lcd(0x27, row, col);

//
RTC_DS3231 rtc;


uint8_t menuPoint = 1;             // merkt sich in welchem menu wir gerade sind, startpunkt ist das erste menu
uint32_t lastDisplayTime;          // Zeitmerker für Displayaktualliserungen

Rotary r = Rotary(18, 19);
constexpr uint8_t selectButton {39};  //Taster vom Drehpoti

const int switch_1 = 22;      // the number of the switch pin
const int switch_2 = 23;    // the number of the switch pin
//const int switch_3 = 24;    // the number of the switch pin
//const int switch_4 = 25;
//const int relai1_ON = 26;   // the number of the relai NO
//const int relai2_ON = 27;   // the number of the relai NO


const int potiDimmer = A0;    // Schieberegler
const int potiMixing_R = A1;  // Drehpoti
const int potiMixing_G = A2;  // Drehpoti
const int potiMixing_B = A3;  // Drehpoti


const int LED_1R = 35;
const int LED_1G = 34;
const int LED_1B = 36;
const int LED_2R = 37;
const int LED_2G = 49;
const int LED_2B = 48;
//const int LED_3R = 47;
//const int LED_3G = 46;
//const int LED_3B = 45;
//const int LED_4R = 44;
//const int LED_4G = 43;
//const int LED_4B = 42;
//const int relai1_A1 = 41;   // relai coil A1
//const int relai2_A1 = 40;   // relai coil A1
// ****************************************************************************
//                                VARIABLES will change
// ****************************************************************************

int switchState1 =    0;         // variable for reading the switch status
int switchState2 =    0;         // variable for reading the switch status
int switchState3 =    0;         // variable for reading the switch status
int switchState4 =    0;         // variable for reading the switch status
int relaiState1 =     0;          // variable for reading the relai status
int relaiState2 =     0;          // variable for reading the relai status

int potiValve_Sch =   0;        // valve from Schieberegler
int potiValve_R =     0;          // valve from Poti
int potiValve_G =     0;          // valve from Poti
int potiValve_B =     0;          // valve from Poti

int valveMixing_R =   0;        // valve for mixing
int valveMixing_G =   0;        // valve for mixing
int valveMixing_B =   0;        // valve for mixing
int valveBrightness = 0;      // valve for Brightness


//unsigned long startTime = 0;
//unsigned long currentTime = 0;
//const unsigned long pause = 5000;


void setup()
{
  Serial.begin(9600);     // Serielle Kommunikation mit dem PC initialisieren
  SPI.begin();         // Initialisiere SPI Kommunikation
  mfrc522.PCD_Init();  // Initialisiere MFRC522 Lesemodul
  lcd.begin();
  //lcd.backlight();
  // updateMenu();         // damit der bildschirm, erstmalig mit dem menu gefüllt wird.
  pinMode(selectButton, INPUT_PULLUP);
  strip.begin();
  rtc.begin();
  //wenn Datum und Zeit nicht korrekt -> Datum/Zeit setzen
  //Jahr, Monat, Tag, Stunde, Minute, Sekunde
  //rtc.adjust(DateTime(2025, 4, 10, 17, 25, 30));
  pinMode(switch_1, INPUT);
  pinMode(switch_2, INPUT);
  //pinMode(switch_3, INPUT);
  //pinMode(switch_4, INPUT);
  //pinMode(relai1_ON, INPUT);
  //pinMode(relai2_ON, INPUT);
  pinMode(LED_1R, OUTPUT);
  pinMode(LED_1G, OUTPUT);
  pinMode(LED_1B, OUTPUT);
  pinMode(LED_2R, OUTPUT);
  pinMode(LED_2G, OUTPUT);
  pinMode(LED_2B, OUTPUT);
  //pinMode(LED_3R, OUTPUT);
  //pinMode(LED_3G, OUTPUT);
  //pinMode(LED_3B, OUTPUT);
  //pinMode(LED_4R, OUTPUT);
  //pinMode(LED_4G, OUTPUT);
  //pinMode(LED_4B, OUTPUT);
  //pinMode(relai1_A1, OUTPUT);
  //pinMode(relai2_A1, OUTPUT);
  //startTime = millis();
}


void loop()   // Diese Funktion wird in Endlosschleife ausgeführt
{
  rfid();
  getInputs();
  lcdMenu();
  uhr();
}

void debugPrintCard()
{
  Serial.print(F("Gelesene UID: "));
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    Serial.print("0x");
    if (mfrc522.uid.uidByte[i] < 0x10)
    { Serial.print(0); }
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    Serial.print(", ");
  }
}
//
void displayWelcome(const uint8_t person)
{
  lcd.clear();
  lcd.print(F("Hallo "));
  lcd.print(uidName[person]);     // Karteninhaber
}
//
void rfid()
{
  // Nur wenn eine Karte gefunden wird und gelesen werden konnte, wird der Inhalt von IF ausgeführt
  // PICC = proximity integrated circuit card = kontaktlose Chipkarte
  if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial() )
  {
    debugPrintCard();                                          // Ausgabe der ID
    byte myCard = cardNums;                                    // Vorbelegung für Auswertung
    for (byte b = 0; b < cardNums; b++)                        // Frage alle bekannten Karten ab
    {
      if (!memcmp(mfrc522.uid.uidByte, uid[b], cardLen))       // Karte passt?
      {
        myCard = b;                                            // Merken
        displayWelcome(myCard);                                // Kartenbesitzer ausgeben
      }
    }
/*INDENT-OFF*/    
    switch (myCard)                                            // Auswertung -> Farbcode
    {
      case 0: colorWipe(strip.Color(  0, 255,   0), 50); break; // Blue
      case 1: colorWipe(strip.Color(255,   0, 255), 50); break; // Purple
    }
/*INDENT-ON*/
    // Versetzt die gelesene Karte in einen Ruhemodus, um nach anderen Karten suchen zu können.
    mfrc522.PICC_HaltA();
  }
}
//
void setupZahl(uint32_t &aenderZahl, const uint32_t &minZahl, const uint32_t &maxZahl, const bool umlauf)
{
  if (aenderZahl < minZahl)
  { aenderZahl = minZahl; }
  if (aenderZahl > maxZahl)
  { aenderZahl = maxZahl; }
  uint32_t myZahl = aenderZahl;     // lokale Berechnung
  unsigned char val = r.process();  // encoder auslesen
  if (val == r.clockwise())         // auf zaehlen
  {
    myZahl++;
    if (umlauf)                     // Wenn Überlauf
    {if (myZahl > maxZahl) myZahl = minZahl;}
    else                            // Wenn Begrenzung
    {if (myZahl > maxZahl) myZahl = maxZahl;}
  }
  if (val == r.counterClockwise())  // ab zaehlen
  {
    if (myZahl == minZahl)          // Wenn kleinstmögliche Zahl schon erreicht
    {
      if (umlauf)
      { myZahl = maxZahl; }         // Nur wenn Überlauf
    }
    else
    { myZahl--; }
  }
  aenderZahl = myZahl;
}
//
void displayMenuText(const uint8_t point)
{
  switch (point)
  {
    case 1:
      lcd.clear();
      lcd.print(">LED Farbenwert");
      lcd.setCursor(0, 1);
      lcd.print(" LED Helligkeit");
      break;
    case 2:
      lcd.clear();
      lcd.print(" LED Farbenwert");
      lcd.setCursor(0, 1);
      lcd.print(">LED Helligkeit");
      break;
    case 3:
      lcd.clear();
      lcd.print(">Temperatur");
      lcd.setCursor(0, 1);
      lcd.print(" MenuItem4");
      break;
    case 4:
      lcd.clear();
      lcd.print(" Temperatur");
      lcd.setCursor(0, 1);
      lcd.print(">MenuItem4");
      break;
  }
}
//
void lcdMenu()
{
  static uint32_t newMenu = menuPoint;   // Zwischenvariable
  setupZahl(newMenu, 1, 4, false);       // Neues Menu auswählen?
  if (newMenu == menuPoint)              // Menu hat sich nicht geändert?
  { executeAction(menuPoint); }          // Dynamische Ausgaben
  else                                   // Neuen Menupunkt
  { displayMenuText(newMenu); }          // Neuen statischen Text ausgeben
  if (!digitalRead(selectButton))
  {
    menuPoint = newMenu;
    displayNewData(menuPoint);
    while (!digitalRead(selectButton));   // damit man nicht weiter scrollt, wenn man die taste zulande drückt
  }
}


// wird aufgerufen wenn die selecttaste gedrückt wurde
void displayNewData(const uint8_t point)
{
  lastDisplayTime = millis();
  switch (point)
  {
    case 1:
      action1();
      break;
    case 2:
      action2();
      break;
    case 3:
      action3();
      break;
    case 4:
      action4();
      break;
  }
}

void executeAction(const uint8_t point)
{
  switch (point)
  {
    case 1:
    case 2:
      if (millis() - lastDisplayTime > 1500)
      { displayNewData(point); }
      break;
    case 3:
      if (millis() - lastDisplayTime > 5000)
      { displayNewData(point); }
      break;
    default:
      displayNewData(point);
      break;
  }
}

void uhr()
{
  // ****************************************************************************
  //                                DS3231
  // ****************************************************************************
  /*
    DateTime aktuell = rtc.now();

    // Datum anzeigen
    lcd.setCursor(0, 0);
    //char Datum[] = "Datum: DD.MM.YY";
    char Datum[] = "DD.MM.YY";
    lcd.print(aktuell.toString(Datum));

    // Zeit anzeigen
    lcd.setCursor(4, 1);
    char Zeit[] = "hh:mm:ss";
    lcd.print(aktuell.toString(Zeit));

    // gemessene Temperatur in String umwandeln
    String Temperatur = String(rtc.getTemperature());
    // angelsächsische Schreibweise der Temperatur
    // . durch , ersetzen
    //Temperatur.replace(".", ",");
    lcd.setCursor(9, 0);
    // Sonderzeichen für ° = \337
    // Temperatur anzeigen
    //lcd.print("Temperatur: " + Temperatur + "\337C");
    lcd.print(Temperatur);
    lcd.print("\337C");

    //delay(1000);
  */
}

void getInputs()
{
  valveBrightness = analogRead(potiDimmer) / 4;
  valveMixing_R = analogRead(potiMixing_R) / 4;
  valveMixing_G = analogRead(potiMixing_G) / 4;
  valveMixing_B = analogRead(potiMixing_B) / 4;
  switchState1  = digitalRead(switch_1);
  switchState2  = digitalRead(switch_2);
}

void stripeColor()
{
  // LED Streifen Dimmen
  //lcd.setCursor(2,0);       //position auf dem Display: 2 pixel von links, obere Reihe
  //lcd.print("Brightness:");
  //lcd.setCursor(6,1);       //position auf dem Display: 6Pixel von links, untere Reihe
  //lcd.print(valveBrightness);
  // LED Streifen Farbe Rot
  //lcd.setCursor(0,0);
  //lcd.print("R: ");
  //lcd.print(valveMixing_R);
  // LED Streifen Farbe Grün
  //lcd.setCursor(0,1);
  //lcd.print("G: ");
  //lcd.print(valveMixing_G);
  // LED Streifen Farbe Blau
  //lcd.setCursor(10,0);
  //lcd.print("B: ");
  //lcd.print(valveMixing_B);
  // read the state of the switch value:
  //switchState3  = digitalRead(switch_3);
  //switchState4  = digitalRead(switch_4);
  //relaiState1 = digitalRead(relai1_ON);
  //relaiState2 = digitalRead(relai2_ON);
  // check if the switch is on. If it is, the switchState is HIGH:
  //###################
  if (switchState1 == HIGH)
  {
    // turn on:
    digitalWrite(LED_1G, HIGH);
    digitalWrite(LED_1R, LOW);
  }
  else
  {
    // turn off:
    digitalWrite(LED_1G, LOW);
    digitalWrite(LED_1R, HIGH);
  }
  // LED Streifen an und Dimmen
  if (switchState2 == HIGH)
  {
    // turn on:
    digitalWrite(LED_2G, HIGH);
    digitalWrite(LED_2R, LOW);
    strip.fill(strip.Color(valveMixing_R, valveMixing_G, valveMixing_B), 0, 130);
    strip.setBrightness(valveBrightness);
    strip.show();  // Send the updated pixel colors to the Hardware
  }
  else
  {
    // turn off:
    digitalWrite(LED_2G, LOW);
    digitalWrite(LED_2R, HIGH);
    strip.clear();
    strip.show();
  }
  //currentTime = millis();
}



void colorWipe(uint32_t color, int wait)
{
  for (uint8_t i = 0; i < strip.numPixels(); i++) // For each pixel in strip...
  {
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}


// das sind die aktion die passieren sollen

void action1()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("R: ");
  lcd.print(valveMixing_R);
  lcd.setCursor(0, 1);
  lcd.print("G: ");
  lcd.print(valveMixing_G);
  lcd.setCursor(10, 0);
  lcd.print("B: ");
  lcd.print(valveMixing_B);
}
//
void action2()
{
  lcd.clear();
  lcd.setCursor(2, 0);      //position auf dem Display: 2 pixel von links, obere Reihe
  lcd.print("Brightness:");
  lcd.setCursor(6, 1);      //position auf dem Display: 6Pixel von links, untere Reihe
  lcd.print(valveBrightness);
}
//
void action3()
{
  lcd.clear();
  lcd.print(">Executing #3");
}
//
void action4()
{
  lcd.clear();
  lcd.print(">Executing #4");
}