Arduino stürzt nach wirkürlichen Zeitabständen ab, ratlos

Ich teile hier mal den Code mit euch, ansonsten funktioniert das Programm doch er stürzt halt immer wieder ab. Das ganze soll eine Aufzuchtstation für Jungpflanzen werden. Verwendet werden eine RTC DS1302
SHT30 über I²C
LCD 16x2 I²C

#include <SHT31.h>
#include <virtuabotixRTC.h>
#include <LiquidCrystal_I2C.h>
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include "Wire.h"

LiquidCrystal_I2C lcd(0x27, 16, 2);
virtuabotixRTC myRTC(6, 7, 8);
SHT31 sht;


// Pin Belegung
#define BUTTON_UP PB1
#define BUTTON_DOWN PB2
#define BUTTON_SELECT PB3
#define LIGHT_RELAY_PIN PD2
#define WATER_RELAY_PIN PD3
#define HEAT_RELAY_PIN PD4
#define SHT31_ADDRESS 0x44


// Menüzustände
enum MenuState {
  Wahl,
  Aufzucht,
  Entnahme
};
MenuState currentState = Wahl;
// Menüoptionen
const char* Pflanzenmenu[] = {
  "Salat",
  "Brokkoli",
  "Tomaten",
  "Paprika",
  "Eisbergsalat",
  "Zucchini",
  "Zwiebeln",
  "Gurken",
  "Auberginen"
};
//Globale Variablen
int8_t currentMenu = 0;
int8_t counter_Aufzucht = 0;
uint8_t verstrichene_Tage=0;
//Datenstruktur
struct Datensatz {
  int nummer;
  char name[20];
  uint8_t Belichtungsdauer; // Std.
  float Temperatur;                // °C
  float Feuchtigkeit;     // %
  uint8_t Reife;};



Datensatz Pflanze[10]; // 10 Datensaetze sind möglich

void setup() {
  Serial.begin(115200);
  Wire.begin();
  sht.begin(SHT31_ADDRESS);
  myRTC.setDS1302Time(0, 0, 20, 2, 3, 10, 2023);
  initializeData();
  lcd.init();
  lcd.backlight();
  Serial.println("Start");
  //Ausgaenge Definieren
  DDRB |= (1 << LIGHT_RELAY_PIN) | (1 << WATER_RELAY_PIN) | (1 << HEAT_RELAY_PIN);
  // Pull-Up-Widerstände aktivieren
  PORTB |= (1 << BUTTON_UP) | (1 << BUTTON_DOWN) | (1 << BUTTON_SELECT);
}
void AuswahlLCD() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Waehle Setzling:");
  lcd.setCursor(0, 1);
  lcd.print(Pflanzenmenu[currentMenu]);
  _delay_ms(500);
}

void AufzuchtLCD(uint8_t i,uint8_t Tage) {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(Pflanze[i].name);
  lcd.setCursor(0,1);
  lcd.print("Ernten in ");
  lcd.print((Pflanze[i].Reife-Tage));
  lcd.print(" T");
  _delay_ms(500);
}
void Benutzereingabe_Wahl() {
  if (currentState != Wahl) {
    return; // Wenn nicht im Wahlzustand, beenden
  }

  bool buttonUpPressed = !(PINB & (1 << BUTTON_UP));
  bool buttonDownPressed = !(PINB & (1 << BUTTON_DOWN));
  bool buttonSelectPressed = !(PINB & (1 << BUTTON_SELECT));

  if (buttonSelectPressed) {
    currentState = Aufzucht; //Zustand auf Aufzucht ändern
    Serial.println("Wechsel zum Aufzuchtzustand");
    _delay_ms(250);
  }

  if (buttonUpPressed) {
    currentMenu++;
    Serial.println("Menü nach oben");
    _delay_ms(250);
  }

  if (buttonDownPressed) {
    currentMenu--;
    Serial.println("Menü nach unten");
  }
}
void Benutzereingabe_Aufzucht() {
  if (currentState != Aufzucht) {
    return; // Wenn nicht im Aufzuchtzustand, beenden
  }

  bool buttonUpPressed = !(PINB & (1 << BUTTON_UP));
  bool buttonDownPressed = !(PINB & (1 << BUTTON_DOWN));
  bool buttonSelectPressed = !(PINB & (1 << BUTTON_SELECT));

  if (buttonSelectPressed && buttonUpPressed) {
    currentState = Wahl; // Zustand auf Wahl ändern
    Serial.println("Wechsel zum Wahlzustand");
  }
}
void initializeData() {
  // Daten für "Salat"
  Pflanze[0].nummer = 0;
  strncpy(Pflanze[0].name, "Salat", sizeof(Pflanze[0].name));
  Pflanze[0].Belichtungsdauer = 14;
  Pflanze[0].Temperatur = 25.0;
  Pflanze[0].Feuchtigkeit = 70.0;
  Pflanze[0].Reife = 30;

  // Daten für "Brokkoli"
  Pflanze[1].nummer = 1;
  strncpy(Pflanze[1].name, "Brokkoli", sizeof(Pflanze[1].name));
  Pflanze[1].Belichtungsdauer = 12;
  Pflanze[1].Temperatur = 18.0;
  Pflanze[1].Feuchtigkeit = 60.0;
  Pflanze[1].Reife = 60;

  // Weitere Daten für andere Pflanzen hier hinzufügen
}
void SteuereLicht(int8_t Belichtungsdauer, int currentHour) {
  // Lichtsteuerung
  if (currentHour >= 8 && currentHour < 22) {
    // Prüfen, ob die Belichtungsdauer erreicht ist
    if (currentHour - 8 < Belichtungsdauer) {
      // Licht einschalten
      PORTB |= (1 << LIGHT_RELAY_PIN);
      Serial.println("Licht an");
    } 
    else {
      // Licht ausschalten, da die Belichtungsdauer erreicht ist
      PORTB &= ~(1 << LIGHT_RELAY_PIN);
      Serial.println("Licht aus");
    }
  } 
  else {
    // Außerhalb der Zeitzone, Licht ausschalten
    PORTB &= ~(1 << LIGHT_RELAY_PIN);
    Serial.println("Keine Lichtfreigabe");
  }
}
void FeuchtigkeitsRegelung(float Sollfeuchtigkeit) {
  float IstFeuchtigkeit = feuchtigkeitEinlesen();
  Serial.println(Sollfeuchtigkeit);
  Serial.print("   ");
  Serial.print(IstFeuchtigkeit);

  if (IstFeuchtigkeit < (Sollfeuchtigkeit - 5.0)) {
    // Bewässerung einschalten
    PORTB |= (1 << WATER_RELAY_PIN);

    Serial.println("Bewässerung ist an");
  }
  else if (IstFeuchtigkeit > (Sollfeuchtigkeit + 10.0)) {
    // Bewässerung ausschalten
    PORTB &= ~(1 << WATER_RELAY_PIN);
    Serial.println("Bewässerung ist aus");
  }
  else {
    // Bewässerung ausschalten
    PORTB &= ~(1 << WATER_RELAY_PIN);
    Serial.println("Bewässerung ist aus (Standard)");
  }
}
float feuchtigkeitEinlesen() {
  sht.read();
  float Wet = sht.getHumidity();
  return Wet;
}
void TemperaturRegelung(float Solltemperatur) {
  float IstTemperatur = temperaturEinlesen();
  Serial.println(Solltemperatur);
  Serial.print("   ");
  Serial.print(IstTemperatur);

  if (IstTemperatur < (Solltemperatur - 2.0)) {
    // Heizung einschalten
    Serial.println("Heizung ein");
    PORTB |= (1 << HEAT_RELAY_PIN);
  }
  else if (IstTemperatur > (Solltemperatur + 1.0)) {
    // Heizung ausschalten
    Serial.println("Heizung aus");
    PORTB &= ~(1 << HEAT_RELAY_PIN);
  }
  else {
    // Heizung ausschalten
    PORTB &= ~(1 << WATER_RELAY_PIN);
    Serial.println("Heizung aus (Standard)");
  }
}
float temperaturEinlesen() {
  sht.read();
  float Temp = sht.getTemperature();
  return Temp;
}
void loop() {

  if (currentState == Wahl) {
    AuswahlLCD();
    Benutzereingabe_Wahl();
  }
   if (currentState == Aufzucht) {
    int8_t currentday=myRTC.dayofmonth;
      if(myRTC.dayofmonth!=currentday&&myRTC.hours==23){
        verstrichene_Tage++;
    }
    myRTC.updateTime();
    AufzuchtLCD(currentMenu,verstrichene_Tage);
    Benutzereingabe_Aufzucht();
    if(myRTC.minutes% 30 ==0)//&&myRTC.seconds% 1 == 0
    
    {
      //Sensorwerte aktualisieren, wenn das Intervall abgelaufen ist
      SteuereLicht(Pflanze[currentMenu].Belichtungsdauer, myRTC.hours);
      FeuchtigkeitsRegelung(Pflanze[currentMenu].Feuchtigkeit);
      TemperaturRegelung(Pflanze[currentMenu].Temperatur);
    }
  }
}

verbesserungen im code sind auch gerne gehört bin noch blutiger anfänger wie man hier sicher sieht

if (buttonDownPressed) {
  currentMenu--;
  Serial.println("Menü nach unten");
}
. . .
. . .
lcd.print(Pflanzenmenu[currentMenu]);

Was verhindert dass currentMenu unter Null geht? (Array underflow)

Vielleicht so etwas :
if ( --currentMenu < 0 ) currentMenu = 0 ;
anstatt:
currentMenu--;

Gleiches Problem wie im vorherigen Beitrag.

Und ähnlich für currentMenu++ ( nicht getested! )

if ( ++currentMenu >= sizeof( Pflanzenmenu ) /sizeof ( char* ) ) currentMenu = ( sizeof( Pflanzenmenu ) /sizeof ( char* ) ) - 1 ;

Nicht ganz optimal ist, dass die 9 oder 10 Pflanzennamen doppelt vorkommen.
Und Konstanten mitten im Code ( initializeData() ) definiert werden.

Nachtrag:
Hat aber wohl nichts mit deinen ratlosen Abstürzen zu tun.

Hinterher schaltest du PORTB

Soll das eine Optimierung sein?

Hat aber wohl nichts mit deinen ratlosen Abstürzen zu tun.

Man sieht nicht welche Libraries du verwendest. Vieleicht geht dir der Speicher aus.

Was du auf alle Fälle machen kannst: lies dich ein zum Thema Arduino F-Makro und ändere deine Print aufrufe:

Serial.println("Licht an");

das könnte etwas SRAM sparen.

Hier ist auch ein mögliche Problem dass nur 2 Datensaetze initialisiert sind ("Salat" und "Brokkoli") und abhängig vom Wert currentMenu die anderen könnten referenziert werden:

Datensatz Pflanze[10]; // 10 Datensaetze sind möglich
. . .
. . .
void AufzuchtLCD(int i) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(Pflanze[i].name);  // möglicherweise ohne end Zeichen \0 falls currentMenu > 1
  lcd.setCursor(0, 1);
  lcd.print("Ernten in ");
  lcd.print(Pflanze[i].Reife);
  lcd.print(" T");
  _delay_ms(500);
}

Hallo,
kannst Du irgendwie eine Aussage dazu machen wann das Ding bei welchen Bedienschritten abstürzt. Oder bei welchem Ablaufschritt.
Oder passiert das auch wenn eigentlich nichts gemacht / getan wird.

warum schaltest Du die Ausgänge nicht mit digital.Write() ?

Nachtrag
setze doch bitte den code in codetags , das geht auch nachträglich noch.

Heinz

Also es ist so geplant das man mit drei Knöpfen durch die erste Phase des Programms steuern kann die "Wahl" Phase wenn die Wahhphase beendet ist kommt man in die "Aufzucht" Phase. Dort entsteht dann das eigentliche Problem, hier müsste ich theoretisch ja über mehrere Wochen in der Umgebung bleiben, doch dort stürtzt das Porgramm in unregelmäßigen Zeitbaständen immer wieder ab.

Das die Ausgänge in dieser Weise geschaltet werden liegt an den Vorgaben die ich durch unseren Lehrer bekommen habe. Deswegen soll das ganze eig. in C geschrieben werden doch dazu fehlen mir momentan die Kenntnisse zu. Hoffe jemand von euch hat noch eine Idee woran es liegen könnte.

Ich habe den Speicher des Arduinos bereits abgefragt und dieser scheint nicht voll zulaufen, kann aber sein das ich nicht nach dem RAM gefragt habe.

Dein Code oben ist nicht nutzbar.
Da fehlt einiges.
Entweder ist das durch die fehlenden Codetags oder Du hast beim kopieren einen Fehler gemacht.

Setz den bitte in Codetags - sonst kann man Dir nicht helfen.

#include <SHT31.h>
#include <virtuabotixRTC.h>
#include <LiquidCrystal_I2C.h>
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include "Wire.h"

LiquidCrystal_I2C lcd(0x27, 16, 2);
virtuabotixRTC myRTC(6, 7, 8);
SHT31 sht;


// Pin Belegung
#define BUTTON_UP PB1
#define BUTTON_DOWN PB2
#define BUTTON_SELECT PB3
#define LIGHT_RELAY_PIN PD2
#define WATER_RELAY_PIN PD3
#define HEAT_RELAY_PIN PD4
#define SHT31_ADDRESS 0x44


// Menüzustände
enum MenuState {
  Wahl,
  Aufzucht,
  Entnahme
};
MenuState currentState = Wahl;
// Menüoptionen
const char* Pflanzenmenu[] = {
  "Salat",
  "Brokkoli",
  "Tomaten",
  "Paprika",
  "Eisbergsalat",
  "Zucchini",
  "Zwiebeln",
  "Gurken",
  "Auberginen"
};
//Globale Variablen
int8_t currentMenu = 0;
int8_t counter_Aufzucht = 0;
uint8_t verstrichene_Tage=0;
//Datenstruktur
struct Datensatz {
  int nummer;
  char name[20];
  uint8_t Belichtungsdauer; // Std.
  float Temperatur;                // °C
  float Feuchtigkeit;     // %
  uint8_t Reife;};



Datensatz Pflanze[10]; // 10 Datensaetze sind möglich

void setup() {
  Serial.begin(115200);
  Wire.begin();
  sht.begin(SHT31_ADDRESS);
  myRTC.setDS1302Time(0, 0, 20, 2, 3, 10, 2023);
  initializeData();
  lcd.init();
  lcd.backlight();
  Serial.println("Start");
  //Ausgaenge Definieren
  DDRB |= (1 << LIGHT_RELAY_PIN) | (1 << WATER_RELAY_PIN) | (1 << HEAT_RELAY_PIN);
  // Pull-Up-Widerstände aktivieren
  PORTB |= (1 << BUTTON_UP) | (1 << BUTTON_DOWN) | (1 << BUTTON_SELECT);
}
void AuswahlLCD() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Waehle Setzling:");
  lcd.setCursor(0, 1);
  lcd.print(Pflanzenmenu[currentMenu]);
  _delay_ms(500);
}

void AufzuchtLCD(uint8_t i,uint8_t Tage) {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(Pflanze[i].name);
  lcd.setCursor(0,1);
  lcd.print("Ernten in ");
  lcd.print((Pflanze[i].Reife-Tage));
  lcd.print(" T");
  _delay_ms(500);
}
void Benutzereingabe_Wahl() {
  if (currentState != Wahl) {
    return; // Wenn nicht im Wahlzustand, beenden
  }

  bool buttonUpPressed = !(PINB & (1 << BUTTON_UP));
  bool buttonDownPressed = !(PINB & (1 << BUTTON_DOWN));
  bool buttonSelectPressed = !(PINB & (1 << BUTTON_SELECT));

  if (buttonSelectPressed) {
    currentState = Aufzucht; //Zustand auf Aufzucht ändern
    Serial.println("Wechsel zum Aufzuchtzustand");
    _delay_ms(250);
  }

  if (buttonUpPressed) {
    currentMenu++;
    Serial.println("Menü nach oben");
    _delay_ms(250);
  }

  if (buttonDownPressed) {
    currentMenu--;
    Serial.println("Menü nach unten");
  }
}
void Benutzereingabe_Aufzucht() {
  if (currentState != Aufzucht) {
    return; // Wenn nicht im Aufzuchtzustand, beenden
  }

  bool buttonUpPressed = !(PINB & (1 << BUTTON_UP));
  bool buttonDownPressed = !(PINB & (1 << BUTTON_DOWN));
  bool buttonSelectPressed = !(PINB & (1 << BUTTON_SELECT));

  if (buttonSelectPressed && buttonUpPressed) {
    currentState = Wahl; // Zustand auf Wahl ändern
    Serial.println("Wechsel zum Wahlzustand");
  }
}
void initializeData() {
  // Daten für "Salat"
  Pflanze[0].nummer = 0;
  strncpy(Pflanze[0].name, "Salat", sizeof(Pflanze[0].name));
  Pflanze[0].Belichtungsdauer = 14;
  Pflanze[0].Temperatur = 25.0;
  Pflanze[0].Feuchtigkeit = 70.0;
  Pflanze[0].Reife = 30;

  // Daten für "Brokkoli"
  Pflanze[1].nummer = 1;
  strncpy(Pflanze[1].name, "Brokkoli", sizeof(Pflanze[1].name));
  Pflanze[1].Belichtungsdauer = 12;
  Pflanze[1].Temperatur = 18.0;
  Pflanze[1].Feuchtigkeit = 60.0;
  Pflanze[1].Reife = 60;

  // Weitere Daten für andere Pflanzen hier hinzufügen
}
void SteuereLicht(int8_t Belichtungsdauer, int currentHour) {
  // Lichtsteuerung
  if (currentHour >= 8 && currentHour < 22) {
    // Prüfen, ob die Belichtungsdauer erreicht ist
    if (currentHour - 8 < Belichtungsdauer) {
      // Licht einschalten
      PORTB |= (1 << LIGHT_RELAY_PIN);
      Serial.println("Licht an");
    } 
    else {
      // Licht ausschalten, da die Belichtungsdauer erreicht ist
      PORTB &= ~(1 << LIGHT_RELAY_PIN);
      Serial.println("Licht aus");
    }
  } 
  else {
    // Außerhalb der Zeitzone, Licht ausschalten
    PORTB &= ~(1 << LIGHT_RELAY_PIN);
    Serial.println("Keine Lichtfreigabe");
  }
}
void FeuchtigkeitsRegelung(float Sollfeuchtigkeit) {
  float IstFeuchtigkeit = feuchtigkeitEinlesen();
  Serial.println(Sollfeuchtigkeit);
  Serial.print("   ");
  Serial.print(IstFeuchtigkeit);

  if (IstFeuchtigkeit < (Sollfeuchtigkeit - 5.0)) {
    // Bewässerung einschalten
    PORTB |= (1 << WATER_RELAY_PIN);

    Serial.println("Bewässerung ist an");
  }
  else if (IstFeuchtigkeit > (Sollfeuchtigkeit + 10.0)) {
    // Bewässerung ausschalten
    PORTB &= ~(1 << WATER_RELAY_PIN);
    Serial.println("Bewässerung ist aus");
  }
  else {
    // Bewässerung ausschalten
    PORTB &= ~(1 << WATER_RELAY_PIN);
    Serial.println("Bewässerung ist aus (Standard)");
  }
}
float feuchtigkeitEinlesen() {
  sht.read();
  float Wet = sht.getHumidity();
  return Wet;
}
void TemperaturRegelung(float Solltemperatur) {
  float IstTemperatur = temperaturEinlesen();
  Serial.println(Solltemperatur);
  Serial.print("   ");
  Serial.print(IstTemperatur);

  if (IstTemperatur < (Solltemperatur - 2.0)) {
    // Heizung einschalten
    Serial.println("Heizung ein");
    PORTB |= (1 << HEAT_RELAY_PIN);
  }
  else if (IstTemperatur > (Solltemperatur + 1.0)) {
    // Heizung ausschalten
    Serial.println("Heizung aus");
    PORTB &= ~(1 << HEAT_RELAY_PIN);
  }
  else {
    // Heizung ausschalten
    PORTB &= ~(1 << WATER_RELAY_PIN);
    Serial.println("Heizung aus (Standard)");
  }
}
float temperaturEinlesen() {
  sht.read();
  float Temp = sht.getTemperature();
  return Temp;
}
void loop() {

  if (currentState == Wahl) {
    AuswahlLCD();
    Benutzereingabe_Wahl();
  }
   if (currentState == Aufzucht) {
    int8_t currentday=myRTC.dayofmonth;
      if(myRTC.dayofmonth!=currentday&&myRTC.hours==23){
        verstrichene_Tage++;
    }
    myRTC.updateTime();
    AufzuchtLCD(currentMenu,verstrichene_Tage);
    Benutzereingabe_Aufzucht();
    if(myRTC.minutes% 30 ==0)//&&myRTC.seconds% 1 == 0
    
    {
      //Sensorwerte aktualisieren, wenn das Intervall abgelaufen ist
      SteuereLicht(Pflanze[currentMenu].Belichtungsdauer, myRTC.hours);
      FeuchtigkeitsRegelung(Pflanze[currentMenu].Feuchtigkeit);
      TemperaturRegelung(Pflanze[currentMenu].Temperatur);
    }
  }
}

ja würde mich über weitere antworten freuen, die ausgänge werden so geschalten weil dies eine vorgabe unseres lehrers war, so wird das eig. in avr microcontrollern gemacht

Ist ein Relay und Heizgerät angeschlossen oder nur mit einem LED oder sonst simuliert?
Eine elektrische Störung könnte auch solche unregelmässig Störungen auslösen. Hast du ein Schaltplan / Schematic?

Hallo,
Ich gehe jetzt mal davon aus das der Arduino abstürzt obwohl zu dem Zeitpunkt keine Taster gedrückt werden, also im normalen Ablaufbetrieb.

Ich sehe da zunächst mal keine Fehler im Programm. Es scheint ja im Prinzip auch zu laufen, allerdings wurde ja bereits darauf hingewiesen das die Variable "currentMenu" Werte annehmen kann die unzulässig sind. Da solltest Du zuerst was machen und die auf 0-9 begrenzen.

Es wurde ja auch bereits darauf hingewiesen das Relais und große Ströme EMV Störungen verursachen können. Also die Frage läuft das derzeit mit ein paar LED´s im Testbetrieb oder bereits im realen Betrieb mit Lampe, Heizung, Pumpe. Welche Leistungen werden da geschaltet.

Mach mal ein Foto von deinem Aufbau

Was gemeint hier ist nicht klar aber wahrscheinlich keine Absturzursache.

if (currentState == Aufzucht) {
   int8_t currentday=myRTC.dayofmonth;
   if(myRTC.dayofmonth!=currentday&&myRTC.hours==23){
      verstrichene_Tage++;  // nie angetastet
   }
   . . .
   . . .
}

Sehe ich auch so:
verstrichene_Tage wird nie hochgesetzt, weil im if der erste Teil immer false liefert
und nur in AufzuchtLCD verwendet für die Ausgabe
"Ernten in xx T"
Dass es als int8_t definiert und als uint8_t verwendet wird, stört auch nicht weiter, schon gar nicht, wenn es immer 0 ist..

Hallo,

das zu debuggen wird schwierig, weil kaum jemand die Hardware hat und die Libs testen kann. Fang nochmal klein von vorn an. Ich halte es zwar für komisch wenn ihr Arduino verwendet aber die Pins nur im häßlichen C Style programmieren dürft. Dann überrasche wenigstens den Lehrer wie man dennoch mit C halbwegs vernünftig mit Namen arbeiten kann. Lege dir wie gezeigt für alle Eingänge und Ausgänge sprechende Namen an die jeweils nur eine Aufgabe haben. Den Anforderungen C zu programmieren sollte damit genüge getan sein zusätzlich verwendest du eigene Makros. Wenn du das verstehst und dem Lehrer erklären kannst sollte alles okay sein. Das kannst du in ein extra Tab legen.

Desweiteren siehst du wie man einen Datensatz deiner Struktur sauber anlegen kann. Weil ich annehme das die Werte Pflanzenspezifisch sind, sind alles Konstanten. Die Nummer brauchst du eigentlich nicht, außer du fühlst dich damit wohler, denn das entspricht der Indexnummer vom Array 'pflanze'. Für mehr Durchblick gewöhne dir an Variablen klein zu schreiben. Makro Namen alles groß.

Falls jede Pflanze eigene Messwerte hat, kommt der Datentyp Messwert in den Datentyp Datensatz, dann kann man alles über for Schleifen erschlagen. Messungen, Vergleiche, Aktionen.

Idee für ein Grundgrüst
// https://forum.arduino.cc/t/arduino-sturzt-nach-wirkurlichen-zeitabstanden-ab-ratlos/1176371/18

#include <Streaming.h>

#ifndef sbi
  #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))   // setzt das angegebene Bit auf 1
#endif
#ifndef cbi
  #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))  // setzt (löscht) das angegebene Bit auf 0
#endif

// *** Ausgänge ***
#define LIGHT_RELAY_OUT  sbi (DDRD, 2) // Ausgang
#define LIGHT_RELAY_ON   sbi (PORTD,2) // einschalten
#define LIGHT_RELAY_OFF  cbi (PORTD,2) // ausschalten

// *** Eingänge ***
#define BUTTON_UP_IN   cbi (DDRB,1)         // Eingang // wobei das überflüssig ist, weil default Eingang
#define BUTTON_UP_PULL sbi (PINB,1)         // Pullup aktiv
#define BUTTON_UP_READ   (!(PINB & _BV(1))) // Pin lesen

struct Datensatz {
  const uint8_t nummer;
  const uint8_t belichtungsdauer; // Std.
  const float temperatur;         // °C
  const float feuchtigkeit;       // %
  const uint8_t reife;
  const char name[20];
};
  
Datensatz pflanze [] {
  {0, 100, 25, 50, 90, "Salat"},
  {1, 110, 25, 55, 90, "Brokkoli"},
  {2, 120, 25, 60, 90, "Tomaten"},
  {3, 130, 25, 65, 90, "Paprika"},
  {4, 140, 25, 70, 90, "Eisbergsalat"},
  {5, 150, 25, 75, 90, "Zucchini"},
  {6, 160, 25, 80, 90, "Zwiebeln"},
  {7, 170, 25, 85, 90, "Gurken"},
  {8, 180, 25, 90, 90, "Paprika"},
  {9, 190, 25, 95, 90, "Auberginen"},
};

const uint8_t ANZAHL_PFLANZEN {sizeof(pflanze)/sizeof(pflanze[0])}; // für Schleifendurchläufe etc.

struct Messwert {
  uint8_t temperatur  {93};  // soll einen eingelesenen Messwert darstellen
  uint8_t luftfeuchte {73};  // soll einen eingelesenen Messwert darstellen
} messWert;

void setup() {
  Serial.begin(9600);
  Serial.println(F("\nuC Reset ####\n"));
  Serial << F("\nfor Ranged Based") << endl;
  for (auto &i : pflanze) {
    Serial << i.nummer << F("  ") << i.name << F("  ") << i.belichtungsdauer << endl;
  }
  
  for (auto &i : pflanze) {
    if (i.feuchtigkeit > messWert.temperatur) {
      Serial << F("der ") << i.name << F(" ist es zu warm") << endl;
    }
  }
  Serial << F("\nfor klassisch Index basiert") << endl;
  for (uint8_t i=0; i<ANZAHL_PFLANZEN; i++) {
    Serial << pflanze[i].nummer << F("  ") << pflanze[i].name << F("  ") << pflanze[i].belichtungsdauer << endl;
  }

  for (uint8_t i=0; i<ANZAHL_PFLANZEN; i++) {
    if (pflanze[i].feuchtigkeit > messWert.luftfeuchte) {
      Serial << F("der ") << pflanze[i].name << F(" ist es zu feucht") << endl;
    }
  }
  
}

void loop()
{
  
}