struct für Dummies

Hallo liebes Forum!
Und ganz besonders:
Hallo Doc!

Ich möchte endlich mal den Umgang mit Strukturen lernen, aber das Brett vor meinem Kopf hindert mich mal wieder daran, das Prinzip zu verstehen.
Zum Üben habe ich mir einen "großflächigen" Sketch mit simpelster Funktion gezimmert, den ich (wenn möglich mit Hilfe) Stück für Stück (und hoffentlich für andere, die ebenfalls Bretter vorm Kopf haben nachvollziehbar) umbauen möchte.
DocArduino hat mir ja schon einen Sketch mit Strukt vorgestellt, aber leider fehlt mir da ein Meter Verständniss.

Bitte zerreißt mich nicht dafür, das hat nichts mit Faulheit zu tun, eher mit Begriffsstutzigkeit.
Ich hoffe, es macht bald Klick... :confused:

Also, hier der simpel-Code, den ich optimieren möchte:

/*
 * struct Lernsketch
 */

int Anzahl = 3; // Anzahl der Taster/ LED

int Taster1 = 2;
unsigned long Entprell1 = 0; 
int LED1 = 3;
bool LEDMerker1 = LOW;
bool TasterStatus1 = LOW;
bool TasterMerker1 = LOW;

int Taster2 = 4;
unsigned long Entprell2 = 0; 
int LED2 = 5;
bool LEDMerker2 = LOW;
bool TasterStatus2 = LOW;
bool TasterMerker2 = LOW;

int Taster3 = 7;
unsigned long Entprell3 = 0; 
int LED3 = 7;
bool LEDMerker3 = LOW;
bool TasterStatus3 = LOW;
bool TasterMerker3 = LOW;


int Entprellpause = 200;

void setup() {
 pinMode(Taster1, INPUT);
 pinMode(Taster2, INPUT);
 pinMode(Taster3, INPUT);
 pinMode(LED1, OUTPUT);
 pinMode(LED2, OUTPUT);
 pinMode(LED3, OUTPUT);
}

void loop() {

//Taster1************************************************************
TasterStatus1 = digitalRead(Taster1);
if(TasterStatus1 == HIGH && TasterMerker1 == LOW)
  {
  TasterMerker1 == HIGH;
  Entprell1 = millis();
  }
if((millis() - Entprell1 < Entprellpause) && TasterMerker1 == HIGH && LEDMerker1 == LOW)
{
  TasterMerker1 = LOW;
  LEDMerker1 = HIGH;
  digitalWrite(LED1, HIGH);
}
if((millis() - Entprell1 < Entprellpause) && TasterMerker1 == HIGH && LEDMerker1 == HIGH)
{
  TasterMerker1 = LOW;
  LEDMerker1 = LOW;
  digitalWrite(LED1, LOW);
}

//Taster2************************************************************
TasterStatus2 = digitalRead(Taster2);
if(TasterStatus2 == HIGH && TasterMerker2 == LOW)
  {
  TasterMerker2 == HIGH;
  Entprell2 = millis();
  }
if((millis() - Entprell2 < Entprellpause) && TasterMerker2 == HIGH && LEDMerker2 == LOW)
{
  TasterMerker2 = LOW;
  LEDMerker2 = HIGH;
  digitalWrite(LED2, HIGH);
}
if((millis() - Entprell2 < Entprellpause) && TasterMerker2 == HIGH && LEDMerker2== HIGH)
{
  TasterMerker2 = LOW;
  LEDMerker2 = LOW;
  digitalWrite(LED2, LOW);
}

//Taster3************************************************************
TasterStatus3 = digitalRead(Taster3);
if(TasterStatus3 == HIGH && TasterMerker3 == LOW)
  {
  TasterMerker3== HIGH;
  Entprell3 = millis();
  }
if((millis() - Entprell3 < Entprellpause) && TasterMerker3 == HIGH && LEDMerker3 == LOW)
{
  TasterMerker3 = LOW;
  LEDMerker3 = HIGH;
  digitalWrite(LED2, HIGH);
}
if((millis() - Entprell3 < Entprellpause) && TasterMerker3 == HIGH && LEDMerker3 == HIGH)
{
  TasterMerker3 = LOW;
  LEDMerker3 = LOW;
  digitalWrite(LED3, LOW);
}
}

Das erste was ich mir wünschen würde wäre, den Pinmode mit einer for- Schleife zu "erschlagen" (wie der Doktor auch schon beschrieben hat).
Leider habe ich noch nicht verstanden, wie das geht.
Bitte seid mir nicht böse....

Könnte ich noch eine Denkhilfe von euch bekommen?

In C++ sind Klassen und Strukturen fast gleich. Anleitungen für Klassen funktionieren daher genauso auch für Strukturen.

struct Pin
{
   const byte pin;
   unsigned long time;
   bool status;
   ...

   Pin(const byte pin) : pin(pin), time(0), status(LOW)
   {
   }
};

Pin pins[] = { 2, 3, 4 };

void setup()
{
    for (Pin& pin : pins)
    {   
       pinMode(pin.pin, OUTPUT);
    }
}

Stichworte:

  • Konstruktor
  • Initialisierungsliste
  • range based for loop / for each

Erster Schritt: Den Ausgangssketch richtig machen:

const byte Anzahl = 3; // Anzahl der Taster/ LED

const byte Taster1 = 2;
const byte LED1 = 3;
unsigned long Entprell1 = 0;
bool LEDMerker1 = LOW;
bool TasterStatus1 = LOW;
bool TasterMerker1 = LOW;

Das dann für alle Taster und Leds. Konstantennamen könnte man groß, Variablennamen klein schreiben.

agmue:
Erster Schritt: Den Ausgangssketch richtig machen...

Bitte entschuldigt, dass ich für das Antworten so lange brauche. Bin gerade nicht ganz auf der Höhe.

Also Schritt eins habe ich.
Warum sollte man da Konstantnamen nehmen?

/*
* struct Lernsketch
*/
const byte TASTER1 = 2;
unsigned long Entprell1 = 0; 
const byte LED1 = 3;
bool LedMerker1 = LOW;
bool TasterStatus1 = LOW;
bool TasterMerker1 = LOW;

const byte TASTER2 = 4;
unsigned long Entprell2 = 0; 
const byte LED2 = 5;
bool LedMerker2 = LOW;
bool TasterStatus2 = LOW;
bool TasterMerker2 = LOW;

const byte TASTER3 = 7;
unsigned long Entprell3 = 0; 
const byte LED3 = 7;
bool LedMerker3 = LOW;
bool TasterStatus3 = LOW;
bool TasterMerker3 = LOW;


int Entprellpause = 200;

void setup() {
pinMode(TASTER1, INPUT);
pinMode(TASTER2, INPUT);
pinMode(TASTER3, INPUT);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
}

void loop() {

//Taster1************************************************************
TasterStatus1 = digitalRead(TASTER1);
if(TasterStatus1 == HIGH && TasterMerker1 == LOW)
 {
 TasterMerker1 == HIGH;
 Entprell1 = millis();
 }
if((millis() - Entprell1 < Entprellpause) && TasterMerker1 == HIGH && LedMerker1 == LOW)
{
 TasterMerker1 = LOW;
 LedMerker1 = HIGH;
 digitalWrite(LED1, HIGH);
}
if((millis() - Entprell1 < Entprellpause) && TasterMerker1 == HIGH && LedMerker1 == HIGH)
{
 TasterMerker1 = LOW;
 LedMerker1 = LOW;
 digitalWrite(LED1, LOW);
}

//Taster2************************************************************
TasterStatus2 = digitalRead(TASTER2);
if(TasterStatus2 == HIGH && TasterMerker2 == LOW)
 {
 TasterMerker2 == HIGH;
 Entprell2 = millis();
 }
if((millis() - Entprell2 < Entprellpause) && TasterMerker2 == HIGH && LedMerker2 == LOW)
{
 TasterMerker2 = LOW;
 LedMerker2 = HIGH;
 digitalWrite(LED2, HIGH);
}
if((millis() - Entprell2 < Entprellpause) && TasterMerker2 == HIGH && LedMerker2== HIGH)
{
 TasterMerker2 = LOW;
 LedMerker2 = LOW;
 digitalWrite(LED2, LOW);
}

//Taster3************************************************************
TasterStatus3 = digitalRead(TASTER3);
if(TasterStatus3 == HIGH && TasterMerker3 == LOW)
 {
 TasterMerker3== HIGH;
 Entprell3 = millis();
 }
if((millis() - Entprell3 < Entprellpause) && TasterMerker3 == HIGH && LedMerker3 == LOW)
{
 TasterMerker3 = LOW;
 LedMerker3 = HIGH;
 digitalWrite(LED2, HIGH);
}
if((millis() - Entprell3 < Entprellpause) && TasterMerker3 == HIGH && LedMerker3 == HIGH)
{
 TasterMerker3 = LOW;
 LedMerker3 = LOW;
 digitalWrite(LED3, LOW);
}
}

Serenifly:
In C++ sind Klassen und Strukturen fast gleich. Anleitungen für Klassen funktionieren daher genauso auch für Strukturen.

struct Pin

{
  const byte pin;
  unsigned long time;
  bool status;
  ...

Pin(const byte pin) : pin(pin), time(0), status(LOW)
  {
  }
};

Pin pins[] = { 2, 3, 4 };

void setup()
{
   for (Pin& pin : pins)
   {  
      pinMode(pin.pin, OUTPUT);
   }
}




Stichworte:
- Konstruktor
- Initialisierungsliste
- range based for loop / for each

Das ist mir im Moment nochn zu hoch... :blush:

Wie gesagt, du kannst dir Anleitungen dazu durchlesen die das alles erklären. Da gibt es unendlich Material im Netz wenn du nach den richtigen Begriffen suchst

Ich denke, der Hinweis, dass Klassen und Strukturen in C++ fast das gleiche ist, ist nicht sehr hilfreich, wenn man von beidem noch keine Ahnung hat.
Mal davon abgesehen, dass ich das sogar für einen Nachteil der Sprache C++ halte. Klassen und reine Datenstrukturen sollte man logisch getrennt halten. Auch wenn gewisse Verwandschft besteht.
Was man in C++ ja auch durchaus machen kann - wenn man will 8) . Nicht umsonst haben die Macher von C++ da ein eigenes Schlüsselwort 'class' kreiert, obwohl sie mit neuen Schlüsselworten ansonsten sehr zurückhaltend sind.

@To: Datenstrukturen sind sozusagen ein 'Container' für zusammengehörige Daten. Man packt die Daten, die logisch zusammengehören in eine 'Kiste' gibt der Kiste einen Namen und das nennt man dann eine Struktur.
Zu deinem Beispiel: Die Struktur ( die 'Datenkiste' :wink: ) enthält dann alle Werte, die für einen Taster relevant sind. Und dann brauchst Du eben für jeden Taster so eine Struktur. Um auf ein Element deiner Datenstruktur zuzugreifen, brauchst Du jetzt 2 Namen: Den Namen der Struktur, und den Namen des enthaltenen Datenelementes. Die werden dann durch einen Punkt getrennt. ( Da sieht man die Verwandschaft zu Klassen schon, aber das lassen wir jetzt mal beiseite )
Bezogen auf deinen Beispielsketch oben, kannst Du auch mehrere solcher gleichartigen Kisten in einem Array zusammenfassen. Das ist dann ein 'Array of structs'.

Btw: sind dir denn Arrays klar? Sonst sollte man vielleicht damit anfangen, bevor man sich mit Strukturen beschäftigt. Auch wenn das nicht unmittelbar zusammenhängt, kann man es doch oft gemeinsam nutzen, wie dein Beispielsketch zeigt. Und um die PinMode ( und noch einiges mehr ) in einer for-Schleife zu erschlagen, brauchst Du vor allen ein Array, da hilft ein struct erstmal nichts.

Edit: Du solltest in der IDE auch mal die Compiler-Warnungen einschalten. Da gibt's oft recht nützliche Hinweise :wink:

nochmal Edit: als Beispiel für das Anlegen einer solchen Datenkiste ( noch ohne Array, nur als Beispiel )

struct taster_t {
  const byte TasterPin;
  unsigned long Entprell;
  const byte LED;
  bool LEDMerker;
  bool TasterStatus;
  bool TasterMerker;
};

taster_t Tast1 = { 2,0,3,LOW,LOW,LOW };
taster_t Tast2 = { 4,0,5,LOW,LOW,LOW };
taster_t Tast3 = { 7,0,3,LOW,LOW,LOW };

Zugriff auf einen Wert dann z.B.

  pinMode(Tast1.LED, OUTPUT);
1 Like

MicroBahner:
Ich denke, der Hinweis, dass Klassen und Strukturen in C++ fast das gleiche ist, ist nicht sehr hilfreich, wenn man von beidem noch keine Ahnung hat.

Es geht darum dass man auf Google nicht nach "Strukturen C++" sucht. Sehr viele Leute scheitern daran dass sie nach den falschen Begriffen suchen. Zu Strukturen findet man zwar auch Sachen, klar, aber bei Klassen findet man viel mehr.
Vor allem wenn es um Dinge wie Konstruktoren und Initialisierungslisten geht. Und das ist schon sinnvoll damit man nicht alle Variablen per Hand initialisieren muss

Der einzige Unterschied sind die Zugriffsrechte (public/private)

Tiff48317:
Warum sollte man da Konstantnamen nehmen?

byte TASTER1 = 2;

Legt eine Variable vom Typ byte im Variablenspeicher an. Der Variablenspeicher ist bei Arduinos (deren µCs) ein kostbares Gut, das man für Konstanten nicht verschwenden sollte.

const byte TASTER1 = 2;

Der Compiler führt eine Textersetzung einschließlich Typprüfung durch1). Außerdem wird der Versuch, eine Konstante zu verändern, mit einer Fehlermeldung quittiert.

const byte TASTER1 = 2;
const byte TASTER2 = 4;
const byte TASTER3 = 6;

kann man zusammenfassen zu einem Feld:

const byte TASTER[] = {2, 4, 6};

Ein Feld beinhaltet Elemente gleichen Typs.

Möchte man nun Konstanten oder Variablen unterschiedlichen Typs mischen, so packt man sie in eine Struktur (man hätte das auch Container, Paket oder dergleichen nennen können) (aus #6):

struct taster_t {
  const byte TasterPin;
  unsigned long Entprell;
  const byte LED;
  bool LEDMerker;
  bool TasterStatus;
  bool TasterMerker;
};

Dabei ist taster_t ein neuer Typ (byte ist ein vordefinierter Typ), der Konstanten und Variablen unterschiedlicher Typen enthält. Eine Struktur beschreibt die zu einem Taster und seiner Led zugehörige Elemente. Und ja, es ist zunächst nur eine Beschreibung, wie eine Struktur aussehen könnte, wirklich geben tut es noch keine.

Das erfolgt im nächsten Schritt, wenn drei Strukturen von Typ taster_t angelegt und mit Inhalt gefüllt werden:

               TasterPin, Entprell, LED, LEDMerker, TasterStatus, TasterMerker
taster_t Tast1 = { 2,         0,        3,   LOW,       LOW,          LOW };
taster_t Tast2 = { 4,         0,        5,   LOW,       LOW,          LOW };
taster_t Tast3 = { 6,         0,        7,   LOW,       LOW,          LOW };

Mir hat sich der Vorteil einer Struktur an dieser Stelle noch nicht offenbart, auch wenn nun "zusammensteht, was zusammengehört". Das Aha-Erlebnis kam bei mir erst später. Lasse Dich also nicht entmutigen :slight_smile:


Anm: (21.9.19, siehe auch nachfolgenden Beitrag)

  1. Mit "Compiler" meine ich alles, was beim Drücken von "Überprüfen/Compilieren" in der IDE passiert. Wenn man sich das in der ausführlichen Anzeige anschaut, ist das eine ganze Menge. Ich meine mit "Textersetzung", daß aus pinMode(Tast1.LED, OUTPUT); dann pinMode(2, OUTPUT); wird, natürlich in der für den Prozessor verständlichen Sprache. Der Name der Konstanten entfällt.

EDIT: Pinnummern korrigiert.

Hallo,

muss ich auch noch ... wurde zwar schon alles gesagt ... was solls

Mit struct (und/oder class) baust du dir deinen eigenen Datentyp zusammen. Der besteht dann eben nicht aus einem Datentyp wie bisher sondern aus genau der Reihenfolge wie angegeben. Und du kannst die Member einzeln mit Namen ansprechen/benutzen. Alles zusammengefasst, aufgeräumt, alles hübsch, weniger Kaos, weniger Variablennamen.

Zuerst erstellst du dir ein sinnvolles struct. Habe es etwas aufgeräumt. Wegen Pullup negierte Logik.
Danach kannste dir mit dem struct 3 einzelne Objekte initialisieren oder nehmen gleich ein Array (Datentyp "Daten" und Arrayname "kombiniert"), weil sich das dafür förmlich aufdrängt. Danach kannste mittels for über alle drübergehen. Wenn dir die Kurzschreibweise nicht gefällt musste vorher die Anzahl der angelegten Objekte ermitteln und verwenden. Wie du siehst ist der gesamte Sketch geschrumpft, besser lesbar und damit einfacher wartbar.

Wenn du dir mit struct/class eine Klasse baust, wandern die Funktionen hinein und nennen sich dann Methoden. Sichtbarkeit einstellen und alles notwendige ist gekapselt. Dann schreibste dir noch eine init/begin Methode und kannst dann in setup alles mit dem init/begin Methodennamen und in loop mit 2 Methodennamen in jeweils einer for erschlagen.

Thats it. Siehe auch:
https://forum.arduino.cc/index.php?topic=635910.msg4308499#msg4308499

struct Daten
{
  const byte pinTaster;
  const byte pinLed;
  bool statusLed = LOW;
  bool statusTaster = HIGH;
};

Daten kombiniert[] =
{
  {2, 28},  // Taster, Led
  {3, 29},
  {4, 30}
};

const unsigned int ENTPRELLZEIT = 40;

void setup() {

  for (Daten &d : kombiniert)
  {
    pinMode(d.pinTaster, INPUT_PULLUP);
    pinMode(d.pinLed, OUTPUT);
  }

}

void loop() {

  updateTaster(ENTPRELLZEIT);
  
  schalteLed();
  
}

void schalteLed ()
{
  for (Daten &d : kombiniert)
  {
    if (!d.statusTaster)
    {
      d.statusLed = HIGH;
    }
    else
    {
      d.statusLed = LOW;
    }
    
    digitalWrite(d.pinLed, d.statusLed);
  }
}


void updateTaster (const unsigned int intervall)
{
  static unsigned long last_ms = 0;
  unsigned long ms = millis();

  if (ms - last_ms >= intervall)
  {
    last_ms = ms;

    for (Daten &d : kombiniert)
    {
      if (!digitalRead(d.pinTaster) )
      {
        d.statusTaster = LOW;
      }
      else
      {
        d.statusTaster = HIGH;
      }
    } // for
    
  } // if
  
}

Nochwas. Der Compiler macht keine Textersetzung, dass würde der Präprozessor machen. Ist hier nicht der Fall. Für eine Datentypprüfung muss die Syntax anders lauten. Der Wert zum initialisieren muss in geschweifte Klammern. Das wäre die korrekte Syntax. Obwohl aktuelle Compiler auch mit alten Syntax eine Warnung ausgeben. Aber nur bei Ganzzahltypen.

byte value {256};     // mit Typprüfung

Verhaut man sich mit float meckert der Compiler mit alten Syntax nicht. Mit neuen Syntax stellt er fest, User schreibt einen Floatwert verwendet aber einen Ganzzahldatentyp. Passt nicht und warnt.

byte value = 0.0;     // ohne Warnung
byte value {0.0};     // Typprüfung > Warnung

Doc_Arduino:
muss ich auch noch ... wurde zwar schon alles gesagt ... was solls

Da niemand von uns die Übung haben dürfte, ein Kompendium zu schreiben, finde ich eine Betrachtung aus mehreren Blickwinkeln durchaus erhellend. Außerdem stellt sich mir immer die Frage, wie präzise ich formulieren soll, ohne es vor lauter Einschränkungen und Erläuterungen unverständlich werden zu lassen. Zur Entropie sagte der Prof: "Es gibt eine verständliche Erklärung, die ist aber falsch, und es gibt eine richtige Erklärung, die aber kaum jemand versteht."

Danke, ich habe gerade mein Wissen zur Typprüfung auffrischen können.

Mal davon abgesehen, dass ich das sogar für einen Nachteil der Sprache C++ halte. Klassen und reine Datenstrukturen sollte man logisch getrennt halten. Auch wenn gewisse Verwandschft besteht.

Das macht aus meiner Sicht gar keinen Sinn.

Denn:
C++ ist aus C mit Klassen hervorgegangen.
Und in C mit Klassen ist Struct eben "DIE" Klasse .

Es ist also keine "gewisse Verwandschaft", sondern ehr eine 1:1 Beziehung.
Eine weitgehende Differenzierung ist also verwirrender, als nötig.

Ich glaube nicht, dass man die C++ Entstehungsgeschichte, und die sich daraus ergebenen Konsequenzen, ausblenden sollte.

Vielen, vielen, vielen Dank an alle!!!
Besonders #8 wird mir sicherlich helfen, den klemmenden Schalter im Kopf ENDLICH umzulegen.

Heute Abend hab ich richtg Zeit und dann prügel ich die letzten drei verbliebenen Hirnzellen!

combie:
Ich glaube nicht, dass man die C++ Entstehungsgeschichte, und die sich daraus ergebenen Konsequenzen, ausblenden sollte.

Das sehe ich halt ein wenig anders. Die Entstehungsgeschichte erklärt zwar einiges.
Aber C++ hat sich nicht umsonst weiterentwickelt, und ich bin der Meinung, dass man so manche aus Kompatibilitätsgründen noch vorhandene Altlast nicht unbedingt in aktuellen Programmen nutzen sollte.

Edit: wobei das mMn besonders gilt, wenn man neu lernt. Bei Dingen, die man 'immer schon so' gemacht hat, ist das ja bekanntermaßen oftmals etwas schwieriger sich umzustellen. Da sind das eben auch eigene 'Altlasten' :wink: .

combie:
Ich glaube nicht, dass man die C++ Entstehungsgeschichte, und die sich daraus ergebenen Konsequenzen, ausblenden sollte.

Ich kann mich nicht daran erinnern, daß sich mein Lernen durch die C++ Entstehungsgeschichte beschleunigt hätte. Das mag aber individuell unterschiedlich sein.

Bei mir ging es eher so, daß ich prozedural Felder verwendet habe:

const byte TasterPin[] =   {  2,   4,   6};
unsigned long Entprell[] = {  0,   0,   0};
const byte LED[] =         {  3,   5,   7};
bool LEDMerker[] =         {LOW, LOW, LOW};
bool TasterStatus[] =      {LOW, LOW, LOW};
bool TasterMerker[] =      {LOW, LOW, LOW};

In der zugehörigen Funktion habe ich dann die Elemente mit gleichem Index verarbeitet. Dreht man nun die Felder um 90 Grad, erhält man die Struktur:

                TasterPin, Entprell, LED, LEDMerker, TasterStatus, TasterMerker
taster_t Tast1 = { 2,         0,        3,   LOW,       LOW,          LOW };
taster_t Tast2 = { 4,         0,        5,   LOW,       LOW,          LOW };
taster_t Tast3 = { 6,         0,        7,   LOW,       LOW,          LOW };

oder gleich so:

taster_t Tast[] =
{ //TasterPin, Entprell, LED, LEDMerker, TasterStatus, TasterMerker
  { 2,         0,        3,   LOW,       LOW,          LOW },
  { 4,         0,        5,   LOW,       LOW,          LOW },
  { 6,         0,        7,   LOW,       LOW,          LOW }
};

Meine Begeisterungskurve stieg dann allerdings erst zusammen mit Methoden von Strukturen/Klassen.

EDIT: Pinnummern korrigiert.

Wir haben früher (tm) in ANSI-C Strukturen für die Abbildung der Datenbanktabellen genutzt.
Jede Tabelle war ein struct in einer Headerdatei, dessen Pointer an die einzelnen Funktionen (insert, read, select) in der c-Datei übergeben wurde.

Das war bei großen Tabellen schon eine gehörige Speicerersparnis durch den Pointer und die Datenfelder waren immer zusammen.
In der Urversion wurden die Struktuten aus den DB-Tabellen per Script erstellt, die Erweiterungen dann händisch angepasst.

Gruß Tommy

Nach laaaanger Pause und ein wenig Üben meldet sich die mit dem Brett vorm Kopf zurück.
Einen Grundentwurf für die Vereinfachung meiner „Tasterfunktion“ habe ich fertig, bin mir nur nicht sicher, in welche Schleife ich es am elegantesten verpacke.
Vorstellen möchte ich sie euch trotzdem schon.
Zumindest den entsprechenden Teil.

int   lcdPause           = 5000;
unsigned long lcdPauseZS = 0;
bool  lcdPauseMerker     = LOW;
int   Entprellzeit       = 500;
unsigned long BetriebsAnzeigeZS = 0;

struct taster_t {
  const byte    TasterPin;
  char          Anzeige; 
  bool          Funktion;
  bool          Hand;
  unsigned long Pause;
  unsigned long Entprell;
  unsigned long SchaltZeit;
  bool          TasterStatus;
  bool          TasterMerker;
  };

//                  TasterPin, Anzeige, Funktion,   Hand,   Pause,    Entprell, SchaltZeit, TasterStatus, TasterMerker, 
taster_t TAST01 =   { A10,      "Futter",   LOW,      LOW,   1200000,       0,          0,        LOW,       LOW,  };
taster_t TAST02 =   { A15,      "Skimmer",  LOW,      LOW,   1800000,       0,          0,        LOW,       LOW,  };
taster_t TAST03 =   { A12,      "Licht",    LOW,      LOW,   3600000,       0,          0,        LOW,       LOW,  };
taster_t TAST04 =   { A13,      "LED",      LOW,      LOW,   1800000,       0,          0,        LOW,       LOW,  };
taster_t TAST05 =   { A11,      "Spots",    LOW,      LOW,   3600000,       0,          0,        LOW,       LOW,  };
taster_t TAST06 =   { A14,      "Luft",     LOW,      LOW,   1800000,       0,          0,        LOW,       LOW,  };
taster_t TAST07 =   { A6,       "Debug",    LOW,      LOW,   3600000,       0,          0,        LOW,       LOW,  };
taster_t TAST08 =   { A4,       "CO2",      LOW,      LOW,   3600000,       0,          0,        LOW,       LOW,  };
taster_t TAST09 =   { A8,       "Cool",     LOW,      LOW,      2000,       0,          0,        LOW,       LOW,  };
taster_t Tast10 =   { A9,       "Taster10", LOW,      LOW,      2000,       0,          0,        LOW,       LOW,  };
taster_t TAST11 =   { A7,       "Taster11", LOW,      LOW,      2000,       0,          0,        LOW,       LOW,  };
taster_t TAST12 =   { A5,       "Taster12", LOW,      LOW,      2000,       0,          0,        LOW,       LOW,  };


void Taster(){
 
TAST02.TasterStatus = digitalRead(TAST02.TasterPin);
  
if(TAST02.TasterStatus == HIGH && TAST02.TasterMerker == LOW){
  TAST02.Entprell = millis();
  TAST02.TasterMerker = HIGH;
  }

//******************************************************************
//*************** Wenn AN*******************************************
//******************************************************************

if(millis() - TAST02.Entprell > Entprellzeit && TAST02.TasterMerker == HIGH && TAST02.Funktion == HIGH){
  TAST02.TasterMerker = LOW;
  TAST02.Funktion     = LOW;
  TAST02.Hand         = HIGH;
  TAST02.SchaltZeit   = millis();
  
  BetriebsAnzeige   = HIGH;
  
  lcd2.setCursor(0, 0);
  lcd2.print(TAST02.Anzeige);
  lcd2.print(" Tast aus");
  lcdPauseZS      = millis();
  lcdPauseMerker  = HIGH; 
  
  if(DebugMerker == HIGH){
    Serial.println(TAST02.Anzeige);
    Serial.println(" Taster aus");
     }
     }

     
//******************************************************************
//*************** Wenn AUS******************************************
//******************************************************************
if(millis() - TAST02.Entprell > Entprellzeit && TAST02.TasterMerker == HIGH && TAST02.Funktion == LOW){
  TAST02.TasterMerker = LOW;
  TAST02.Funktion     = HIGH;
  TAST02.Hand         = HIGH;
  TAST02.SchaltZeit   = millis();
  
  lcdPauseZS        = millis();
  lcdPauseMerker    = HIGH;
  BetriebsAnzeige   = HIGH;
  BetriebsAnzeigeZS = millis();
  lcd2.setCursor(0, 0);
  lcd2.print(TAST02.Anzeige);
  lcd2.print(" Tast an");
   
  if(DebugMerker == HIGH){
    Serial.print(TAST02.Anzeige);
    Serial.println(" Tast an");
     }
     }

if(millis() - TAST02.SchaltZeit > TAST02.Pause)
{  TAST02.Hand = LOW; }

if(millis() - lcdPauseZS > lcdPause)
{ lcdPauseMerker = LOW;  }

}

Vielleicht habt ihr ja einen Rat oder Tipp für mich, dass Ganze noch etwas zu schleifen? lieb guck
"Benutzen" möchte ich die Taster 02 - 12.
Taster 01 wird woanders benötigt.

Ganz lieben Dank im Voraus.

Tiff

Füge einen Konstruktor hinzu, setze die Werte, die immer 0 / LOW sind als Defaultwerte und packe es in ein Array.
So als grobe Anregungen.

Die Funktionen, die Du für Aktionen geschrieben hast, packst Du als Methoden rein.

Gruß Tommy

Hallo,

kompiliert leider nicht weil unvollständig. Eine Warnung solltest du dennoch ernst nehmen.
Bezieht sich auf dein char Anzeige im struct taster_t. Wird nicht funktionieren. Entweder Zeiger oder char Array verwenden. Ich glaube dafür gibts sogar ein Bsp. mit/ohne Progmem in der Arduino Referenz.

sketch_nov27a.ino:21:33: warning: invalid conversion from 'const char*' to 'char' [-fpermissive]
21 | taster_t TAST01 = { A10, "Futter", LOW, LOW, 1200000, 0, 0, LOW, LOW, };
| ^~~~~
| |
| const char*

Alles weitere wie Tommy sagt.

Hallo,

nochwas zum einarbeiten, habs gefunden wo ich damals ein Problem hatte, ich denke das kannst du gebrauchen.
https://forum.arduino.cc/index.php?topic=583691.0