Weiterentwicklung einer Software zur Funktionsreife

Hier nochmal der komplette Code mit den letzten paar Änderungen aus Post#376/378

#define debug
#define ff
//#define ag

#ifdef ff
  #undef ag
  #undef debug
#endif

#ifdef debug
  #define DBG_PRINT(...) Serial.print(__VA_ARGS__)
  #define DBG_PRINTLN(...) Serial.println(__VA_ARGS__)
#else
  #define DBG_PRINT(...)
  #define DBG_PRINTLN(...)
#endif

const byte lcdZeilen = 2;
const byte lcdSpalten = 20;
#ifndef ag
  // EEprom
  #include <EEPROM.h>
#endif

// Rotary
#include <rotary.h>

// bedingte Kompilierung - Zuweisung der Konfigurationen
#ifdef ff
  #include <Adafruit_CharacterOLED.h>
  Adafruit_CharacterOLED display(OLED_V2, 4, 6, 5, 7, 8, 9, 10);
  Rotary r = Rotary(2, 3); // Hier muss ff seine Konfig rein
  const byte rotBut = 13;
  const byte mutBut = 12;
  const byte mutLed = 255;
#elif ag
  #include <Wire.h>
  #include <LiquidCrystal_I2C.h>
  const byte lcdAddress = 0x27;
  LiquidCrystal_I2C display(lcdAddress, lcdSpalten, lcdZeilen);
  Rotary r = Rotary(3, 2);
  const byte rotBut = 11;
  const byte mutBut = 12;
  const byte mutLed = LED_BUILTIN;
#else
  #include <LiquidCrystal_I2C.h>
  const byte lcdAddress = 0x27;
  LiquidCrystal_I2C display(lcdAddress, lcdSpalten, lcdZeilen);

  Rotary r = Rotary(45, 43);
  const byte rotBut = 41;
  const byte mutBut = 12;
  const byte mutLed = LED_BUILTIN;
#endif

enum {ungedrueckt, kurz, lang};

const uint32_t bounceTime = 20; // zeit in ms
// Inhalt
struct inhalt
{
  char name[lcdSpalten + 1];
  char hid[2];
};
#include "hidTable.h"

inhalt MyFilter[]
{
  {"Filter 1", ""}, {"Filter 2", "s"},
  {"Filter 3", "d"}, {"Filter 4", "f"},
};

inhalt MyWlan[]
{
  {"Wlan 1", "e"}, {"Wlan 2", "e"},
};

inhalt MyPlatzhalter[]
{
  {"Platzhalter 1", "y"}, {"Platzhalter 2", "x"},
  {"Platzhalter 3", "c"}, {"Platzhalter 4", "v"},
  {"Platzhalter 5", "b"},
};

char mySetup[][lcdSpalten + 1] =
{
  "Auswahl", "Displayzeit", "Wlan", "Bezeichner",
  "Platzhalter1", "Platzhalter2", "Platzhalter3",   // Platzhalter wird durch MyPlatzhalter
  "Platzhalter4", "Platzhalter5"                    // aus dem EEprom ersetzt!
};

uint8_t displayZeit = 20;                           // Zeit in Sekunden bis abschalten
uint32_t displayTick = 0;                           // Merker für letzte Aktion am Encoder oder Button

char displayZeileOben[lcdSpalten + 1] = {'\0'};     // Globale Variablen für DisplayZeilen
char displayZeileUnten[lcdSpalten + 1] = {'\0'};

bool isMenu = true;
bool isSetup = !isMenu;
bool isMute = false;

void setup()
{
#ifdef ff
  Serial.begin(9600);
#else
  Serial.begin(115200);
#endif
  DBG_PRINTLN(F("Start..."));
  pinMode (rotBut, INPUT);
  pinMode (mutBut, INPUT_PULLUP);
  pinMode (mutLed, OUTPUT);
#ifdef ff
  display.begin(lcdSpalten, lcdZeilen);
  startSequenz();
#elif ag
  Wire.begin();
  display.begin();
  display.backlight();
#else
  display.begin();
#endif
#ifndef ag
  //updateEEprom();                                  // Nur einmalig aufrufen;
    if (EEPROM.read(0) == 255) updateEEprom();
  // ---
  readEEprom();                                    // Holt die Variablen aus dem EEprom
#endif
  displayTick = millis();
}
//
void loop()
{
  if (isMute)
  {
    heartbeat(500);
    ausgabe("Mute aktiv", "");
  }
  else
  {
    if (digitalRead(mutLed))                      // wenn nicht Mute
      digitalWrite(mutLed, LOW);                  // sicherstellen, das aus
    if (isMenu) filterMenu();
    if (isSetup) setupMenu();
  }
  setMute();
  isDisplay();
}
//
bool editBezeichner()                             // Ein Versuch - wird ggfls. noch aufgelöst
{
  const char bezeichner[][lcdSpalten + 1] =
  {"Filtertexte", "Filterkey", "Wlantexte", "Wlalkey", "Platztexte", "Platzkey", "Setuptexte"};
  const uint8_t num = sizeof(bezeichner) / sizeof(bezeichner [0]) - 1;
  static uint8_t schritt = 0;
  static uint8_t rotaryPos = 0;
  static uint8_t auswahl[2] = {0};
  const uint8_t minPos = 0;
  static bool returnWert = false;
  static uint8_t spalte = 0;
  static char editZeile[lcdSpalten + 1] = {'\0'};
  if (!returnWert) // Wenn erster Aufruf, init der Var
  {
    returnWert = true;
    schritt = rotaryPos = auswahl[0] = 0;
    memset(editZeile, '\0', lcdSpalten + 1);
  }
  switch (schritt)
  {
    case 0:  // Hauptmenu
      {
        menuAuswahl(rotaryPos, minPos, num, "Editieren", bezeichner[rotaryPos]);
        switch (getTaste())
        {
          case kurz:
            memset(displayZeileOben, '\0', lcdSpalten + 1);
            strcpy(displayZeileOben, bezeichner[rotaryPos]);
            auswahl[0] = auswahl[1] = rotaryPos;
            rotaryPos = 0;
            schritt = 1;
            break;
          case lang:
            schritt = 99;
            break;
        }
      }
      break;
    case 1:
      if (auswahl[1] % 2 != 0) memset(displayZeileOben, '\0', lcdSpalten + 1);
      switch (auswahl[1])
      {
        case 0:
          menuAuswahl(rotaryPos, minPos, sizeof(MyFilter) / sizeof(inhalt) - 1, displayZeileOben, MyFilter[rotaryPos].name);
          strcpy(editZeile, MyFilter[rotaryPos].name);
          break;
        case 1:
          strcpy(displayZeileOben, MyFilter[rotaryPos].name);
          menuAuswahl(rotaryPos, minPos, sizeof(MyFilter) / sizeof(inhalt) - 1, displayZeileOben, MyFilter[rotaryPos].hid);
          strcpy(editZeile, MyFilter[rotaryPos].hid);
          break;
        case 2:
          menuAuswahl(rotaryPos, minPos, sizeof(MyWlan) / sizeof(inhalt) - 1, displayZeileOben, MyWlan[rotaryPos].name);
          strcpy(editZeile, MyWlan[rotaryPos].name);
          break;
        case 3:
          strcpy(displayZeileOben, MyWlan[rotaryPos].name);
          menuAuswahl(rotaryPos, minPos, sizeof(MyWlan) / sizeof(inhalt) - 1, displayZeileOben, MyWlan[rotaryPos].hid);
          strcpy(editZeile, MyWlan[rotaryPos].hid);
          break;
        case 4:
          menuAuswahl(rotaryPos, minPos, sizeof(MyPlatzhalter) / sizeof(inhalt) - 1, displayZeileOben, MyPlatzhalter[rotaryPos].name);
          strcpy(editZeile, MyPlatzhalter[rotaryPos].name);
          break;
        case 5:
          strcpy(displayZeileOben, MyPlatzhalter[rotaryPos].name);
          menuAuswahl(rotaryPos, minPos, sizeof(MyPlatzhalter) / sizeof(inhalt) - 1, displayZeileOben, MyPlatzhalter[rotaryPos].hid);
          strcpy(editZeile, MyPlatzhalter[rotaryPos].hid);
          break;
        case 6: // Da mySetup.hid nicht gesetzt wird, muss das der letzte Eintrag sein!
          uint8_t auswahlPunkte = sizeof(mySetup) / sizeof(mySetup[0]) - 1 - sizeof(MyPlatzhalter) / sizeof(MyPlatzhalter[0]);
          menuAuswahl(rotaryPos, minPos, auswahlPunkte, displayZeileOben, mySetup[rotaryPos]);
          strcpy(editZeile, mySetup[rotaryPos]);
          break;
      }
      switch (getTaste())
      {
        case kurz:
          spalte = 0;
          display.blink();
          display.setCursor(spalte, 1);
          display.print(editZeile);
          for (uint8_t b = strlen(editZeile); b < lcdSpalten; b++) display.print(' ');
          display.setCursor(spalte, 1);
          schritt = 2;
          break;
        case lang:
          schritt = 0;
          rotaryPos = auswahl[0];
          break;
      }
      break;
    case 2:
      {
        const uint8_t minZeichen = 32;
        const uint8_t maxZeichen = 125;
        uint8_t buchstabe = maxZeichen;
        if (editZeile[spalte] < minZeichen)editZeile[spalte] = minZeichen;
        if (auswahl[1] % 2 == 0)
        {
          if (editZeile[spalte] > maxZeichen)editZeile[spalte] = maxZeichen;
          buchstabe = uint8_t(editZeile[spalte]);
          setupZahl(buchstabe, minZeichen, maxZeichen);
        }
        else
        {
          if (editZeile[spalte] == 32 || editZeile[spalte] == '\0') editZeile[spalte] = 96;
          buchstabe = editZeile[spalte];
          setupZahl(buchstabe, 96, 122);
          if (buchstabe == 96) buchstabe = 32;
        }
        if (uint8_t(editZeile[spalte]) != buchstabe)
        {
          display.setCursor(spalte, 1);
          display.print(char(buchstabe));
          display.setCursor(spalte, 1);
          editZeile[spalte] = buchstabe;
        }
        switch (getTaste())
        {
          case kurz:
            spalte++;
            if (auswahl[1] % 2 == 0) {if (spalte >= lcdSpalten) spalte = 0;} // Wenn Text am Zeilenende
            else {spalte = 0;display.noBlink();}                                                 // Wenn hid immer erste Position
            display.setCursor(spalte, 1);
            break;
          case lang:
            display.noBlink();
            int8_t c = sizeof(editZeile) - 1;
            while (c >= 0 && !isGraph(editZeile[c]))                         // Entfernt Leerzeichen etc am Ende
            {
              editZeile[c] = '\0';
              c--;
            }
            switch (auswahl[1])
            {
              case 0: memcpy(MyFilter[rotaryPos].name, editZeile, sizeof(MyFilter[rotaryPos].name) - 1); break;
              case 1: memcpy(MyFilter[rotaryPos].hid, editZeile, sizeof(MyFilter[rotaryPos].hid) - 1); break;
              case 2: memcpy(MyWlan[rotaryPos].name, editZeile, sizeof(MyWlan[rotaryPos].name) - 1); break;
              case 3: memcpy(MyWlan[rotaryPos].hid, editZeile, sizeof(MyWlan[rotaryPos].hid) - 1); break;
              case 4: memcpy(MyPlatzhalter[rotaryPos].name, editZeile, sizeof(MyPlatzhalter[rotaryPos].name) - 1); break;
              case 5: memcpy(MyPlatzhalter[rotaryPos].hid, editZeile, sizeof(MyPlatzhalter[rotaryPos].hid) - 1); break;
              case 6: memcpy(mySetup[rotaryPos], editZeile, sizeof(mySetup[rotaryPos]) - 1); break;
            }
            memset(editZeile, '\0', lcdSpalten + 1);
            updateEEprom();
            schritt = 1;
            ausgabe("", "");
            break;
        }
      }
      break;
    case 99:
      auswahl[0] = 0;
      returnWert = false;
      break;
  }
  if (!isDisplay())
  {
    display.noBlink();
    returnWert = false;
  }
  return returnWert;
}
//
void setupMenu()
{
  const uint8_t maxPos = sizeof(mySetup) / sizeof(mySetup[0]); // Anzahl der Elemente ermitteln
  const uint8_t minPos = 1;                                    // Der Eintrag 0 ist kein Menueintrag
  static uint8_t rotaryPos = minPos;
  static uint8_t menuPos = 0;
  static uint8_t subMenuPos = 0;                               // Hilfsvariable für Untermenu
  static uint32_t startzeit = 0;
  switch (menuPos)
  {
    case 0:
      {
        char buf[lcdSpalten + 1] = {'\0'};
        strcpy(buf, mySetup[rotaryPos]);
        if (millis() - startzeit < 300)
          buf[strlen(mySetup[rotaryPos]) - 1] = '*';
        menuAuswahl(rotaryPos, minPos, maxPos - 1, mySetup[0], buf);
        switch (getTaste())
        {
          case kurz:
            menuPos = rotaryPos;                               // Wenn ausgewählt: menuPos setzen
            if (menuPos == 2) subMenuPos = 0;                  // wenn Submenu gebraucht wird
            else startzeit = millis();
            break;
          case lang:
            menuPos = maxPos;
            break;
        }
      }
      break;
    case 1: // Die displayZeit wird
      displayTime(mySetup[menuPos], displayZeit);             // direkt geändert
      if (getTaste() == kurz)                                 // verlassen des Menupunktes
      {
        menuEnde(menuPos, mySetup[0], mySetup[menuPos]);      // zurücksetzen auf eine Ebene höher
        updateEEprom();
      }
      break;
    case 2:                                                   // Wlan
      {
        char buf[lcdSpalten + 1] = {'\0'};
        strcpy(buf, MyWlan[subMenuPos].name);
        if (millis() - startzeit < 300) buf[strlen(MyWlan[subMenuPos].name) - 1] = '*';
        menuAuswahl(subMenuPos, 0 , 1, mySetup[menuPos], buf);
        switch (getTaste())
        {
          case kurz:
            startzeit = millis();
            sendHid(MyWlan[subMenuPos].hid);
            break;
          case lang:
            menuEnde(menuPos, mySetup[2], mySetup[subMenuPos]);
            break;
        }
      }
      break;
    case 3:                                                  // Texte ändern
      if (!editBezeichner())
      {
        DBG_PRINTLN("ENDE");
        menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      }
      break;
    case 4:
      DBG_PRINTLN(F("Platzhalter1"));
      sendHid(MyPlatzhalter[0].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
    case 5:
      DBG_PRINTLN(F("Platzhalter2"));
      sendHid(MyPlatzhalter[1].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
    case 6:
      DBG_PRINTLN(F("Platzhalter3"));
      sendHid(MyPlatzhalter[2].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
    case 7:
      DBG_PRINTLN(F("Platzhalter4"));
      sendHid(MyPlatzhalter[3].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
    case 8:
      DBG_PRINTLN(F("Platzhalter5"));
      sendHid(MyPlatzhalter[4].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
  }
  if (!isDisplay() || (menuPos == maxPos)) // Wenn der Display aus geht ODER maxPos (exit) ausgelöst
  {
    menuPos = 0; // alles zurücksetzen
    rotaryPos = minPos;
    isMenu = true; isSetup = false;
  }
}
//
// Die folgende Funktion ist für die Auswahl und Übergabe jeweiliger
// Menueinträge vorgesehen. Die sich ständig wiederholenden Abfragen
// des RotaryEncoders in den unterschiedlichen Menus zusammengefasst
// rotaryPos ist die aktuelle Position, die einzige die veränderlich ist ;)
void menuAuswahl(uint8_t &rotaryPos, const uint8_t &minPos,
                 const uint8_t &maxPos, const char *zeile1, const char *zeile2)
{
  unsigned char val = r.process();
  if (val && isDisplay())
  {
    if (val == r.clockwise())
    {
      if (rotaryPos >= maxPos) rotaryPos = minPos;
      else rotaryPos++;
    }
    else if (val == r.counterClockwise())
    {
      if (rotaryPos <= minPos) rotaryPos = maxPos;
      else rotaryPos--;
    }
    displayTick = millis();
  }
  ausgabe(zeile1, zeile2);
}
//
void filterMenu()                                                 // filterauswahl ist default
{
  memset(displayZeileOben, '\0', lcdSpalten + 1);                 // Zeile leeren
  strcpy(displayZeileOben, "Filter waehlen");                     // und neu befüllen
  const uint8_t maxPos = sizeof(MyFilter) / sizeof(inhalt) - 1;
  const uint8_t minPos = 0;
  static uint8_t rotaryPos = 0;
  static uint32_t startzeit = 0;
  if (isDisplay())                                                // Nur wenn Display an ist
  {
    // Übergeben wird die (sich nicht mehr ändernde) obere Zeile und der Inhalt
    // aus dem Struct. Darstellung wird dann in der Funktion menuAuswahl() gebaut
    char buf[lcdSpalten + 1] = {'\0'};
    strcpy(buf, MyFilter[rotaryPos].name);
    if (millis() - startzeit < 300)
      buf[strlen(MyFilter[rotaryPos].name) - 1] = '*';
    menuAuswahl(rotaryPos, minPos, maxPos, displayZeileOben, buf);
  }
  switch (getTaste())                                             // Tastenabfrage
  {
    case kurz:
      sendHid(MyFilter[rotaryPos].hid);
      startzeit = millis();
      break;
    case lang: isMenu = false; isSetup = true; break;
  }
}
//
void displayTime(char *zeile1, uint8_t &sekunde)                  // Einstellen der DisplayTime
{
  setupZahl(sekunde); // Sekunde verstellen
  if (sekunde < 5) sekunde = 5;
  memset(displayZeileUnten, '\0', lcdSpalten + 1);                // untere DisplayZeile leeren
  sprintf(displayZeileUnten, "%d", sekunde);                      // und mit Zahl füllen
  ausgabe(zeile1, displayZeileUnten);                             // und ausgeben
}
//
void setupZahl(uint8_t &aenderZahl, const uint8_t &minZahl, const uint8_t &maxZahl)
{
  // Serial.print(aenderZahl); Serial.print(' '); Serial.print(minZahl); Serial.print(' '); Serial.println(maxZahl);
  uint32_t myZahl = aenderZahl;
  setupZahl(myZahl);
  if (myZahl > maxZahl) myZahl = minZahl;
  if (myZahl < minZahl) myZahl = maxZahl;
  aenderZahl = myZahl;
}
void setupZahl(uint8_t &aenderZahl) // Je nach Größe der
{
  uint32_t myZahl = aenderZahl;
  setupZahl(myZahl, 255);
  aenderZahl = myZahl;
}
void setupZahl(uint16_t &aenderZahl) // übergebenen Zahl
{
  uint32_t myZahl = aenderZahl;
  setupZahl(myZahl, 65535); // begrenzen des Zählers
  aenderZahl = (uint16_t)myZahl;
}
void setupZahl(uint32_t &aenderZahl, const uint32_t &maxZahl)
{
  setupZahl(aenderZahl);
  if (aenderZahl > maxZahl) aenderZahl = 0;
}
void setupZahl(uint32_t &aenderZahl)
{
  unsigned char val = r.process();
  if (val && isDisplay()) // und hier einfach nur auf/ab zaehlen
  {
    if (val == r.clockwise())
      aenderZahl++;
    if (val == r.counterClockwise())
      aenderZahl--;
    displayTick = millis(); // und dem Merker sagen, das sich was bewegt hat
  }
}
//
void menuEnde(uint8_t &menuPos, char *zeile1, char *zeile2)
{
  menuPos = 0;
  ausgabe(zeile1, zeile2);
}
//
uint8_t findeZeichen(char zeichen)
{
  uint8_t position = 255;
  for (uint8_t h = 0; h < hidNums; h++)
  {
    uint8_t hidSeq = pgm_read_byte_near(&hidTable[h].zeichen);
    if (hidSeq == zeichen) position = h;
  }
  return position;
}
//
void sendHid(char *zeichen)
{
  DBG_PRINT(F("HID: "));
  DBG_PRINT(zeichen);
  DBG_PRINT(F("\tCode: "));
  uint8_t h = findeZeichen(zeichen[0]);
  if (h < 255)
  {
    DBG_PRINT(zeichen[0]);
    for (uint8_t b = 0; b < 8; b++)
    {
      uint8_t hidByte = pgm_read_byte_near(&hidTable[h].hidcode[b]);
      DBG_PRINT(' '); DBG_PRINT(hidByte, HEX);
#ifndef debug
      Serial.write(hidByte);
      const uint8_t none[8] = {0, 0, 0, 0, 0, 0, 0, 0};
      Serial.write(none, 8); // Relaese
#endif
    }
    DBG_PRINTLN();
  }
}
//
void printDisplay(char *zeile, byte number)                    // Displayzeile und welche Zeilennummer
{
  display.setCursor(0, number);                                // cursor setzen
  uint8_t laenge = strlen(zeile);                              // wie lang ist die Zeichenkette?
  for (byte b = 0; b < (lcdSpalten - laenge) / 2; b++)         // Errechnen der ersten Hälfte die
    display.print(' ');                                        // mit Leerzeichen aufgefüllt
  display.print(zeile);                                        // Ausgabe der Zeile
  for (byte b = (lcdSpalten - laenge) / 2 + laenge; b < lcdSpalten; b++)
    display.print(' ');                                        // Auffüllen der Zeile bis Ende mit Spaces
  DBG_PRINT(F("Zeile "));
  DBG_PRINT(number + 1);
  DBG_PRINT(": ");
  DBG_PRINTLN(zeile);
}
//
void ausgabe(const char *zeile1, const char *zeile2)           // Übernahme beider Zeilen
{
  static char lastZeileOben[lcdSpalten + 1] = {'\0'};          // Merker der letzten Ausgabe
  static char lastZeileUnten[lcdSpalten + 1] = {'\0'};
  if (strcmp(lastZeileOben, zeile1))                           // Wenn sich der Inhalt geändert hat
  {
    memset(lastZeileOben, '\0', lcdSpalten + 1);               // Merker löschen
    strcpy(lastZeileOben, zeile1);                             // neu füllen
    printDisplay(lastZeileOben, 0);                            // und ausgeben
  }
  if (strcmp(lastZeileUnten, zeile2))
  {
    memset(lastZeileUnten, '\0', lcdSpalten + 1);
    strcpy(lastZeileUnten, zeile2);
    printDisplay(lastZeileUnten, 1);
  }
}
//
void updateEEprom()
{
  uint16_t speicherPosition = 0;
  EEPROM.put(speicherPosition, MyFilter);    // struct ablegen
  speicherPosition += sizeof(MyFilter);
  EEPROM.put(speicherPosition, displayZeit); // nächste dahinter
  speicherPosition += sizeof(displayZeit);
  EEPROM.put(speicherPosition, MyWlan);
  speicherPosition += sizeof(MyWlan);
  EEPROM.put(speicherPosition, mySetup);
  speicherPosition += sizeof(mySetup);
  EEPROM.put(speicherPosition, MyPlatzhalter);
  speicherPosition += sizeof(MyPlatzhalter);
  // Jeder neue Eintrag hier muss auch in readEEprom!
  //
  readEEprom();                              // Nach der Platzhalteränderung hier geändert
}
void readEEprom()
{
  uint16_t speicherPosition = 0;             // Start auszulesende Zelle
  EEPROM.get(speicherPosition, MyFilter);    // ... dann holen ...
  speicherPosition += sizeof(MyFilter);      // Nächster Eintrag beginnt an
  EEPROM.get(speicherPosition, displayZeit); // ... dann holen ...
  speicherPosition += sizeof(displayZeit);
  EEPROM.get(speicherPosition, MyWlan);
  speicherPosition += sizeof(MyWlan);
  EEPROM.get(speicherPosition, mySetup);
  speicherPosition += sizeof(mySetup);
  EEPROM.get(speicherPosition, MyPlatzhalter);
  // Ersetzen der Platzhalterbezeichnungen durch die EEPromWerte!
  for (byte b = 0; b < sizeof(MyPlatzhalter) / sizeof(inhalt); b++)
    memcpy(mySetup[b + 4], MyPlatzhalter[b].name, lcdSpalten);
  //
  speicherPosition += sizeof(MyPlatzhalter);
  // Ab hier neue Einträge! Auch in updateEEprom hinterlegen!
  //
}
//
bool isDisplay()
{
  static bool lastReturn = false;
  if (millis() - displayTick > displayZeit * 1000UL && !isMute && !isSetup)
  {
    ausgabe(" ", " ");
    display.noDisplay();
    lastReturn = false;
    return false;
  }
  display.display();
  if (!lastReturn)
  {
    ausgabe ("", ""); lastReturn = true;
  }
  return true;
}
//
void setMute()
{
  static uint32_t lastmillis = 0;
  static bool isPressed = false;
  if (!digitalRead(mutBut) && !isPressed)
  {
    isPressed = true;
    displayTick = millis();
    lastmillis = millis();
    isMute = !isMute;
    DBG_PRINT(F(""));
    char a[] = "a";
    sendHid(a);
  }
  else if ((millis() - lastmillis > bounceTime) &&
           (digitalRead(mutBut) && isPressed))
  {
    isPressed = false;
  }
}
//
uint8_t getTaste()
{
  uint8_t butPress = ungedrueckt;
  static uint32_t pressTime = 0;
  static byte schritt = 0;
  bool isPressed = !digitalRead(rotBut);
  switch (schritt)
  {
    default:
      if (isPressed)
      {
        pressTime = millis();
        schritt = 1;
      }
      break;
    case 1:
      if (millis() - pressTime > bounceTime)
        isPressed ? schritt = 2 : schritt = 0;
      break;
    case 2:
      if (!isDisplay())
      {
        schritt = 3;
      }
      else if (!isPressed)
      {
        butPress = kurz;
        schritt = 3;
      }
      else
      {
        if (millis() - pressTime > 500)
        {
          butPress = lang;
          schritt = 3;
        }
      }
      break;
    case 3:
      displayTick = millis();
      if (!isPressed)
      {
        schritt = 0;
      }
      break;
  }
  return butPress;
}
//
void heartbeat(const uint32_t tik)
{
  static uint32_t lasttik = 0;
  if (millis() - lasttik >= tik)
  {
    lasttik += tik;
    digitalWrite(mutLed, !digitalRead(mutLed));
  }
}
//
void startSequenz()
{
  ausgabe("Willkommen", "");
  delay(1000);
  ausgabe("Booting", "");
  char zeile2[lcdSpalten + 1] = {'\0'};
  uint8_t pos = 0;
  while (pos < lcdSpalten)
  {
    delay(300);
    zeile2[pos] = '*';
    ausgabe("Booting", zeile2);
    pos++;
  }
}

Damit die beiden Bedingungen auch erfüllt sind musste noch das geändert werden:

Spalte 230 display.cursor(); rein
Spalte 273 display.noBlink(); raus
Spalte 277 display.noBlink(); raus

Und hier nochmal komplett mit den Änderungen, damit die 2 Bedingungen auch erfüllt sind:

#define debug
#define ff
//#define ag

#ifdef ff
  #undef ag
  #undef debug
#endif

#ifdef debug
  #define DBG_PRINT(...) Serial.print(__VA_ARGS__)
  #define DBG_PRINTLN(...) Serial.println(__VA_ARGS__)
#else
  #define DBG_PRINT(...)
  #define DBG_PRINTLN(...)
#endif

const byte lcdZeilen = 2;
const byte lcdSpalten = 20;
#ifndef ag
  // EEprom
  #include <EEPROM.h>
#endif

// Rotary
#include <rotary.h>

// bedingte Kompilierung - Zuweisung der Konfigurationen
#ifdef ff
  #include <Adafruit_CharacterOLED.h>
  Adafruit_CharacterOLED display(OLED_V2, 4, 6, 5, 7, 8, 9, 10); // RotKurz Blau RotLang Lila Grün Weiß Gelb
  Rotary r = Rotary(2, 3); // Hier muss ff seine Konfig rein
  const byte rotBut = 13;
  const byte mutBut = 12;
  const byte mutLed = 255;
#elif ag
  #include <Wire.h>
  #include <LiquidCrystal_I2C.h>
  const byte lcdAddress = 0x27;
  LiquidCrystal_I2C display(lcdAddress, lcdSpalten, lcdZeilen);
  Rotary r = Rotary(3, 2);
  const byte rotBut = 11;
  const byte mutBut = 12;
  const byte mutLed = LED_BUILTIN;
#else
  #include <LiquidCrystal_I2C.h>
  const byte lcdAddress = 0x27;
  LiquidCrystal_I2C display(lcdAddress, lcdSpalten, lcdZeilen);

  Rotary r = Rotary(45, 43);
  const byte rotBut = 41;
  const byte mutBut = 12;
  const byte mutLed = LED_BUILTIN;
#endif

enum {ungedrueckt, kurz, lang};

const uint32_t bounceTime = 20; // zeit in ms
// Inhalt
struct inhalt
{
  char name[lcdSpalten + 1];
  char hid[2];
};
#include "hidTable.h"

inhalt MyFilter[]
{
  {"Filter 1", ""}, {"Filter 2", "s"},
  {"Filter 3", "d"}, {"Filter 4", "f"},
};

inhalt MyWlan[]
{
  {"Wlan 1", "e"}, {"Wlan 2", "e"},
};

inhalt MyPlatzhalter[]
{
  {"Platzhalter 1", "y"}, {"Platzhalter 2", "x"},
  {"Platzhalter 3", "c"}, {"Platzhalter 4", "v"},
  {"Platzhalter 5", "b"},
};

char mySetup[][lcdSpalten + 1] =
{
  "Auswahl", "Displayzeit", "Wlan", "Bezeichner",
  "Platzhalter1", "Platzhalter2", "Platzhalter3",   // Platzhalter wird durch MyPlatzhalter
  "Platzhalter4", "Platzhalter5"                    // aus dem EEprom ersetzt!
};

uint8_t displayZeit = 20;                           // Zeit in Sekunden bis abschalten
uint32_t displayTick = 0;                           // Merker für letzte Aktion am Encoder oder Button

char displayZeileOben[lcdSpalten + 1] = {'\0'};     // Globale Variablen für DisplayZeilen
char displayZeileUnten[lcdSpalten + 1] = {'\0'};

bool isMenu = true;
bool isSetup = !isMenu;
bool isMute = false;

void setup()
{
#ifdef ff
  Serial.begin(9600);
#else
  Serial.begin(115200);
#endif
  DBG_PRINTLN(F("Start..."));
  pinMode (rotBut, INPUT);
  pinMode (mutBut, INPUT_PULLUP);
  pinMode (mutLed, OUTPUT);
#ifdef ff
  display.begin(lcdSpalten, lcdZeilen);
  startSequenz();
#elif ag
  Wire.begin();
  display.begin();
  display.backlight();
#else
  display.begin();
#endif
#ifndef ag
  //updateEEprom();                                  // Nur einmalig aufrufen;
    if (EEPROM.read(0) == 255) updateEEprom();
  // ---
  readEEprom();                                    // Holt die Variablen aus dem EEprom
#endif
  displayTick = millis();
}
//
void loop()
{
  if (isMute)
  {
    heartbeat(500);
    ausgabe("Mute aktiv", "");
  }
  else
  {
    if (digitalRead(mutLed))                      // wenn nicht Mute
      digitalWrite(mutLed, LOW);                  // sicherstellen, das aus
    if (isMenu) filterMenu();
    if (isSetup) setupMenu();
  }
  setMute();
  isDisplay();
}
//
bool editBezeichner()                             // Ein Versuch - wird ggfls. noch aufgelöst
{
  const char bezeichner[][lcdSpalten + 1] =
  {"Filtertexte", "Filterkey", "Wlantexte", "Wlalkey", "Platztexte", "Platzkey"}; //, "Setuptexte" hier rausgenommen
  const uint8_t num = sizeof(bezeichner) / sizeof(bezeichner [0]) - 1;
  static uint8_t schritt = 0;
  static uint8_t rotaryPos = 0;
  static uint8_t auswahl[2] = {0};
  const uint8_t minPos = 0;
  static bool returnWert = false;
  static uint8_t spalte = 0;
  static char editZeile[lcdSpalten + 1] = {'\0'};
  if (!returnWert) // Wenn erster Aufruf, init der Var
  {
    returnWert = true;
    schritt = rotaryPos = auswahl[0] = 0;
    memset(editZeile, '\0', lcdSpalten + 1);
  }
  switch (schritt)
  {
    case 0:  // Hauptmenu
      {
        menuAuswahl(rotaryPos, minPos, num, "Editieren", bezeichner[rotaryPos]);
        switch (getTaste())
        {
          case kurz:
            memset(displayZeileOben, '\0', lcdSpalten + 1);
            strcpy(displayZeileOben, bezeichner[rotaryPos]);
            auswahl[0] = auswahl[1] = rotaryPos;
            rotaryPos = 0;
            schritt = 1;
            break;
          case lang:
            schritt = 99;
            break;
        }
      }
      break;
    case 1:
      if (auswahl[1] % 2 != 0) memset(displayZeileOben, '\0', lcdSpalten + 1);
      switch (auswahl[1])
      {
        case 0:
          menuAuswahl(rotaryPos, minPos, sizeof(MyFilter) / sizeof(inhalt) - 1, displayZeileOben, MyFilter[rotaryPos].name);
          strcpy(editZeile, MyFilter[rotaryPos].name);
          break;
        case 1:
          strcpy(displayZeileOben, MyFilter[rotaryPos].name);
          menuAuswahl(rotaryPos, minPos, sizeof(MyFilter) / sizeof(inhalt) - 1, displayZeileOben, MyFilter[rotaryPos].hid);
          strcpy(editZeile, MyFilter[rotaryPos].hid);
          break;
        case 2:
          menuAuswahl(rotaryPos, minPos, sizeof(MyWlan) / sizeof(inhalt) - 1, displayZeileOben, MyWlan[rotaryPos].name);
          strcpy(editZeile, MyWlan[rotaryPos].name);
          break;
        case 3:
          strcpy(displayZeileOben, MyWlan[rotaryPos].name);
          menuAuswahl(rotaryPos, minPos, sizeof(MyWlan) / sizeof(inhalt) - 1, displayZeileOben, MyWlan[rotaryPos].hid);
          strcpy(editZeile, MyWlan[rotaryPos].hid);
          break;
        case 4:
          menuAuswahl(rotaryPos, minPos, sizeof(MyPlatzhalter) / sizeof(inhalt) - 1, displayZeileOben, MyPlatzhalter[rotaryPos].name);
          strcpy(editZeile, MyPlatzhalter[rotaryPos].name);
          break;
        case 5:
          strcpy(displayZeileOben, MyPlatzhalter[rotaryPos].name);
          menuAuswahl(rotaryPos, minPos, sizeof(MyPlatzhalter) / sizeof(inhalt) - 1, displayZeileOben, MyPlatzhalter[rotaryPos].hid);
          strcpy(editZeile, MyPlatzhalter[rotaryPos].hid);
          break;
        case 6: // Da mySetup.hid nicht gesetzt wird, muss das der letzte Eintrag sein!
          uint8_t auswahlPunkte = sizeof(mySetup) / sizeof(mySetup[0]) - 1 - sizeof(MyPlatzhalter) / sizeof(MyPlatzhalter[0]);
          menuAuswahl(rotaryPos, minPos, auswahlPunkte, displayZeileOben, mySetup[rotaryPos]);
          strcpy(editZeile, mySetup[rotaryPos]);
          break;
      }
      switch (getTaste())
      {
        case kurz:
          spalte = 0;
          display.blink();
          display.cursor();
          display.setCursor(spalte, 1);
          display.print(editZeile);
          for (uint8_t b = strlen(editZeile); b < lcdSpalten; b++) display.print(' ');
          display.setCursor(spalte, 1);
          schritt = 2;
          break;
        case lang:
          schritt = 0;
          rotaryPos = auswahl[0];
          break;
      }
      break;
    case 2:
      {
        const uint8_t minZeichen = 32;
        const uint8_t maxZeichen = 125;
        uint8_t buchstabe = maxZeichen;
        if (editZeile[spalte] < minZeichen)editZeile[spalte] = minZeichen;
        if (auswahl[1] % 2 == 0)
        {
          if (editZeile[spalte] > maxZeichen)editZeile[spalte] = maxZeichen;
          buchstabe = uint8_t(editZeile[spalte]);
          setupZahl(buchstabe, minZeichen, maxZeichen);
        }
        else
        {
          if (editZeile[spalte] == 32 || editZeile[spalte] == '\0') editZeile[spalte] = 96;
          buchstabe = editZeile[spalte];
          setupZahl(buchstabe, 96, 122);
          if (buchstabe == 96) buchstabe = 32;
        }
        if (uint8_t(editZeile[spalte]) != buchstabe)
        {
          display.setCursor(spalte, 1);
          display.print(char(buchstabe));
          display.setCursor(spalte, 1);
          editZeile[spalte] = buchstabe;
        }
        switch (getTaste())
        {
          case kurz:
            spalte++;
            if (auswahl[1] % 2 == 0) {if (spalte >= lcdSpalten) spalte = 0;} // Wenn Text am Zeilenende
            else {spalte = 0;}                                                 // Wenn hid immer erste Position no.Blink noCursor war hier noch mit drin, wegen Edit HID Key, jetzt blinken die immer auch nach kurzen Bestätigen
            display.setCursor(spalte, 1);
            break;
          case lang:
            //display.noBlink();  // bewirkt scheinbar nichts
            //display.noCursor();  // bewirkt scheinbar nichts
            int8_t c = sizeof(editZeile) - 1;
            while (c >= 0 && !isGraph(editZeile[c]))                         // Entfernt Leerzeichen etc am Ende
            {
              editZeile[c] = '\0';
              c--;
            }
            switch (auswahl[1])
            {
              case 0: memcpy(MyFilter[rotaryPos].name, editZeile, sizeof(MyFilter[rotaryPos].name) - 1); break;
              case 1: memcpy(MyFilter[rotaryPos].hid, editZeile, sizeof(MyFilter[rotaryPos].hid) - 1); break;
              case 2: memcpy(MyWlan[rotaryPos].name, editZeile, sizeof(MyWlan[rotaryPos].name) - 1); break;
              case 3: memcpy(MyWlan[rotaryPos].hid, editZeile, sizeof(MyWlan[rotaryPos].hid) - 1); break;
              case 4: memcpy(MyPlatzhalter[rotaryPos].name, editZeile, sizeof(MyPlatzhalter[rotaryPos].name) - 1); break;
              case 5: memcpy(MyPlatzhalter[rotaryPos].hid, editZeile, sizeof(MyPlatzhalter[rotaryPos].hid) - 1); break;
              case 6: memcpy(mySetup[rotaryPos], editZeile, sizeof(mySetup[rotaryPos]) - 1); break;
            }
            memset(editZeile, '\0', lcdSpalten + 1);
            updateEEprom();
            schritt = 1;
            ausgabe("", "");
            break;
        }
      }
      break;
    case 99:
      auswahl[0] = 0;
      returnWert = false;
      break;
  }
  if (!isDisplay())
  {
    display.noBlink();
   // display.noCursor();
    returnWert = false;
  }
  return returnWert;
}
//
void setupMenu()
{
  const uint8_t maxPos = sizeof(mySetup) / sizeof(mySetup[0]); // Anzahl der Elemente ermitteln
  const uint8_t minPos = 1;                                    // Der Eintrag 0 ist kein Menueintrag
  static uint8_t rotaryPos = minPos;
  static uint8_t menuPos = 0;
  static uint8_t subMenuPos = 0;                               // Hilfsvariable für Untermenu
  static uint32_t startzeit = 0;
  switch (menuPos)
  {
    case 0:
      {
        char buf[lcdSpalten + 1] = {'\0'};
        strcpy(buf, mySetup[rotaryPos]);
        if (millis() - startzeit < 300)
          buf[strlen(mySetup[rotaryPos]) - 1] = '*';
        menuAuswahl(rotaryPos, minPos, maxPos - 1, mySetup[0], buf);
        switch (getTaste())
        {
          case kurz:
            menuPos = rotaryPos;                               // Wenn ausgewählt: menuPos setzen
            if (menuPos == 2) subMenuPos = 0;                  // wenn Submenu gebraucht wird
            else startzeit = millis();
            break;
          case lang:
            menuPos = maxPos;
            break;
        }
      }
      break;
    case 1: // Die displayZeit wird
      displayTime(mySetup[menuPos], displayZeit);             // direkt geändert
      if (getTaste() == kurz)                                 // verlassen des Menupunktes
      {
        menuEnde(menuPos, mySetup[0], mySetup[menuPos]);      // zurücksetzen auf eine Ebene höher
        updateEEprom();
      }
      break;
    case 2:                                                   // Wlan
      {
        char buf[lcdSpalten + 1] = {'\0'};
        strcpy(buf, MyWlan[subMenuPos].name);
        if (millis() - startzeit < 300) buf[strlen(MyWlan[subMenuPos].name) - 1] = '*';
        menuAuswahl(subMenuPos, 0 , 1, mySetup[menuPos], buf);
        switch (getTaste())
        {
          case kurz:
            startzeit = millis();
            sendHid(MyWlan[subMenuPos].hid);
            break;
          case lang:
            menuEnde(menuPos, mySetup[2], mySetup[subMenuPos]);
            break;
        }
      }
      break;
    case 3:                                                  // Texte ändern
      if (!editBezeichner())
      {
        DBG_PRINTLN("ENDE");
        menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      }
      break;
    case 4:
      DBG_PRINTLN(F("Platzhalter1"));
      sendHid(MyPlatzhalter[0].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
    case 5:
      DBG_PRINTLN(F("Platzhalter2"));
      sendHid(MyPlatzhalter[1].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
    case 6:
      DBG_PRINTLN(F("Platzhalter3"));
      sendHid(MyPlatzhalter[2].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
    case 7:
      DBG_PRINTLN(F("Platzhalter4"));
      sendHid(MyPlatzhalter[3].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
    case 8:
      DBG_PRINTLN(F("Platzhalter5"));
      sendHid(MyPlatzhalter[4].hid);
      menuEnde(menuPos, mySetup[0], mySetup[menuPos]);
      break;
  }
  if (!isDisplay() || (menuPos == maxPos)) // Wenn der Display aus geht ODER maxPos (exit) ausgelöst
  {
    menuPos = 0; // alles zurücksetzen
    rotaryPos = minPos;
    isMenu = true; isSetup = false;
  }
}
//
// Die folgende Funktion ist für die Auswahl und Übergabe jeweiliger
// Menueinträge vorgesehen. Die sich ständig wiederholenden Abfragen
// des RotaryEncoders in den unterschiedlichen Menus zusammengefasst
// rotaryPos ist die aktuelle Position, die einzige die veränderlich ist ;)
void menuAuswahl(uint8_t &rotaryPos, const uint8_t &minPos,
                 const uint8_t &maxPos, const char *zeile1, const char *zeile2)
{
  unsigned char val = r.process();
  if (val && isDisplay())
  {
    if (val == r.clockwise())
    {
      if (rotaryPos >= maxPos) rotaryPos = minPos;
      else rotaryPos++;
    }
    else if (val == r.counterClockwise())
    {
      if (rotaryPos <= minPos) rotaryPos = maxPos;
      else rotaryPos--;
    }
    displayTick = millis();
  }
  ausgabe(zeile1, zeile2);
}
//
void filterMenu()                                                 // filterauswahl ist default
{
  memset(displayZeileOben, '\0', lcdSpalten + 1);                 // Zeile leeren
  strcpy(displayZeileOben, "Filter waehlen");                     // und neu befüllen
  const uint8_t maxPos = sizeof(MyFilter) / sizeof(inhalt) - 1;
  const uint8_t minPos = 0;
  static uint8_t rotaryPos = 0;
  static uint32_t startzeit = 0;
  if (isDisplay())                                                // Nur wenn Display an ist
  {
    // Übergeben wird die (sich nicht mehr ändernde) obere Zeile und der Inhalt
    // aus dem Struct. Darstellung wird dann in der Funktion menuAuswahl() gebaut
    char buf[lcdSpalten + 1] = {'\0'};
    strcpy(buf, MyFilter[rotaryPos].name);
    if (millis() - startzeit < 300)
      buf[strlen(MyFilter[rotaryPos].name) - 1] = '*';
    menuAuswahl(rotaryPos, minPos, maxPos, displayZeileOben, buf);
  }
  switch (getTaste())                                             // Tastenabfrage
  {
    case kurz:
      sendHid(MyFilter[rotaryPos].hid);
      startzeit = millis();
      break;
    case lang: isMenu = false; isSetup = true; break;
  }
}
//
void displayTime(char *zeile1, uint8_t &sekunde)                  // Einstellen der DisplayTime
{
  setupZahl(sekunde); // Sekunde verstellen
  if (sekunde < 5) sekunde = 5;
  memset(displayZeileUnten, '\0', lcdSpalten + 1);                // untere DisplayZeile leeren
  sprintf(displayZeileUnten, "%d", sekunde);                      // und mit Zahl füllen
  ausgabe(zeile1, displayZeileUnten);                             // und ausgeben
}
//
void setupZahl(uint8_t &aenderZahl, const uint8_t &minZahl, const uint8_t &maxZahl)
{
  // Serial.print(aenderZahl); Serial.print(' '); Serial.print(minZahl); Serial.print(' '); Serial.println(maxZahl);
  uint32_t myZahl = aenderZahl;
  setupZahl(myZahl);
  if (myZahl > maxZahl) myZahl = minZahl;
  if (myZahl < minZahl) myZahl = maxZahl;
  aenderZahl = myZahl;
}
void setupZahl(uint8_t &aenderZahl) // Je nach Größe der
{
  uint32_t myZahl = aenderZahl;
  setupZahl(myZahl, 255);
  aenderZahl = myZahl;
}
void setupZahl(uint16_t &aenderZahl) // übergebenen Zahl
{
  uint32_t myZahl = aenderZahl;
  setupZahl(myZahl, 65535); // begrenzen des Zählers
  aenderZahl = (uint16_t)myZahl;
}
void setupZahl(uint32_t &aenderZahl, const uint32_t &maxZahl)
{
  setupZahl(aenderZahl);
  if (aenderZahl > maxZahl) aenderZahl = 0;
}
void setupZahl(uint32_t &aenderZahl)
{
  unsigned char val = r.process();
  if (val && isDisplay()) // und hier einfach nur auf/ab zaehlen
  {
    if (val == r.clockwise())
      aenderZahl++;
    if (val == r.counterClockwise())
      aenderZahl--;
    displayTick = millis(); // und dem Merker sagen, das sich was bewegt hat
  }
}
//
void menuEnde(uint8_t &menuPos, char *zeile1, char *zeile2)
{
  menuPos = 0;
  ausgabe(zeile1, zeile2);
}
//
uint8_t findeZeichen(char zeichen)
{
  uint8_t position = 255;
  for (uint8_t h = 0; h < hidNums; h++)
  {
    uint8_t hidSeq = pgm_read_byte_near(&hidTable[h].zeichen);
    if (hidSeq == zeichen) position = h;
  }
  return position;
}
//
void sendHid(char *zeichen)
{
  DBG_PRINT(F("HID: "));
  DBG_PRINT(zeichen);
  DBG_PRINT(F("\tCode: "));
  uint8_t h = findeZeichen(zeichen[0]);
  if (h < 255)
  {
    DBG_PRINT(zeichen[0]);
    for (uint8_t b = 0; b < 8; b++)
    {
      uint8_t hidByte = pgm_read_byte_near(&hidTable[h].hidcode[b]);
      DBG_PRINT(' '); DBG_PRINT(hidByte, HEX);
#ifndef debug
      Serial.write(hidByte);
      const uint8_t none[8] = {0, 0, 0, 0, 0, 0, 0, 0};
      Serial.write(none, 8); // Relaese
#endif
    }
    DBG_PRINTLN();
  }
}
//
void printDisplay(char *zeile, byte number)                    // Displayzeile und welche Zeilennummer
{
  display.setCursor(0, number);                                // cursor setzen
  uint8_t laenge = strlen(zeile);                              // wie lang ist die Zeichenkette?
  for (byte b = 0; b < (lcdSpalten - laenge) / 2; b++)         // Errechnen der ersten Hälfte die
    display.print(' ');                                        // mit Leerzeichen aufgefüllt
  display.print(zeile);                                        // Ausgabe der Zeile
  for (byte b = (lcdSpalten - laenge) / 2 + laenge; b < lcdSpalten; b++)
    display.print(' ');                                        // Auffüllen der Zeile bis Ende mit Spaces
  DBG_PRINT(F("Zeile "));
  DBG_PRINT(number + 1);
  DBG_PRINT(": ");
  DBG_PRINTLN(zeile);
}
//
void ausgabe(const char *zeile1, const char *zeile2)           // Übernahme beider Zeilen
{
  static char lastZeileOben[lcdSpalten + 1] = {'\0'};          // Merker der letzten Ausgabe
  static char lastZeileUnten[lcdSpalten + 1] = {'\0'};
  if (strcmp(lastZeileOben, zeile1))                           // Wenn sich der Inhalt geändert hat
  {
    memset(lastZeileOben, '\0', lcdSpalten + 1);               // Merker löschen
    strcpy(lastZeileOben, zeile1);                             // neu füllen
    printDisplay(lastZeileOben, 0);                            // und ausgeben
  }
  if (strcmp(lastZeileUnten, zeile2))
  {
    memset(lastZeileUnten, '\0', lcdSpalten + 1);
    strcpy(lastZeileUnten, zeile2);
    printDisplay(lastZeileUnten, 1);
  }
}
//
void updateEEprom()
{
  uint16_t speicherPosition = 0;
  EEPROM.put(speicherPosition, MyFilter);    // struct ablegen
  speicherPosition += sizeof(MyFilter);
  EEPROM.put(speicherPosition, displayZeit); // nächste dahinter
  speicherPosition += sizeof(displayZeit);
  EEPROM.put(speicherPosition, MyWlan);
  speicherPosition += sizeof(MyWlan);
  EEPROM.put(speicherPosition, mySetup);
  speicherPosition += sizeof(mySetup);
  EEPROM.put(speicherPosition, MyPlatzhalter);
  speicherPosition += sizeof(MyPlatzhalter);
  // Jeder neue Eintrag hier muss auch in readEEprom!
  //
  readEEprom();                              // Nach der Platzhalteränderung hier geändert
}
void readEEprom()
{
  uint16_t speicherPosition = 0;             // Start auszulesende Zelle
  EEPROM.get(speicherPosition, MyFilter);    // ... dann holen ...
  speicherPosition += sizeof(MyFilter);      // Nächster Eintrag beginnt an
  EEPROM.get(speicherPosition, displayZeit); // ... dann holen ...
  speicherPosition += sizeof(displayZeit);
  EEPROM.get(speicherPosition, MyWlan);
  speicherPosition += sizeof(MyWlan);
  EEPROM.get(speicherPosition, mySetup);
  speicherPosition += sizeof(mySetup);
  EEPROM.get(speicherPosition, MyPlatzhalter);
  // Ersetzen der Platzhalterbezeichnungen durch die EEPromWerte!
  for (byte b = 0; b < sizeof(MyPlatzhalter) / sizeof(inhalt); b++)
    memcpy(mySetup[b + 4], MyPlatzhalter[b].name, lcdSpalten);
  //
  speicherPosition += sizeof(MyPlatzhalter);
  // Ab hier neue Einträge! Auch in updateEEprom hinterlegen!
  //
}
//
bool isDisplay()
{
  static bool lastReturn = false;
  if (millis() - displayTick > displayZeit * 1000UL && !isMute && !isSetup)
  {
    ausgabe(" ", " ");
    display.noDisplay();
    lastReturn = false;
    return false;
  }
  display.display();
  if (!lastReturn)
  {
    ausgabe ("", ""); lastReturn = true;
  }
  return true;
}
//
void setMute()
{
  static uint32_t lastmillis = 0;
  static bool isPressed = false;
  if (!digitalRead(mutBut) && !isPressed)
  {
    isPressed = true;
    displayTick = millis();
    lastmillis = millis();
    isMute = !isMute;
    DBG_PRINT(F(""));
    char a[] = "a";
    sendHid(a);
  }
  else if ((millis() - lastmillis > bounceTime) &&
           (digitalRead(mutBut) && isPressed))
  {
    isPressed = false;
  }
}
//
uint8_t getTaste()
{
  uint8_t butPress = ungedrueckt;
  static uint32_t pressTime = 0;
  static byte schritt = 0;
  bool isPressed = !digitalRead(rotBut);
  switch (schritt)
  {
    default:
      if (isPressed)
      {
        pressTime = millis();
        schritt = 1;
      }
      break;
    case 1:
      if (millis() - pressTime > bounceTime)
        isPressed ? schritt = 2 : schritt = 0;
      break;
    case 2:
      if (!isDisplay())
      {
        schritt = 3;
      }
      else if (!isPressed)
      {
        butPress = kurz;
        schritt = 3;
      }
      else
      {
        if (millis() - pressTime > 500)
        {
          butPress = lang;
          schritt = 3;
        }
      }
      break;
    case 3:
      displayTick = millis();
      if (!isPressed)
      {
        schritt = 0;
      }
      break;
  }
  return butPress;
}
//
void heartbeat(const uint32_t tik)
{
  static uint32_t lasttik = 0;
  if (millis() - lasttik >= tik)
  {
    lasttik += tik;
    digitalWrite(mutLed, !digitalRead(mutLed));
  }
}
//
void startSequenz()
{
  ausgabe("Willkommen", "");
  delay(1000);
  ausgabe("Booting...", "");
  delay(1000);
  char zeile2[lcdSpalten + 1] = {'\0'};
  uint8_t pos = 0;
  while (pos < lcdSpalten)
  {
    delay(200);
   zeile2[pos] = '\67'; // zeile2[pos] = '-';
    ausgabe("Booting...", zeile2);
    pos++;
  }
}

An dem Punkt kann ich einfach überhaupt nicht ausdrücken wie happy ich bin, vielen vielen lieben Dank nochmal an die Beiden hier die sich auf so eine lange Reise eingelassen haben. :+1: :+1:

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.