Arduino Forum

International => Deutsch => Topic started by: olli_h on Jun 29, 2020, 08:39 pm

Title: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: olli_h on Jun 29, 2020, 08:39 pm
Hallo zusammen,

vor ein paar Wochen hab ich einen Arduino Uno + Starterkit bekommen, da die meisten Projekte mal durch und Spass dran gefunden.

Als erste Anwendung hab ich mal mit einer Pflanzenbewässerung angefangen, scheint ja ein echter Klassiker zum Start zu sein, hab hier im Forum schon ein paar gute Threads dazu gelesen.

Ich will mal relativ einfach anzufangen und die Sache dann Schritt für Schritt ausauen. Dabei soll das nicht nur so irgendwie funktionieren, sondern ich mag auch gerade am Anfang darauf achten, dass ich einigermaßen brauchbaren Code produziere, über den man sich austauschen kann. Daher wäre mein erstes Anliegen mal über mein Werk drüber zu schauen:

Code: [Select]
// Konstantendeklaration
// Förderleistungen der Pumpen in den einzelnen Bereichen 0 bis 3 in ml/s
const int FL[] = {20, 20, 20, 20};

// Zeit bis Start erste Bewässerung in Stunden
const float ToFirst_h = 0.005; //18s zum Testen

//Belegung der Pins für die Pumpenrelais
const byte R[] = {2, 3, 4, 5};

// Variablendeklaration - sollen später im loop anpassbar sein

// auszubringende Wassermengen in den einzelnen Bereichen 0 bis 3 in ml
int Menge[] = {100, 75, 200, 125};

// Intervall in dem Wasser ausgebracht werden soll in Stunden
float Intervall_h;

// Kenner ob und wie viele Gießintervalle ausgelassen werden sollen pro Bereich
byte Skip[] = {0, 1, 2, 0};

// Fehlerkenner für Unterbrechung von loop Teilen und Anzeige
byte Failcode;

//globale Variablen für Code
unsigned long StartMillis; //Für Steuerung der Intervalle
unsigned long CurrentMillis;
unsigned long NextIntervall;
byte CurrentSkip[4]; // Zähler für die aktuelle Anzahl der Intervalle die bereits ausgelassen worden sind
unsigned long Pumpenlaufzeit[4];
unsigned long Pumpenlaufzeit_ges;
byte x; //Laufvariable für diverse For Schleifen

void setup()
{
  // Initialwerte für Bewässerung
  Serial.begin(9600);
  Failcode = 0; //Fehlercode 0 = kein Fehler
  Intervall_h = 0.01; //Bewässerung alle 36s für Test - später 24 oder so

  //Pins für die Relais setzen
  for (x = 0; x < 4; x++)
  {
    pinMode (R[x], OUTPUT);
    digitalWrite(R[x], HIGH); //Relais schalten bei LOW
  }

  StartMillis = millis(); // Startzeit setzen
  NextIntervall = ToFirst_h * 3600000; //Erstes Intervall setzen in Millis

  //Erste Skipwerte setzen
  for (x = 0; x < 4; x++)
  {
    CurrentSkip[x] = Skip[x];
  }
}

void loop()
{
  CurrentMillis = millis();
  if (CurrentMillis - StartMillis >= NextIntervall)
  {
    NextIntervall = Intervall_h * 3600000; //Nächstes Intervall setzen in Millis
    StartMillis = CurrentMillis; //Start zurücksetzen
    //Berechnung der Pumpenlaufzeiten
    Calc_Laufzeit();
    //Prüfung ob Gesamtlaufzeit Pumpen + Puffer unter Intervall liegt
    if (Pumpenlaufzeit_ges > NextIntervall)
    {
      Failcode = 1;
    }
    //Pumpen laufen lassen und Skipwerte aktualisieren
    if (Failcode == 0)
    {
      for (x = 0; x < 4; x++)
      {
        if (CurrentSkip[x] < 1)
        {
          digitalWrite (R[x], LOW);
          delay (Pumpenlaufzeit[x]);
          digitalWrite (R[x], HIGH);
          delay (250);
          CurrentSkip[x] = Skip[x];
        }
        else
        {
          CurrentSkip[x]--;
        }
      }
    }
  }
  Serial.print("Pumpenlaufzeit0: ");
  Serial.println(Pumpenlaufzeit[0]);
  Serial.print("Pumpenlaufzeit1: ");
  Serial.println(Pumpenlaufzeit[1]);
  Serial.print("Pumpenlaufzeit2: ");
  Serial.println(Pumpenlaufzeit[2]);
  Serial.print("Pumpenlaufzeit3: ");
  Serial.println(Pumpenlaufzeit[3]);
  Serial.print("NextIntervall: ");
  Serial.println(NextIntervall);
  Serial.print("Fehler: ");
  Serial.println(Failcode);
  delay(3000);
}

void Calc_Laufzeit()
{
  Pumpenlaufzeit_ges = 1000; //Zeit für die maximal 4x 250 ms zwischen den Relais
  for (x = 0; x < 4; x++)
  {
    if (CurrentSkip[x] < 1) //Wenn nicht geskipt wird, Berechnung aus Menge und Förderleistung
    {
      Pumpenlaufzeit[x] = Menge[x] / FL[x] * 1000;
    }
    else
    {
      Pumpenlaufzeit[x] = 0; // Wenn geskipt wird, dann keine Laufzeit
    }
    Pumpenlaufzeit_ges = Pumpenlaufzeit_ges + Pumpenlaufzeit[x];
  }
}


Das System soll 4 Bereiche bewässern.

Der Grundablauf ist simpel:
- warte einen definierten Zeitraum (24h, 12h oder sowas)
- lass 4 Pumpen hintereinander eine definierte Wassermenge ausgeben
- von vorn

Features:
- Wassermengen pro Bereich können direkt eingegeben werden, die Ausgabe wird über Förderleistung in Laufzeit umgerechnet
- Intervalle können geziehlt pro Bereich ausgelassen werden (also nur jeden 2. oder 3. Intervall gießen)
- Erstes Intervall kann gesondert festgelegt werden (damit der Bewässerungszeitpunkt nicht gleich Startzeitpunkt sein muss)
- Bisher wird ein Fehler geprüft und abgefangen - Überscheitet die Gesamtpumpenlaufzeit das Intervall (das würde uns wohl ins Chaos stürzen, sollt aber im Regelbetrieb kaum vorkommen)

Der Code macht soweit mal das was er soll, zumindest mal an 4 Test - Led, die ich über die Relais ansteuere momentan. Trotzdem wäre ich dran interessiert, ob hier noch was verbessert und vereinfacht werden kann. Passt diese Mischung aus Millis() und Delay() oder lieber alles mit Millis steuern? Der Serial.Print Block ist da auch noch nicht optimal, da sehe ich die aktuellen Laufzeiten erst, wenn die Pumpen schon gelaufen sind ...


Weitere Schritte:
- Das Intervall und die Wassermengen sollen online (Mobilphone) während der Laufzeit veränderbar sein
- Einbindung von Sensoren für Feuchtigkeit, Temperatur, etc
- Achja, die Hardware (Tank, Pumpen, Leitungen) muss ich irgendwann mal bauen :D
- Irgendwann wird das ganze wohl auf eine Pumpe und Ventile zur Steuerung der Bereiche umgebaut
- Abfrage Füllstand Tank ...

Für die Umsetzung der Steuerung aufs Handy ist mir Blynk ins Auge gestochen. Scheint so für den Anfang recht simpelzu sein. Nur ist hier die Frage, wie komm ich mit dem Uno Board ins WLAN, bzw. ist der Uno hier überhaupt das geeignete Board?

Besser scheint ja ein ESP8266 (also sowas:ESP8266 (https://www.amazon.de/dp/B06Y1LZLLY/ref=cm_sw_em_r_mt_dp_U_OcJ-EbT5NVYYQ)) aber das hat auf den ersten Blick nur einen analog Eingang, was mir ungünstig erscheint, wenn ich da irgendwann Feuchtigkeits und Temperatursensoren anschließen will...? Ich hab da auch schon einiges hin und her recherchiert, aber das Feld ist groß und für Einsteiger recht unübersichtlich.

Bin also für Tips, Anregungen, gute Links und sonstigen Input dankbar.

Grüße Olli
Title: Re: Einsteiger mit paar Fragen
Post by: HotSystems on Jun 29, 2020, 08:49 pm
Das du hier was fragen willst, ist uns klar.
Aber wo dein Problem ist, eher nicht.

Somit ist es besser, wenn dein Titel auch deine Frage zeigt.
Dann wird dein Problem besser gefunden und es gibt mehr Helfer.

Also mach das bitte gleich, das geht auch noch.
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: olli_h on Jun 29, 2020, 08:55 pm
Hallo Dieter, alles klar, angepasst ...
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: HotSystems on Jun 29, 2020, 09:01 pm
Hallo Dieter, alles klar, angepasst ...
Ok.
Mit welchem Controller du startest, hängt auch von deinen Kenntnissen ab.
Du kannst einen Uno für deine Sensoren verwenden und die Verbindung zum WLan mittels ESP8266 aufbauen.
Beide Controller verbindest du per I2C.
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: noiasca on Jun 30, 2020, 06:19 am
Quote
Daher wäre mein erstes Anliegen mal über mein Werk drüber zu schauen:
löse die delay() Blockaden ab. Meide lange delays. Nutze das System von "BlinkWithoutDelay" Beispiel.

Quote
aber das hat auf den ersten Blick nur einen analog Eingang,
das stimmt, aber du kannst weitere Analogsensoren an den NodeMCU einfach mittels I2C AnalogDigital Wandler dranhängen.
Damit kommst du dann auf "wesentlich mehr" als dir ein Uno zur Verfügung stellen kann.



Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: StefanL38 on Jun 30, 2020, 07:40 am
Hallo Olli,

wenn WLAN mit dabei sein soll empfehle ich ESP32. Das ist der Nachfolger vom ESP8266.
ziemlich viele IO-Pins RTC ist schon onboard, Bluetooth auch.
Hat auch gleich noch FLASH-Speicher on board den man zum abspeichern von Daten benutzen kann.
Für viele Analogeingänge würde man dann auch einen AD-Wandler-Chip dazu nehmen den man per I2C ansteuert.

https://circuits4you.com/2018/12/31/esp32-devkit-esp32-wroom-gpio-pinout/
ESP32-DevKit (https://circuits4you.com/2018/12/31/esp32-devkit-esp32-wroom-gpio-pinout/)

oder
https://az-delivery.de/products/esp32-developmentboard?_pos=2&_sid=c5d852b42&_ss=r

viele Grüße Stefan
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: agmue on Jun 30, 2020, 10:13 am
vor ein paar Wochen hab ich einen Arduino Uno + Starterkit bekommen, da die meisten Projekte mal durch und Spass dran gefunden.
Dann willkommen zu Deinem neuen Hobby und hier im Forum!

Dabei soll das nicht nur so irgendwie funktionieren, sondern ich mag auch gerade am Anfang darauf achten, dass ich einigermaßen brauchbaren Code produziere, über den man sich austauschen kann. Daher wäre mein erstes Anliegen mal über mein Werk drüber zu schauen:
Du hast eine Menge Dinge richtig gemacht, die ich bei anderen Neulingen vermisse:

Dafür schon mal meine Anerkennung!

Nun, wie gewünscht, meine Anmerkungen:

1. Groß-Klein-Konventionen: Wenn der Compiler zufrieden ist, kannst Du Variablen, Konstanten und andere Objekte benennen, wie Du magst. Für den Austausch gibt es gewisse Konventionen, leider finde ich die Seite, die ich Dir verlinken wollte nicht wieder. Variablen klein, erster Buchstabe groß bei Klassen usw. Programmierrichtlinien (http://www.informatik.uni-bremen.de/~zach/progr/guidelines.html)

2. Typ:
Code: [Select]
const int FL[] = {20, 20, 20, 20};
Kann die Förderleistung negativ werden? Nein, also unsigned.

Wird die Leistung größer als 255? Wenn nein, dann uint8_t oder byte.

Der Typ int ist ungünstig, weil er auf 8-Bit AVRs 16 Bit lang ist, auf ESPs aber 32 Bit. Die Schreibweise int16_t ist unabhängig vom Prozessor und damit eindeutig. Anstelle unsigned long besser uint32_t.

Gleiche Überlegungen für die Wassermenge.

Code: [Select]
byte x; //Laufvariable für diverse For Schleifen
Das ist unüblich und könnte bei verschachtelten Schleifen auch zu Fehlern führen. Daher besser

Code: [Select]
for (byte x = 0; x < 4; x++)

3. Zeiten: Wenn Du mit delay arbeitest, ist in dieser Zeit der µC taub für Nachrichten, weshalb jede blockierende Programmierung nicht zulässig und auch nicht nötig ist. Das gilt auch für zeitraubende Schleifen.

4. Ausgaben: So schnell, wie loop sein sollte, kann niemand einer Ausgabe folgen, außerdem ist die Ausgabe blockierend. Daher sollte nur in Intervallen eine Anzeige von Werten erfolgen.

Nur ist hier die Frage, wie komm ich mit dem Uno Board ins WLAN, bzw. ist der Uno hier überhaupt das geeignete Board?
Mit Blynk habe ich mich noch nicht beschäftigt und daher für mich eine HTML-Seite entworfen, die mein Händi anzeigt. Die Seite steht im SPIFFS eines ESP32. Der ESP ist bei mir Access Point, kann sich aber auch am Router anmelden. Als Grundlage habe ich Esp32 Webserver Arduino Tab (https://fipsok.de/Esp32-Webserver/Esp32) verwendet.

Siehe ESP32 Pinout Reference: Which GPIO pins should you use? (https://randomnerdtutorials.com/esp32-pinout-reference-gpios/) Mit WiFi ist nur ADC1 zu verwenden!

Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: olli_h on Jun 30, 2020, 09:58 pm
Hallo zusammen,

vielen Dank für eure Antworten, das hat mich weiter gebracht!

Hab mal geschaut, was ich von den Tipps umgesetzt bekomme. Am schwersten ist es mir gefallen alle Pumpenlaufzeiten und deren Abhängigkeiten ohne delay hinzubekommen, aber jetzt läuft die Sache wieder (nachdem es zwischendrin mal wirklich merkwürdige Sachen gemacht hat). Ich hab ein bissel im Forum geschaut, da war so ein Beispiel von einem Wächter, der rumläuft und Lichtschalter an und aus macht ... das hat geholfen  :)

Hier der überarbeitete Code:
Code: [Select]
// Konstantendeklaration
const byte Kreise = 4; // Anzahl der Kreise
// Förderleistungen der Pumpen in den einzelnen Kreisen 0 bis 3 in ml/s
const byte FL[] = {20, 20, 20, 20}; //Förderleisten bis 255 ml/s

// Zeit bis Start erste Bewässerung in Stunden
float ToFirst_h = 0.005; //18s zum Testen

//Belegung der Pins für die Pumpenrelais
const byte R[] = {2, 3, 4, 5};

// Variablendeklaration - sollen später im loop anpassbar sein

float Menge[] = {55, 25, 30, 50}; // Auszubringende Mengen in ml, hier wird float benötigt um die spätere Division durch FL hinzubekommen

uint32_t CurrentMillis; //Aktuell vergangene Zeit seit Start des Controllers
float Intervall_h; // Länge des Intervalls in dem Wasser ausgebracht werden soll in Stunden
uint32_t StartMillis; //Startpunkt des Intervalls bis zur Bewässerung
uint32_t NextIntervall; //Länge des nächsten Intervalls bis zur Bewässerung

uint32_t Pumpenlaufzeit[Kreise]; //Länge der Pumpenlaufzeiten pro Kreis
uint32_t Pumpenlaufzeit_ges; //Summe aller Pumpenlaufzeiten + Puffer

uint32_t StartMillis_Pumpe[] = {0, 0, 0, 0}; //Startpunkte der einzelnen Pumpen
bool Pumpenstatus[] = {HIGH, HIGH, HIGH, HIGH}; //Status ob Pumpe läuft oder nicht
byte Pumpenfolge = Kreise; // Zeigt welche Pumpe an der Reihe ist. Mit Setzen auf Kreise erst mal ungültig, damit am Anfang nix läuft.

byte Skip[] = {0, 1, 0, 2}; // Kenner ob und wie viele Gießintervalle ausgelassen werden sollen pro Bereich
byte CurrentSkip[Kreise]; // Zähler für die aktuelle Anzahl der Intervalle die bereits ausgelassen worden sind

byte Failcode; // Fehlerkenner für Unterbrechung von loop Teilen und Anzeige

uint32_t Monitorintervall = 3000; //Intervall für Ausgabe auf dem Seriellen Monitor
uint32_t StartMonitor = 0;

void setup()
{
  // Initialwerte für Bewässerung
  Serial.begin(9600);
  Failcode = 0; //Fehlercode 0 = kein Fehler
  Intervall_h = 0.005; //Bewässerung alle 18s für Test - später 24 oder 12

  for (byte x = 0; x < Kreise; x++)
  {
    pinMode (R[x], OUTPUT); //Pins für die Relais setzen
    digitalWrite(R[x], HIGH); //Relais schalten bei LOW, daher Grundzustand HIGH
    CurrentSkip[x] = Skip[x]; //Erste Skipwerte setzen
  }
  StartMillis = millis(); // Startzeit setzen
  NextIntervall = ToFirst_h * 3600000; //Erstes Intervall setzen in Millis
}

void loop()
{
  CurrentMillis = millis();
 
  // Bewässerungsintervall
  if (CurrentMillis - StartMillis >= NextIntervall)
  {
    NextIntervall = Intervall_h * 3600000; //Nächstes Intervall setzen in Millis
    StartMillis = CurrentMillis; //Start zurücksetzen
    Calc_Laufzeit(); //Berechnung der Pumpenlaufzeiten
    //Prüfung ob Gesamtlaufzeit Pumpen + Puffer unter Intervall liegt
    if (Pumpenlaufzeit_ges > NextIntervall)
    {
      Failcode = 1;
    }
    if (Failcode == 0)
    {
      Pumpenfolge = 0; // Setzt die Pumpenfolge auf den ersten gültigen Wert und startet damit die Pumpenschleife
    }
  }
 
  // Pumpenaktivierung
  for (byte x = 0; x < Kreise; x++)
  {
    if ((Pumpenstatus[x] == HIGH) && (Pumpenfolge == x)) //Wenn die Pumpe aus ist und an der Reihe
    {
      digitalWrite (R[x], LOW); // Pumpe einschalten
      Pumpenstatus[x] = LOW; // Pumpenstatus anpassen
      StartMillis_Pumpe[x] = CurrentMillis; //Startpumkt der Pumpe setzen
    }
    else if ((Pumpenstatus[x] == LOW) && (CurrentMillis - StartMillis_Pumpe[x] >= Pumpenlaufzeit[x]) && (Pumpenfolge == x)) //Wenn die Pumpe an ist, die Laufzeit erreicht und an der Reihe
    {
      digitalWrite (R[x], HIGH); // Pumpe ausschalten
      Pumpenstatus[x] = HIGH; // Pumpenstatus anpassen
      Pumpenfolge = x + 1; // Aktiviert die nächste Pumpe und bleibt nach der letzten Pumpe auf ungültigem Wert stehen
    }
  }
  if (CurrentMillis - StartMonitor >= Monitorintervall) //Ausgabe im Intervall
  {
    Serial.print("Pumpenlaufzeit0: ");
    Serial.println(Pumpenlaufzeit[0]);
    Serial.print("Pumpenlaufzeit1: ");
    Serial.println(Pumpenlaufzeit[1]);
    Serial.print("Pumpenlaufzeit2: ");
    Serial.println(Pumpenlaufzeit[2]);
    Serial.print("Pumpenlaufzeit3: ");
    Serial.println(Pumpenlaufzeit[3]);
    Serial.print("NextIntervall: ");
    Serial.println(NextIntervall);
    Serial.print("Fehler: ");
    Serial.println(Failcode);
    StartMonitor = CurrentMillis;
  }
}

void Calc_Laufzeit()
{
  Pumpenlaufzeit_ges = 2000; //kleiner Puffer
  for (byte x = 0; x < Kreise; x++)
  {
    if (CurrentSkip[x] < 1) //Wenn nicht geskipt wird, Berechnung aus Menge und Förderleistung
    {
      Pumpenlaufzeit[x] = Menge[x] / FL[x] * 1000;
      CurrentSkip[x] = Skip[x]; //Rücksetzung der Skipvariable auf Ausganswert
    }
    else
    {
      Pumpenlaufzeit[x] = 0; // Wenn geskipt wird, dann keine Laufzeit
      CurrentSkip[x]--; //Runterzählen der Skipvariable bis 0
    }
    Pumpenlaufzeit_ges = Pumpenlaufzeit_ges + Pumpenlaufzeit[x];
  }
}


Der macht wieder was er soll, aber von ideal sicherlich noch recht entfernt...

Die Empfehlung zum ESP 32 klingt interessant. Damit werde ich es wohl mal probieren. Zwischenzeitlich hab ich auch gelernt, dass ein analoger Eingang für mehrere Sensoren kein großes Problem ist.

Für weitere Tipps und Anregungen bin ich immer offen ...

Grüssle Olli

Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: combie on Jun 30, 2020, 10:10 pm
Quote
Kann mein Code optimiert werden?
Ich sehe bei dir einige Arrays, welche gleich lang sein MÜSSEN.

Quote
Für weitere Tipps und Anregungen bin ich immer offen ...
Das vorher genannte, ist eigentlich ein dringendlicher Anlass eine Struktur bildende Maßnahme einzuläuten.
Also nicht die Daten einer Pumpe über einige Arrays verstreut, sondern zusammengefasst, was zusammen gehört.
Und die Pumpen dann selber in ein Array stopfen



Hier mal ein Strickmuster:

Code: [Select]


struct Pumpe
{
  const int FL;  // Förderleistungen der Pumpen in den einzelnen Bereichen 0 bis 3 in ml/s
  const byte R;  // Belegung der Pins für die Pumpenrelais
  int Menge;     // auszubringende Wassermengen in den einzelnen Bereichen 0 bis 3 in ml
  byte Skip;     // Kenner ob und wie viele Gießintervalle ausgelassen werden sollen pro Bereich
 
  void init()
  {
    digitalWrite(R, HIGH); //Relais schalten bei LOW
    pinMode(R, OUTPUT);
  }
 
  void run()
  {
     // hier tue das, was deine Pumpe tun muss
  }
};


Pumpe pumpen[] {
                           {20,2,100,0},
                           {20,3, 75,1},
                           {20,4,200,2},
                           {20,5,125,0},
                         };




void setup()
{
  Serial.begin(9600);
 
  for(Pumpe &p:pumpen) p.init();
}

void loop()
{
  for(Pumpe &p:pumpen) p.run();
}



Todo:
Run mit Fleisch füllen
Auf class umbauen
Ein Konstruktor wird sinnvoll sein


Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: HotSystems on Jun 30, 2020, 10:10 pm
Quote
Zwischenzeitlich hab ich auch gelernt, dass ein analoger Eingang für mehrere Sensoren kein großes Problem ist.

Da hast du sicher etwas falsch verstanden.
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: combie on Jun 30, 2020, 10:14 pm
Da hast du sicher etwas falsch verstanden.

evtl. meint ihm I2C über A4 A5
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: HotSystems on Jun 30, 2020, 10:17 pm
evtl. meint ihm I2C über A4 A5
Jo, da kann es sein.
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: olli_h on Jun 30, 2020, 10:36 pm
Hi zusammen,

zum Thema mehrere Sensoren an einem Analog Eingang hab ich einmal diese Schaltung gefunden:

Anleitung Schaltung (https://www.instructables.com/id/ESP8266-with-Multiple-Analog-Sensors/). Fand ich soweit ganz einleuchtend.

Und diese Bauteile: Multiplexer (https://www.amazon.de/dp/B06XGFTN7K/ref=cm_sw_em_r_mt_dp_U_Ha6-EbXYZCTQA)  Klingt auch recht simpel, oder täusche ich mich da?  :smiley-confuse:

Die Struktur bildenden Maßnahmen werde ich einleiten. Aber ich fürchte da brauche ich ein bissel Zeit für. Der Rest der Woche ist ziemlich verplant .... ::)

Grüssle Olli
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: HotSystems on Jun 30, 2020, 10:44 pm
Ahh...ok, mittels Multiplexer, das ist ja auch was anderes und sicher keine simple Sache.
Aber ok, so geht das natürlich, mit dem entsprechenden Sketch.
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: agmue on Jun 30, 2020, 11:12 pm
Die Struktur bildenden Maßnahmen werde ich einleiten.
Das Beispiel Wieder bewässerung (https://forum.arduino.cc/index.php?topic=578429.msg3947641#msg3947641) hast Du sicherlich schon gefunden.

Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: agmue on Jul 01, 2020, 10:08 am
In #6 habe ich einen Link zu Programmierrichtlinien ergänzt.

Als Einzelkämpfer ist das egal, in der Gruppe macht eine Richtlinie Sinn.

In #7 hast Du schon (wieder) eine Menge richtig gemacht, dennoch Anmerkungen von mir:

1. Typ:
Code: [Select]
float Menge[] = {55, 25, 30, 50};
Wegen der Deutlichkeit würde ich {55.0, 25.0, 30.0, 50.0} schreiben.

2. Zahl der Elemente:
Code: [Select]
const byte FL[Kreise] = {20, 20, 20, 20};
Der Zugriff auf nicht vorhandene Elemente eines Feldes ist ein häufiger Fehler vom Typ "Programm schmiert manchmal ab". Leider wird das zur Laufzeit vom Programm nicht erkannt. Mit der zusätzlichen Angabe der Anzahl der Elemente kann man dieses Problem zumindest manchmal frühzeitig erkennen.

3. Schleife hin zu loop öffnen: (ungetestet)
Code: [Select]
 // Pumpenaktivierung
  static byte x = 0;
  if (Pumpenfolge < Kreise)
  {
    if ((Pumpenstatus[x] == HIGH) && (Pumpenfolge == x)) //Wenn die Pumpe aus ist und an der Reihe
    {
      digitalWrite (R[x], LOW); // Pumpe einschalten
      Pumpenstatus[x] = LOW; // Pumpenstatus anpassen
      StartMillis_Pumpe[x] = CurrentMillis; //Startpumkt der Pumpe setzen
    }
    else if ((Pumpenstatus[x] == LOW) && (CurrentMillis - StartMillis_Pumpe[x] >= Pumpenlaufzeit[x]) && (Pumpenfolge == x)) //Wenn die Pumpe an ist, die Laufzeit erreicht und an der Reihe
    {
      digitalWrite (R[x], HIGH); // Pumpe ausschalten
      Pumpenstatus[x] = HIGH; // Pumpenstatus anpassen
      Pumpenfolge = x + 1; // Aktiviert die nächste Pumpe und bleibt nach der letzten Pumpe auf ungültigem Wert stehen
    }
  }
  x = (1 + x) % Kreise;
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: olli_h on Jul 02, 2020, 11:51 pm
Hiho und guten Abend, vielen Dank für die Wegweiser und "Hausaufgaben", hab mich mal mit den structs befasst und den code entsprechend umgebaut:

Code: [Select]
const byte Kreise = 4; // Anzahl der Kreise, Achtung bei Änderung auch die Arrays mit anpassen!

//Strukturdefinition
struct Pumpenkreis_st
{
  const byte Nr; //Pumpennummer
  const byte FL; //Förderleistung des Pumpenkreises bis 255 ml/s
  const byte R; //Belegung der Pins für die Pumpenrelais
  float Menge; // Auszubringende Mengen in ml, hier wird float benötigt um die spätere Division durch FL hinzubekommen
  byte Skip; // Kenner ob und wie viele Gießintervalle ausgelassen werden sollen pro Bereich
  uint32_t StartMillis_Pumpe; //Startpunkte der einzelnen Pumpen
  bool Pumpenstatus; //Status ob Pumpe läuft oder nicht
  uint32_t Pumpenlaufzeit; //Länge der Pumpenlaufzeiten pro Kreis
  byte CurrentSkip; // Zähler für die aktuelle Anzahl der Intervalle die bereits ausgelassen worden sind
  byte Folge;

  void init() //Initialisierung
  {
    pinMode (R, OUTPUT); //Pins für die Relais setzen
    digitalWrite (R, HIGH); //Relais schlaten bei LOW, daher Grundzustand HIGH
    CurrentSkip = Skip; //erste Skipwerte setzen
    Folge = Kreise; //Pumpenfolge auf ungültig setzen
  }

  uint32_t calc() //Berechnet die Pumpenlaufzeiten
  {
    if (CurrentSkip < 1) //Wenn nicht geskipt wird, Berechnung aus Menge und Förderleistung
    {
      Pumpenlaufzeit = Menge / FL * 1000;
      CurrentSkip = Skip; //Rücksetzung der Skipvariable auf Ausgangswert
    }
    else
    {
      Pumpenlaufzeit = 0; // Wenn geskipt wird, dann keine Laufzeit
      CurrentSkip--; //Runterzählen der Skipvariable bis 0
    }
    return Pumpenlaufzeit;
  }
  byte start(uint32_t Now, byte Folge) //Lässt die Pumpen laufen, braucht die aktuelle Zeit und die Pumpenfolge als Parameter
  {
    if ((Pumpenstatus == HIGH) && (Folge == Nr)) //Wenn die Pumpe aus ist und an der Reihe
    {
      digitalWrite (R, LOW); // Pumpe einschalten
      Pumpenstatus = LOW; // Pumpenstatus anpassen
      StartMillis_Pumpe = Now; //Startpumkt der Pumpe setzen
    }
    else if ((Pumpenstatus == LOW) && (Now - StartMillis_Pumpe >= Pumpenlaufzeit) && (Folge == Nr)) //Wenn die Pumpe an ist, die Laufzeit erreicht und an der Reihe
    {
      digitalWrite (R, HIGH); // Pumpe ausschalten
      Pumpenstatus = HIGH; // Pumpenstatus anpassen
      Folge++; // Aktiviert die nächste Pumpe und bleibt nach der letzten Pumpe auf ungültigem Wert stehen
    }
    return Folge;
  }

  void ausgabe() //  Gibt Daten auf dem Serial Monitor aus
  {
    Serial.print("Pumpenlaufzeit ");
    Serial.print(Nr);
    Serial.print(": ");
    Serial.println(Pumpenlaufzeit);
  }

};

//Array für Pumpenkreise deklarieren und befüllen
Pumpenkreis_st Pumpenkreis [Kreise]
{ //Nr, FL, R, Menge, Skip, StartMillis_Pumpe, Pumpenstatus, Pumpenlaufzeit, CurrentSkip
  {0,  20, 2, 55.0,  0,    0,                 HIGH,         0,               0           },
  {1,  20, 3, 25.0,  1,    0,                 HIGH,         0,               0           },
  {2,  20, 4, 30.0,  0,    0,                 HIGH,         0,               0           },
  {3,  20, 5, 50.0,  2,    0,                 HIGH,         0,               0           },
};

float ToFirst_h = 0.005; //Zeit bis Start erste Bewässerung in Stunden, 18s zum Testen

uint32_t CurrentMillis; //Aktuell vergangene Zeit seit Start des Controllers
float Intervall_h; // Länge des Intervalls in dem Wasser ausgebracht werden soll in Stunden
uint32_t StartMillis; //Startpunkt des Intervalls bis zur Bewässerung
uint32_t NextIntervall; //Länge des nächsten Intervalls bis zur Bewässerung

uint32_t Pumpenlaufzeit_ges; //Summe aller Pumpenlaufzeiten + Puffer
byte Pumpenfolge = Kreise; // Zeigt welche Pumpe an der Reihe ist. Mit Setzen auf Kreise erst mal ungültig, damit am Anfang nix läuft.
byte Failcode; // Fehlerkenner für Unterbrechung von loop Teilen und Anzeige

uint32_t Monitorintervall = 3000; //Intervall für Ausgabe auf dem Seriellen Monitor
uint32_t StartMonitor = 0;

void setup()
{
  // Initialwerte für Bewässerung
  Serial.begin(9600);
  Failcode = 0; //Fehlercode 0 = kein Fehler
  Intervall_h = 0.005; //Bewässerung alle 18s für Test - später 24 oder 12

  for (Pumpenkreis_st &Pk : Pumpenkreis) Pk.init(); //Pumpenkreis_st ist die Struktur, Pumpenkreis das Array vom Typ Pumpenkreis_st, Pk ist die einzelne Variable im Array Pumpenkreis vom Typ Pumpenkreis_stt, init ist die Methode die innerhalb Pumpenkreis_st aufgerufen wird

  StartMillis = millis(); // Startzeit setzen
  NextIntervall = ToFirst_h * 3600000; //Erstes Intervall setzen in Millis
}

void loop()
{
  CurrentMillis = millis();

  // Bewässerungsintervall
  if (CurrentMillis - StartMillis >= NextIntervall)
  {
    NextIntervall = Intervall_h * 3600000; //Nächstes Intervall setzen in Millis
    StartMillis = CurrentMillis; //Start zurücksetzen
    Pumpenlaufzeit_ges = 2000; //Puffer und Reset der Gesamtlaufzeit
    for (Pumpenkreis_st &Pk : Pumpenkreis) Pumpenlaufzeit_ges = Pumpenlaufzeit_ges + Pk.calc(); //Aufruf Struktur über for in Kurzform wie im Setup kommentiert, Methode calc gibt hier die einzelnen Pumpenlaufzeiten zurück, Summierung in Gesamtlaufzeit
    if (Pumpenlaufzeit_ges > NextIntervall) Failcode = 1; //Prüfung ob Gesamtlaufzeit Pumpen + Puffer unter Intervall liegt
    if (Failcode == 0) Pumpenfolge = 0; // Setzt die Pumpenfolge auf den ersten gültigen Wert und startet damit die Pumpenschleife
  }

  // Pumpenaktivierung
  for (Pumpenkreis_st &Pk : Pumpenkreis) Pumpenfolge = Pk.start(CurrentMillis, Pumpenfolge); //Aufruf wie oben, Methode start bekommt aktuelle Zeit und Pumpenfolge übergeben, gibt die neue Pumpenfolge zurück

  if (CurrentMillis - StartMonitor >= Monitorintervall) //Ausgabe im Intervall
  {
    for (Pumpenkreis_st &Pk : Pumpenkreis) Pk.ausgabe(); //Ausgabe einiger Strukturwerte
    Serial.print("Gesamtlaufzeit der Pumpen: ");
    Serial.println(Pumpenlaufzeit_ges);
    Serial.print("NextIntervall: ");
    Serial.println(NextIntervall);
    Serial.print("Fehler: ");
    Serial.println(Failcode);
    Serial.print("Pumpenfolge: ");
    Serial.println(Pumpenfolge);
    StartMonitor = CurrentMillis;
  }
}


Macht auch wieder das was er soll, Kritik wie immer erwünscht :-)

Der Umbau in class steht noch an.

Ich bin mir nicht ganz sicher, wie man das am besten mit den Variablen macht. Hab irgendwie ein ungutes Gefühl aus einer struct/class Methode globale Variablen zu ändern, obwohl das hier und da einiges vereinfachen würde. Aber eigentlich sollte ja so eine class problemlos in andere codes übertragbar sein und ob sie da die gleichen globalen Variablen findet ist ja eher fraglich, also hab ich mal versucht alles zu übergeben. Hab allerdings auch irgendwo gelesen, dass Variablen per Referenz übergeben werden können, muss ich mir mal anschauen.

Die ESP 32 sind heute auch schon gekommen ... das steht dann auch noch an, vom Uno da drauf umzuziehen ...

Grüssle Olli

Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: combie on Jul 03, 2020, 01:07 am
Quote
Ich bin mir nicht ganz sicher, wie man das am besten mit den Variablen macht. Hab irgendwie ein ungutes Gefühl aus einer struct/class Methode globale Variablen zu ändern, obwohl das hier und da einiges vereinfachen würde. Aber eigentlich sollte ja so eine class problemlos in andere codes übertragbar sein und ob sie da die gleichen globalen Variablen findet ist ja eher fraglich, also hab ich mal versucht alles zu übergeben. Hab allerdings auch irgendwo gelesen, dass Variablen per Referenz übergeben werden können, muss ich mir mal anschauen.
Ja, ich nenne Funktionen, welche auf globale Variablen zugreifen, oder statische Variablen enthalten Wegwerf Funktionen.
Oder auch wegwerf Klassen, wenn es darin geschieht.

Weil eben nicht/schlecht wieder verwendbar.


Beispiel:
Du hast eine Methode ausgabe() in der Klasse/Struktur erfunden.
Gute Idee!
Ich peppe die mal jetzt mal etwas auf, so dass sie die globale Variable Serial zur Ausgabe übergeben bekommt.
Das ist dann schon mal eine Abhängigkeit weniger.
Auch hast du jetzt die Möglichkeit deine Objekte z.B.  in Dateien zu drucken.
Eben alles, was Print implementiert, nimmt deine Klasse.


Code: [Select]

class Pumpenkreis_st : public Printable
{
  private:
   const int kreis;

  public:
    Pumpenkreis_st(const int kreis):kreis(kreis){}

    virtual size_t printTo(Print & print) const override
    {
      size_t len = 0;
      len += print.print("Kreis ");
      len += print.print(kreis);
      return len;
    }

};

Pumpenkreis_st Pumpenkreis[] {1,2,3,4};


void setup()
{
  Serial.begin(9600);
}

void loop()
{
  for (Pumpenkreis_st &Pk : Pumpenkreis) Serial.println(Pk); //Ausgabe einiger Strukturwerte
}







Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: gregorss on Jul 03, 2020, 01:18 am
...
Ich bin gerade eben erst in diesen Thread gestolpert und habe Deinen Code nur sehr oberflächlich quergelesen. Aufgefallen sind mir dabei zwei Dinge:


Das nur mal auf die Schnelle mein Senf dazu.

Gruß

Gregor
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: agmue on Jul 03, 2020, 10:11 am
Auch zwei Senfkörnchen von mir: Als fauler Mensch mag ich kreis(X_kreis), da ich mir keine zwei Namen ausdenken muß. Zur Verdeutlichung, daß es sich aber um unterschiedliche Dinge handelt, meine Lernversion:

Code: [Select]

class Pumpenkreis_st : public Printable
{
  private:
    const int kreis;

  public:
    Pumpenkreis_st(const int X_kreis): kreis(X_kreis) {}

    virtual size_t printTo(Print & print) const override
    {
      size_t len = 0;
      len += print.print("Kreis ");
      len += print.print(kreis);
      return len;
    }

};

Pumpenkreis_st Pumpenkreis[] {1, 2, 3, 4};


void setup()
{
  Serial.begin(9600);
}

void loop()
{
  for (Pumpenkreis_st &Pk : Pumpenkreis) Serial.println(Pk); //Ausgabe einiger Strukturwerte
}

X_kreis enthält die Werte {1, 2, 3, 4}, womit die Konstante kreis, bei einer Variablen als Anfangswert, gefüllt wird. Die Methode verwendet dann die Konstante kreis.

Variablen, die für alle Elemente den gleichen Anfangswert bekommen, können ihren Wert auch vom Konstruktor erhalten:

Code: [Select]
//Strukturdefinition
class Pumpenkreis_st
{
    const byte Nr; //Pumpennummer
    const byte FL; //Förderleistung des Pumpenkreises bis 255 ml/s
    const byte R; //Belegung der Pins für die Pumpenrelais
    float Menge; // Auszubringende Mengen in ml, hier wird float benötigt um die spätere Division durch FL hinzubekommen
    byte Skip; // Kenner ob und wie viele Gießintervalle ausgelassen werden sollen pro Bereich
    uint32_t StartMillis_Pumpe; //Startpunkte der einzelnen Pumpen
    bool Pumpenstatus; //Status ob Pumpe läuft oder nicht
    uint32_t Pumpenlaufzeit; //Länge der Pumpenlaufzeiten pro Kreis
    byte CurrentSkip; // Zähler für die aktuelle Anzahl der Intervalle die bereits ausgelassen worden sind
    byte Folge;

  public:
    Pumpenkreis_st(const byte Nr, const byte FL, const byte R, float Menge, byte Skip):
      Nr(Nr), FL(FL), R(R), Menge(Menge), Skip(Skip), StartMillis_Pumpe(0), Pumpenstatus(HIGH), Pumpenlaufzeit(0), CurrentSkip(0) {}

...

//Array für Pumpenkreise deklarieren und befüllen
Pumpenkreis_st Pumpenkreis [Kreise]
{ //Nr, FL, R, Menge, Skip, StartMillis_Pumpe, Pumpenstatus, Pumpenlaufzeit, CurrentSkip
  {0,  20, 2, 55.0,  0},
  {1,  20, 3, 25.0,  1},
  {2,  20, 4, 30.0,  0},
  {3,  20, 5, 50.0,  2}
};
...


Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: michael_x on Jul 03, 2020, 12:08 pm
Das Wesentliche an combie's Beispiel ist die Ermunterung, eigene Klassen als Erweiterung von Printable zu definieren, um Printable::printTo zu überladen.

Setzt natürlich voraus, dass klar ist, was bei
   MeineKlasse x = ...;
   Serial.println(x);
ausgegeben werden sollte.

Wenn man schon dabei ist, extra eine Funktion/Methode ausgabe() zu erfinden ...

Karma +
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: olli_h on Jul 06, 2020, 10:44 pm
Hiho zusammen, mal wieder ein update von mir.

Vielen Dank für die Kommentare, hab wie immer versucht das meiste umzusetzen, und die Sache läuft immer noch  :D. Zwischenzeitlich bin ich von Uno auf ESP32 umgezogen. Ging im Wesentlichen problemlos, bis auf das Übertragen des Codes, was etwas nervig ist. Der Boot Button muss im richtigen Moment gedrückt werden und wenn ich den 5V Pin belegt habe, weigert er sich generell Code anzunehmen... ist das normal?

Ich hab nun das Ganze als Class umgebaut und in .h und .cpp Datei geordnet. Ist Code Breite verhandelbar? 100 Zeichen bekomme ich ganz gut hin. Hab ich den Rest so einigermaßen richtig hinbekommen?

Die Sache mit dem Printable check ich noch nicht so ganz. Hab auch irgendwie wenig Material gefunden und noch wenig Zeit mich damit zu beschäftigen. Hab es mal kurz probiert auf die 3 Dateien richtig zu verteilen, aber da gab es Probleme mit dem virtual sitze_t. Hab hier (https://forum.arduino.cc/index.php?topic=456569.0) was gefunden, das könnte mich weiter bringen. Gibts da noch irgendwo info Quellen?

Hier mal der aktuelle Stand:

.ino

Code: [Select]
//****************20******************40******************60******************80*****************100
#include "Pumpenkreis_cl.h"

const byte Kreise = 4; // Anzahl der Kreise, Achtung bei Änderung auch die Arrays mit anpassen!

//Array für Pumpenkreise deklarieren, füllen der Variablen, die nicht durchgängig gleich sind
Pumpenkreis_cl Pumpenkreis [Kreise]
{ //Nr, FL, R, Menge, Skip, StartMillis_Pumpe, Pumpenstatus, Pumpenlaufzeit, CurrentSkip
  {0,  20, 12, 55.0,  0},
  {1,  20, 14, 25.0,  1},
  {2,  20, 27, 30.0,  0},
  {3,  20, 26, 50.0,  2},
};

float ToFirst_h = 0.005; //Zeit bis Start erste Bewässerung in Stunden, 18s zum Testen

uint32_t CurrentMillis; //Aktuell vergangene Zeit seit Start des Controllers
float Intervall_h; // Länge des Intervalls in dem Wasser ausgebracht werden soll in Stunden
uint32_t StartMillis; //Startpunkt des Intervalls bis zur Bewässerung
uint32_t NextIntervall; //Länge des nächsten Intervalls bis zur Bewässerung

uint32_t Pumpenlaufzeit_ges; //Summe aller Pumpenlaufzeiten + Puffer

//Zeigt welche Pumpe an der Reihe ist. Mit Setzen auf Kreise ungültig, damit am Anfang nix läuft.
byte Pumpenfolge = Kreise;
byte Failcode; // Fehlerkenner für Unterbrechung von loop Teilen und Anzeige

uint32_t Monitorintervall = 3000; //Intervall für Ausgabe auf dem Seriellen Monitor
uint32_t StartMonitor = 0;

void setup()
{
  // Initialwerte für Bewässerung
  Serial.begin(9600);
  Failcode = 0; //Fehlercode 0 = kein Fehler
  Intervall_h = 0.005; //Bewässerung alle 18s für Test - später 24 oder 12
 
  //Pumpenkreis_cl ist die Klasse, Pumpenkreis das Array vom Typ Pumpenkreis_cl,
  //Pk ist die einzelne Variable im Array Pumpenkreis vom Typ Pumpenkreis_cl,
  //init ist die Methode die innerhalb Pumpenkreis_cl aufgerufen wird
  for (Pumpenkreis_cl &Pk : Pumpenkreis)
  {
    Pk.init(Kreise);
  }
  StartMillis = millis(); // Startzeit setzen
  NextIntervall = ToFirst_h * 3600000; //Erstes Intervall setzen in Millis
}

void loop()
{
  CurrentMillis = millis();

  // Bewässerungsintervall
  if (CurrentMillis - StartMillis >= NextIntervall)
  {
    NextIntervall = Intervall_h * 3600000; //Nächstes Intervall setzen in Millis
    StartMillis = CurrentMillis; //Start zurücksetzen
    Pumpenlaufzeit_ges = 2000; //Puffer und Reset der Gesamtlaufzeit

    //Aufruf Struktur über for in Kurzform wie im Setup kommentiert,
    //Methode calc gibt hier die einzelnen Pumpenlaufzeiten zurück, Summierung in Gesamtlaufzeit
    for (Pumpenkreis_cl &Pk : Pumpenkreis)
    {
      Pumpenlaufzeit_ges = Pumpenlaufzeit_ges + Pk.calc();
    }
   
    //Prüfung ob Gesamtlaufzeit Pumpen + Puffer unter Intervall liegt
    if (Pumpenlaufzeit_ges > NextIntervall) Failcode = 1;
   
    // Setzt die Pumpenfolge auf den ersten gültigen Wert und startet damit die Pumpenschleife
    if (Failcode == 0) Pumpenfolge = 0;
  }

  // Pumpenaktivierung
  //Aufruf wie oben, Methode start bekommt aktuelle Zeit und Pumpenfolge übergeben,
  //gibt die neue Pumpenfolge zurück
  for (Pumpenkreis_cl &Pk : Pumpenkreis)
  {
    Pumpenfolge = Pk.start(CurrentMillis, Pumpenfolge);
  }
 
  if (CurrentMillis - StartMonitor >= Monitorintervall) //Ausgabe im Intervall
  {
    for (Pumpenkreis_cl &Pk : Pumpenkreis) Pk.ausgabe(); //Ausgabe einiger Strukturwerte
    Serial.print("Gesamtlaufzeit der Pumpen: ");
    Serial.println(Pumpenlaufzeit_ges);
    Serial.print("NextIntervall: ");
    Serial.println(NextIntervall);
    Serial.print("Fehler: ");
    Serial.println(Failcode);
    Serial.print("Pumpenfolge: ");
    Serial.println(Pumpenfolge);
    StartMonitor = CurrentMillis;
  }
}


.h
Code: [Select]
//****************20******************40******************60******************80*****************100
#ifndef Pumpenkreis_cl_h
#define Pumpenkreis_cl_h
#include "Arduino.h"
class Pumpenkreis_cl
{
  private:
    const byte Nr; //Pumpennummer
    const byte FL; //Förderleistung des Pumpenkreises bis 255 ml/s
    const byte R; //Belegung der Pins für die Pumpenrelais
    float Menge; // Auszubringende Mengen in ml, hier float für die spätere Division durch FL
    byte Skip; // Kenner ob und wie viele Gießintervalle ausgelassen werden sollen pro Bereich
    uint32_t StartMillis_Pumpe; //Startpunkte der einzelnen Pumpen
    bool Pumpenstatus; //Status ob Pumpe läuft oder nicht
    uint32_t Pumpenlaufzeit; //Länge der Pumpenlaufzeiten pro Kreis
    byte CurrentSkip; //die aktuelle Anzahl der Intervalle die bereits ausgelassen worden sind
    byte Folge;

  public:
    //Konstuktor - heißt wie Klasse, Variablen werden aufgeführt, die im Array initialisiert werden
    //Variablen mit durchgehend gleichen Werten werden im Konstruktor initialisiert (cpp Datei)
   
    Pumpenkreis_cl(const byte Nr, const byte FL, const byte R, float Menge, byte Skip);
   
    void init(byte Kreise); //Initialisierung, braucht Kreise als Parameter

    uint32_t calc(); //Berechnet die Pumpenlaufzeiten
 
    byte start(uint32_t Now, byte Folge); //Lässt Pumpen laufen, braucht akt. Zeit und Pumpenfolge

    void ausgabe(); //  Gibt Daten auf dem Serial Monitor aus
};
#endif


.cpp
Code: [Select]
//****************20******************40******************60******************80*****************100
#include "Arduino.h"
#include "Pumpenkreis_cl.h"

//Konstruktor mit Initalisierung der Variablen, konstante Werte übers Array werden direkt gesezt
Pumpenkreis_cl::Pumpenkreis_cl(const byte Nr, const byte FL, const byte R, float Menge, byte Skip):
  Nr(Nr), FL(FL), R(R), Menge(Menge), Skip(Skip),
  StartMillis_Pumpe(0), Pumpenstatus(HIGH), Pumpenlaufzeit(0), CurrentSkip(0) {}

void Pumpenkreis_cl :: init(byte Kreise) //Initialisierung
{
  pinMode (R, OUTPUT); //Pins für die Relais setzen
  digitalWrite (R, HIGH); //Relais schlaten bei LOW, daher Grundzustand HIGH
  CurrentSkip = Skip; //erste Skipwerte setzen
  Folge = Kreise; //Pumpenfolge auf ungültig setzen
}

uint32_t Pumpenkreis_cl :: calc() //Berechnet die Pumpenlaufzeiten
{
  if (CurrentSkip < 1) //Wenn nicht geskipt wird, Berechnung aus Menge und Förderleistung
  {
    Pumpenlaufzeit = Menge / FL * 1000;
    CurrentSkip = Skip; //Rücksetzung der Skipvariable auf Ausgangswert
  }
  else
  {
    Pumpenlaufzeit = 0; // Wenn geskipt wird, dann keine Laufzeit
    CurrentSkip--; //Runterzählen der Skipvariable bis 0
  }
  return Pumpenlaufzeit;
}

//Lässt Pumpen laufen, braucht aktuelle Zeit und Pumpenfolge
byte Pumpenkreis_cl :: start(uint32_t Now, byte Folge)
{
  //Wenn die Pumpe aus ist und an der Reihe
  if ((Pumpenstatus == HIGH) && (Folge == Nr))
  {
    digitalWrite (R, LOW); // Pumpe einschalten
    Pumpenstatus = LOW; // Pumpenstatus anpassen
    StartMillis_Pumpe = Now; //Startpumkt der Pumpe setzen
  }
  //Wenn die Pumpe an ist, die Laufzeit erreicht und an der Reihe
  else if ((Pumpenstatus == LOW) && (Now - StartMillis_Pumpe >= Pumpenlaufzeit) && (Folge == Nr))
  {
    digitalWrite (R, HIGH); // Pumpe ausschalten
    Pumpenstatus = HIGH; // Pumpenstatus anpassen
    Folge++; // Aktiviert nächste Pumpe, bleibt nach der letzten Pumpe auf ungültigem Wert stehen
  }
  return Folge;
}

void Pumpenkreis_cl :: ausgabe() //  Gibt Daten auf dem Serial Monitor aus
{
  Serial.print("Pumpenlaufzeit ");
  Serial.print(Nr);
  Serial.print(": ");
  Serial.println(Pumpenlaufzeit);
}


Grüsse Olli

Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: noiasca on Jul 06, 2020, 10:52 pm
Quote
Der Boot Button muss im richtigen Moment gedrückt werden und wenn ich den 5V Pin belegt habe, weigert er sich generell Code anzunehmen... ist das normal?
ja, habe ich auch auf einigen Boards.
Nimm OTA, geht sowieso schneller ;-)
Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: agmue on Jul 06, 2020, 11:59 pm
Der Boot Button muss im richtigen Moment gedrückt werden ...
Für Faule wie mich: EN-Pin - 10µF Elektrolyt - GND

Title: Re: Einsteigerfragen: Kann mein Code optimiert werden? Welches Board für Wifi?
Post by: gregorss on Jul 07, 2020, 12:49 am
Ist Code Breite verhandelbar? 100 Zeichen bekomme ich ganz gut hin.
Ja, klar ist das verhandelbar :-)

Ob und wie Du Deinen Code organisierst/formatierst/usw. hängt im Wesentlichen davon ab, wer damit arbeiten soll. Wenn Du der Einzige bist, der sich damit herumschlagen muss, kannst Du es machen, wie es Dir passt.

Wichtig werden Vorgaben zu Zeilenlänge oder Formatierung/Klammerung dann, wenn mehrere Leute mit dem Code zurecht kommen sollen. Oder z. B. dann, wenn Du sicher sein möchtest, dass Du auch in ein paar Wochen oder Monaten noch verstehen können möchtest, was Du Dir jetzt, wo Du grad im Code steckst, beim Programmieren gedacht hast.

Gruß

Gregor