Poolwasser mit der Sonne aufheizen.

Benutzeravatar
Admin
Administrator
Beiträge: 1199
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Admin »

Man sieht am Foto im Beitrag darüber, dass auf meinem Display in der dritten Zeile das "S" von dem Wort "Soll" weg ist. :(o): Das ist im Programm hier darüber inzwischen bereinigt. Wenn in der ersten Zeile der % - Wert 100 ist, dann braucht die Ausgabe eine Position mehr, und die wird in die dritte Zeile geschoben, das ist eben so, bei diesen Displays. Deshalb schreibe ich jetzt immer, wenn die erste Zeile ausgegeben wird, danach das Wort "Soll" in der dritten Zeile neu. Das ist wesentlich einfach als die Ausgabe in der ersten Zeile genau auf 20 Zeichen zu begrenzen.

Franz
Bernhard - Fony
Beiträge: 73
Registriert: Mo 12. Jun 2023, 17:49
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Bernhard - Fony »

das ist eben so, bei diesen Displays.
Nicht nur, wenn man bei manchen TFT Lib ( Grundsätzlich Adafruit) nicht aufpasst passiert auch sowas, so am Rande, mag die Adafruit nicht, je nach TFT LCD nehme vom Oli Krause, Bodmer oder LcdWicki ( ist auch sehr gut beschrieben, aber nicht einfach, man muss sich einarbeiten )
Benutzeravatar
Admin
Administrator
Beiträge: 1199
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Admin »

Ich bekomme plötzlich eine Lieferung angekündigt, von Teilen, die ich vor einem Monat nachgefragt hat, aber keine Antwort bekommen habe. Jetzt bekomme ich plötzlich eine Lieferung, die sich "auf meine Bestellung von 2 August beruft. Und die Rechnung ist 0,00 Euro. Also ohne Berechung. Ich verstehe das noch nicht ganz. Aber ich werde mal nachhaken, wer da ein schlechtes Gewissen bekommen hat.
Das war mal eine Nachfrage vor etwa einem Monat, wie ich an 10 Verbindungsmuffen und an 10 Endkappen für diesen Krempel komme. Die meinen wohl, jetzt reisse ich wieder alles runter vom Dach und baue so um wie ich es haben wollte :?:
Wir überlegen schon, weil das Zeug ja nicht Frostfest ist, ob wir es am Ende des Sommers runterbauen und in den Müll tretten, oder ob wir uns das antun, diesen Steifen Krempel im nächsten Jahr wieder aufs Dach bauen. Es lässt sich ja auch nicht vernünftig lagern, nachdem wir es endlich einigermassen gerade gebogen haben, Sollen wir es wieder aufrollen. Ich denke das lassen wir mal schön. Wir könnte höchtes mal versuchen, vor dem abbauen heißes Wasser durch die Leitungen zu schicken, dass es weicher wird, um es dann aufzurollen. Und wenn das geklappt hat, im nächsten Jahr wieder heißes Wasser rein, um es wieder gerade zu biegen, bevor wir es aufs Dach bringen.
Naja, wir werden sehen. :(V):
Bernhard - Fony
Beiträge: 73
Registriert: Mo 12. Jun 2023, 17:49
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Bernhard - Fony »

Durchblassen mit Pressluft? Mache mit meinen PVC Schlächen im Spätherbst damit das Wasser zum größten teil rauskommt.
Einziges Problem bei Dir ist die parallele Verbindung, somit kann passieren das zu viel Wasser in den Dinger bleibt
Benutzeravatar
Admin
Administrator
Beiträge: 1199
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Admin »

Ja, da sind immer 32 Schläuche Parallel. und diese Dinge haben ich 3x in Reihe. Das sind 460 Meter Schlauch. :eek:

Ja, ich denke wir werden das Zeug am Dach lassen und von oben nach unten durchblasen. Wenn es im nächsten Sommer noch dicht ist, Glück gehabt, ansonsten Müll.

Schönes Wochenende
Franz :oo:
Benutzeravatar
Admin
Administrator
Beiträge: 1199
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Admin »

Bin gerade auch noch dabei, das Gerät nochmal zu bauen. Ich habe inzwischen für diese Gehäuse eine wunderbare 3mm Starke Alu-Montageplatte bekommen. Auf diese Platten möchte ich alle Teile die ich in einem Gerät brauche montieren. Das soll eine Platte werden, auf die man verschiedenen Teile montieren kann. Die Platte hat im Moment schon Löcher mit 3mm Gewinde, auf die ich dann Metall-Abstandsbolzen schrauben kann. Die Gewinde sind jetzt schon mal zur Aufnahme von einem Nano, oder einem Uno, oder einem Mega. Daneben ist Platz für einen DC/DC Wandler, wieder daneben Platz für den Motortreiber. Dann kommt noch eine Halterung für die Max 485 TTL und für die RJ45 - Buchse. Und mal schauen was da noch dazu kommt.

Ich möchte damit ein Grund-System schaffen, mit dem ich rel. schnell alles, was ich gerade bauen möchte einfach zusammenschraube. Wenn die neue Steuerung fertig ist, tausche ich die alte damit aus, so dass ich auch das alte Gehäuse mit der Montageplatte bestücken kann, für das nächte Gerät das ich entwickeln möchte. ALso so ein Baukasten-System.
Hier im Bild, rechts unten, sieht man so eine mit Abstandsbolzen bestückte Platte, wie sie auch hier in dem Geräte schon eigebaut ist. Aber die Platte wird noch wesentlich besser. Ich möchte die noch viel offener für andere Module machen. Also noch mehr Gewindelöcher, zur Aufnahme weiterer Module.
.
SolarRegler_03.jpeg
SolarRegler_03.jpeg (647.74 KiB) 468 mal betrachtet
Benutzeravatar
Admin
Administrator
Beiträge: 1199
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Admin »

Noch eine kleine Info, warum ich für den Start der Pumpe nicht die Differenz zwischen Poolwasser-Temperatur und Solarwasser-Temperatur verwenden kann. Beide Temperaturen werden in den Schläuchen am Dach gemessen. Daher sind diese Temperaturen natürlich ziehmlich gleich, wenn die Pumpe, also das Wasser nicht läuft. Daher nehme ich für den Anlauf die Temperatur am Dach vom Solarfühler. Das ist dieser Codeteil hier:

Code: Alles auswählen

  
  if ((tempsolar > 28) && (tempdif < 10))
    {
      tempdif = 10;
    }
     if ((tempsolar < 26) && (tempdif < 10))
    {
      tempdif = 0;
    }
    //-------------Solldrehzahl aus Temperaturdifferenz ermitteln--------------
    Solldrehzahl = map(tempdif, 10, 40, 150, 255);
    
Wenn die Temperatur am Dach größer 28 Grad ist, obwohl die Differenz kleiner 1 Grad ist, kann man annehmen, dass es sich lohnt die Pumpe einzuschalten. Also wird die Temperatur-Differenz auf "1" gestellt, naja es wird also etwas vorgegaukelt, was dann hoffentlich auch zutrifft. Im "map" wird aus "tempdif 10" eine "Solldrehzahl von 150". Also die Mindestdrehzahl mit der die Pumpe das Wasser aufs Dach pumpt.
Also Startet die Pumpe und wenn dann die Differenz größer wird, und die Wassertemperatur in Schlauch vom Pool zum Dach kleiner wird (weil ja das Poolwasser am ersten DS18B20 vor den Solar-Wasserschläuchen ankommt), ist alles klar und die Pumpe läuft, weil dann die Differenz sicher ein mehrfaches von 1 wird. Der zweite DS18B20, der sich im Schlauch nach den 460 Meter Solar-Wasserschläuchen am Dach befindet, bekommt dann das aufgeheizte Wasser, das nach dem Solar-Wasserschläuchen wieder zum Pool runterläuft.

Da ich ja nicht die Pumpe einfach laufen lassen kann, und dann das Wasser vielleicht eher gekühlt als geheizt wird, mußte irgend eine Lösung für den Start her. Und am Dach mehr als 28 Grad, ist ein guter Grund, denke ich. :(o): In der Sonne 28 Grad, sind auch rel. schnell erreicht, wenn die Sonne da drauf brennt. Das Wasser läuft in dem Moment, wo die Pumpe ausgeschalten wird, rel. zügig aus den Schläuchen in beiden Richtungen in den Pool zurück, weil diese Solar-Wassertaschen alles andere als Dicht sind. Die ziehen als sofort Luft an allen undichten Stellen, wenn das Wasser nach unten zieht, und sind razfaz leer. Was ja kein Problem ist, wenn die Pumpe läuft tröpfelt es ein bischen vom Dach, aber bei einem Poolinhalt von 42000 Liter, sind ein paar Tropfen Wasser die fehlen kein Problem. da laufen in der Stunde 1000 Liter übers Dach. Ein Problem ist eher das Wasser, dass den Pool bei Regen überfüllt. Das muß man regelmässig zum Rückspühlen des Sandfilters verwenden. So ist auch das Regenwasser für was gut. :(V):

Servus
Franz
Benutzeravatar
Admin
Administrator
Beiträge: 1199
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Admin »

Ich bin jetzt mit der Steuerung rel. zufrieden. Ich mache jetzt die zweite Steuerung noch fertig, dann tausche ich die erste gegen die Neue aus. Und die alte Steuerung bestücke ich dann auch mit dem Montageblech, und nutze die wieder für andere, neue Ideen.

Wenn sich jetzt im Betrieb, im laufe der Zeit, noch neue Fehler an der Solar - Poolheizung zeigen, bin ich natürlich sicher wieder dran und bringe entsprechende Programm-Änderungen, oder wenn nötig auch Infos zu Hardware - Änderungen. Aber im Momant denke ich läuft das alles sehr gut.

Servus
Franz

PS: Hier noch die aktuelle Software, Stand heute.

Code: Alles auswählen

// Arduino Pool_Solarheizung_Pumpensteuerung mit MPPT Kontrolle
#include <OneWire.h>
#include <DallasTemperature.h>
#include "Wire.h"
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
//###########################################################################
//-------------------------------------MPPT Regler Deklaration---------------
/*************************************
   Für Uno wird SoftwareSerial benutzt
**************************************/
#include <SoftwareSerial.h>
SoftwareSerial tracerSerial(9, 8); // RO, DI  Pins drehen wenn nicht funktioniert
/**********************************************
    Ich verwende  einen MAX485-kompatiblen RS485-Transceiver.
  Rx/Tx ist mit der seriellen Schnittstelle der Hardware an "Serial" verbunden.
  Die Pins "Data Enable" und "Rec3eiver Enable" sind wie folgt beschaltet:
 ********************************************************/
#include <ModbusMaster.h>

#define MAX485_DE      7 // DE und RE dürfen am einen Pin hängen 
#define MAX485_RE_NEG  7

// instantiate ModbusMaster object
ModbusMaster node;

int prozent = 0;
float akkuVolt = 0;
float akkuAmpere = 0;
float pvwat = 0;
float pva = 0;
float pvv = 0;
unsigned long currentMillis = 0;

void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}
unsigned long previousMillis = 0;
const long intervall = 60000;// Daten werden alle 60 Sek ausgelesen
//------------------------------------MPPT Regler Deklaration Ende-----------
//###########################################################################
//-----Motortreiber----
const byte RPWM = 10;
const byte LPWM = 11;
//-------Potis---------
const byte Poti1 = A0;
const byte Poti2 = A1;
//-------Taster--------
byte Tasterstatur = 0;
const byte Taster = 4;// Display einschalten !!
//-------Merker--------
byte Pumpe = 0;
int P1 = 0;
int P2 = 0;
byte Pool = 1; // Hier 1 oder 2 tauschen mit Solar, wenn Sensoren vertauscht
byte Solar = 2; // Hier 1 oder 2 tauschen mit Pool, wenn Sensoren vertauscht
int Drehzahl = 0;
int Solldrehzahl = 0;
int Sollalt = 10;
byte Anfahren = 0;
int Drehzahlmin = 150;
int Drehzahlmax = 255;
unsigned long millisekunden = 0;
//-------------------------------Zeiten---------------------------------------
unsigned long Sekundenablauf01 = 0;      // Messung Potis und Ausgabe Display
const unsigned long Pausezeit01 = 1000;
//------------------------------------------------------------------------------
unsigned long Sekundenablauf02 = 0;      // Display nach Zeit ausschalten
const unsigned long Pausezeit02 = 60000 * 15;
//------------------------------------------------------------------------------
unsigned long Sekundenablauf03 = 0;      //Serial Werte Ausgabezeit
const unsigned long Pausezeit03 = 60000 * 5;
//------------------------------------------------------------------------------
unsigned long Sekundenablauf04 = 0;      // Werte für Pumpe und Pumpe ansteuern
const unsigned long Pausezeit04 = 30000; //Alle 30 Sekunden Daten für Pumpe
//------------------------------------------------------------------------------
#define One_Wire_Bus 2  // Sensor auf Pin 2
OneWire oneWire(One_Wire_Bus);
DallasTemperature sensoren (&oneWire);
int Anzahl_Sensoren = 0;
int is = 0; // Zähler für die Sensoren
int ia = 0; // Zähler für die Adressstellen 0-7
int Sensor = 0;
float temppool = 0;
float tempsolar = 0;
float tempdif = 0;
DeviceAddress tempDeviceAddress; // Für die Adressausgabe
int numberOfDevices; // Für die Adressausgabe
//##########################################################################
//################################  Setup ##################################
//##########################################################################
void setup() {
  Wire.begin();
  sensoren.begin();
  Serial.begin(9600);
  lcd.begin();
  lcd.backlight();
  //##########################################################################
  //-----------------------------------MPPT Setup-----------------------------
  tracerSerial.begin(115200); // Modbus Kommunikation mit 115200 Baud
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  digitalWrite(MAX485_RE_NEG, 0);// Init in receive mode
  digitalWrite(MAX485_DE, 0);
  // Tracer xxxxAN Modbus slave ID 1
  node.begin(1, tracerSerial);  // Begin der Verbindung mit Tracer
  // Rückrufe ermöglichen es uns, den RS485-Transceiver korrekt zu konfigurieren
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  //-------------------------------MPPT Setup Ende--------------------------
  //##########################################################################
  lcd.setCursor (0, 1);
  lcd.print (F("Soll"));
  lcd.setCursor (10, 1);
  lcd.print (F("Ist"));
  lcd.setCursor (0, 2);
  lcd.print (F("Soll"));
  lcd.setCursor (10, 2);
  lcd.print (F("Ist"));
  lcd.setCursor (0, 3);
  lcd.print (F("Soll      Ist"));
  // Anzahl der Sesoren ermitteln-------------------------------------
  Anzahl_Sensoren = sensoren.getDeviceCount();
  // Ermitteln der Sensor-Adressen------------------------------------
  for (is = 0; is < Anzahl_Sensoren; is++)
  {
    if (sensoren.getAddress(tempDeviceAddress, is))
    {
      Serial.println ();
      printAddress(tempDeviceAddress);
    }
  }
  //-----------Aus-/Eingänge einrichten-------------------------------------
  pinMode(RPWM, OUTPUT);              // PWM rechts Pumpensteuerung
  pinMode(LPWM, OUTPUT);              // PWM links Pumpensteuerung
  pinMode(Poti1, INPUT);              // Pool Solltemperatur
  pinMode(Poti2, INPUT);              // Differenz Solltemperatur
  pinMode(Taster, INPUT_PULLUP);      // Taster Display einschalten
  //Display einschalten
  Sekundenablauf02 = millisekunden;
}
// Ausgabe der Sensor-Adressen
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t ia = 0; ia < 8; ia++)
  {
    if (deviceAddress[ia] < 16)
    {
      Serial.print("0"); //ist die Hex Adresse kleiner 16 dann erste Stelle eine "0"
    }
    Serial.print(deviceAddress[ia], HEX);
  }
  Serial.println();
}
//###########################################################################
//################################## LOOP ###################################
//###########################################################################
void loop()
{
  millisekunden = millis();
  //--------------------------Display Lichtkontrolle -------------------------
  Tasterstatur = digitalRead(Taster);
  if (Tasterstatur == LOW)
  {
    lcd.backlight();
    Sekundenablauf02 = millisekunden;
  }
  if (millisekunden - Sekundenablauf02 >= Pausezeit02) // Dislay Zeit abgelaufen?
  {
    lcd.noBacklight();
  }
  //--------------------------Display Licht kontrolle Ende-------------------
  //#########################################################################
  //-------------------------Daten auswerten und aufs Display----------------
  if (millisekunden - Sekundenablauf01 >= Pausezeit01) // Eine Sekunde abgelaufen?
  {
    P1 = analogRead (Poti1);
    P1 = map(P1, 0, 1023, 0, 40); // -------Solltemperatur Einstellung-------
    P2 = analogRead (Poti2);
    P2 = map(P2, 0, 1023, 0, 10); // -------Solldiffderenz Einstellung-------
    lcd.setCursor (5, 1);
    lcd.print (P1);
    lcd.print (F("  "));
    lcd.setCursor (5, 2);
    lcd.print (P2);
    lcd.print (F("  "));
    lcd.setCursor (5, 3);
    lcd.print (Solldrehzahl);
    lcd.print (F("  "));
    lcd.setCursor (14, 3);
    lcd.print (Drehzahl);
    lcd.print (F("  "));
    Sekundenablauf01 = millisekunden;
    // -------------------------Temperatur Sensoren Auswerten---------------------------
    //Temperaturen Aulesen
    sensoren.requestTemperatures();

    // Hier werden die Temp-Sensoren ausgelesen und aufs Display gebracht
    if (Sensor < 2)
    {
      Sensor ++;
      float temperatur = sensoren.getTempCByIndex(Sensor - 1);
      if (Sensor == Pool)
      {
        tempsolar = temperatur; // -----------Temperatur Messung 1------------------
      }
      if (Sensor == Solar)
      {
        temppool = temperatur - 1; // -----------Temperatur Messung 2------------------
        //--------------------------------------Temperatur aufs Display----------------
        lcd.setCursor (14, 1);
        lcd.print (temppool);
        lcd.print (F(" "));
        tempdif = (tempsolar * 10) - (temppool * 10); //---Themperatur Differenz----
        if (tempdif < 0)
        {
          tempdif = 5;
        }
        lcd.setCursor (14, 2);
        lcd.print (tempdif / 10);
        lcd.print (F(" "));
      }
    }
    // ---Alle Sensoren ausgelesen? Dann für nächste Messungen auf Null Stellen---
    if (Sensor == Anzahl_Sensoren)
    {
      Sensor = 0;
    }
  }
  //-------------------------Daten auslesen und Aufs Diplay Ende------------------
  //##############################################################################
  // ------Daten für Pumpensteuerung auswerten und an Pumpe übergeben-------------

  if (millisekunden - Sekundenablauf04 >= Pausezeit04) // 30 Sekunden abgelaufen?
  {
    /*
       Prüfen ob Solartemperatur zum Anlauf der Pumpe sinnvoll ist, obwohl noch
       keine Differenz-Temperatur vorhanden ist, da die Schläuche noch nicht mit
       Wasser gefüllt sind. Wenn genug Wärme am Dach vorhanden ist, wird Differenz
       einfach vorausgesetzt und die Pumpe angefahren. Sind dann die Schläuche
       gefüllt, ist die Differenz höher und ist kein Thema mehr.
    */
    if ((tempsolar > 28) && (tempdif < 10))
    {
      tempdif = 10;
    }
    /*
       Geht die Temperatur am dach wieder zurück und die Differenz ist immer
       noch unter ein Grad, dann wird der Anlauf wieder abgebrochen.
    */
    if ((tempsolar < 26) && (tempdif < 10))
    {
      tempdif = 0;
    }
    //-------------Solldrehzahl aus Temperaturdifferenz ermitteln--------------
    Solldrehzahl = map(tempdif, 10, 40, 150, 255);
    if (Solldrehzahl > Drehzahlmax)
    {
      Solldrehzahl = Drehzahlmax;
    }
    else
    {
      if (Solldrehzahl < Drehzahlmin)
      {
        Solldrehzahl = Drehzahlmin;
      }
    }
    // Ist gemessene tempdif gleich/größer Solldifferenz, dann Max Drehzahl
    if (tempdif >= (P2 * 10))
    {
      Solldrehzahl = Drehzahlmax;
    }
    //------------------Pumpen Ansteuerung------------------------------------
    // Gibt es keine brauchbare TemperaturDifferenz mehr, dann Pumpe auf PWM 0
    if (Anfahren == 0)
    {
      if (tempdif < 10) //---Temp.Differenz kleiner 1 Grad, dann Pumpe aus----
      {
        Solldrehzahl = 0;
      }
      // Ist aber die Wunsch-Temperatur +2 erreicht, dann keine Solar Unterstützung mehr
      if ((temppool > (P1 + 2)) && (tempdif > 20))
      {
        Solldrehzahl = 0;
      }
      // Ist Solldrehzahl erreicht ? Dann Drehzahl auf die Solldrehzahl einstellen
      if (Solldrehzahl < Sollalt)
      {
        Drehzahl = Solldrehzahl;
        Sollalt = Solldrehzahl;
      }
    }
    // Ist Solldrehzahl nicht erreicht dann Drehzahl um 10 erhöhen
    if ((Solldrehzahl > Sollalt) && (tempdif > 13))
    {
      if (Drehzahl < 120)
      {
        Drehzahl = 130;
      }
      Drehzahl = Drehzahl + 10;
      // Wenn über Max, dann die Drehzahl auf Maxdrehzahl anpassen
      if (Drehzahl > Drehzahlmax)
      {
        Drehzahl = Drehzahlmax;
      }
      Sollalt = Drehzahl;
      Anfahren = 1;
    }
    else
    {
      Anfahren = 0;
    }
    /*
      Hier wird geprüft, ob die Batterie noch genug Leistung hat.
      Ist sie schon schwach geht die pume auf weniger Leistung zurück.
      Das ist dann Drehzahl "150", also PWM Wert 150.
      Ist die Batterie schon sehr leer, geht die Drehzahl auf "0", dass
      die Batterie nicht zu tief enladen wird. Dann wird nur noch
      Leistung für die CPU benötigt.
    */
    if ((prozent <= 50) && (prozent > 0) && (tempdif > 12))
    {
      Drehzahl = 150;
    }
    if ((prozent <= 35) && (prozent > 0))
    {
      Drehzahl = 0;
    }
    /*
       Ist die Leistung der Batterie wieder im grünen Bereich und die
       TemperaturDifferenz des Wassers wieder hoch genug, ist davon
       auszugehen, dass wieder genug Sonne vorhanden ist, und somit
       die Pumpe wieder mit Vollgas betrieben werden darf.
    */
    if ((prozent > 60) && ((tempdif / 10) > P2))
    {
      Solldrehzahl = Drehzahlmax;
    }
    analogWrite(RPWM, Drehzahl); // PWM für Pumpe Vorwärts
    analogWrite(LPWM, 0); //Hier muss immer "0" sein, weil Rückwärts nicht gut ist
    Sekundenablauf04 = millisekunden;
  }
  //------------------------Pumpensteuerung Ende-------------------------------
  //###########################################################################
  // ------------------------Serial Print Ausgabe------------------------------
  if (millisekunden - Sekundenablauf03 >= Pausezeit03) // Serial Ausgabezeit abgelaufen?
  {
    /*
      Serial.println(F("---------------------------------"));
      Serial.print(F("Drehzahl Pumpe = "));
      Serial.print(Drehzahl);
      Serial.print(F("  soll = "));
      Serial.println(Solldrehzahl);
      Serial.print(F("Temp Pool = "));
      Serial.println(temppool);
      Serial.print(F("Temp Solar = "));
      Serial.println(tempsolar);
      Serial.print(F("Tempdif = "));
      Serial.print(tempsolar - temppool);
      Serial.print(F("  Soldif = "));
      Serial.println(P2);
      Serial.println(F("---------------------------------"));
      Serial.print(F("Panel "));
      Serial.print(pvv);
      Serial.print(F("V  "));
      Serial.print(pva);
      Serial.print (F("A  "));
      Serial.print(pvwat);
      Serial.println(F("W"));
      Serial.print(F("Akku  "));
      Serial.print(akkuVolt);
      Serial.print (F("V  "));
      Serial.print(akkuAmpere);
      Serial.print(F("A  "));
      Serial.print(prozent);
      Serial.println (F("%"));
      Serial.println (F("---------------------------------"));
    */
    Sekundenablauf03 = millisekunden;
  }
  //-------------------------Seriale Ausgabe Ende-----------------------------
  //##########################################################################
  //-------------------------------MPPT LOOP----------------------------------
  currentMillis = millis();
  if (currentMillis - previousMillis >= intervall)
  {
    previousMillis = currentMillis; // Zeitpunkt der letzten Schaltung wird festgehalten
    // Read 16 registers beginn mit Adresse  0x3100)
    uint8_t result;
    result = node.readInputRegisters(0x3100, 16);
    if (result == node.ku8MBSuccess)
    { //PV Daten
      pvv = node.getResponseBuffer(0x00) / 100.0f; //Tracer PV Volt
      pva = node.getResponseBuffer(0x01) / 100.0f;//PV Ampere
      //PV Leistung
      pvwat = ((node.getResponseBuffer(0x06) +  node.getResponseBuffer(0x07) ) / 100.0f);
      /*****  Akkustand Anzeigen  *****/
      akkuVolt = node.getResponseBuffer(0x04) / 100.0f; //Tracer Akku Volt
      akkuAmpere = node.getResponseBuffer(0x05) / 100.0f;//Akku Ladedaten in Ampere
    }
    result = node.readInputRegisters(0x311A , 1);//Akkukapazität in Prozent
    if (result == node.ku8MBSuccess) {
      prozent = node.getResponseBuffer(0x00);
    }
    lcd.setCursor (0, 0);
    lcd.print(akkuVolt);
    lcd.print (F("V  "));
    lcd.print(akkuAmpere);
    lcd.print (F("A  "));
    lcd.print(prozent);
    lcd.print (F("%  "));
    lcd.setCursor (0, 2);
    lcd.print (F("Soll"));
  }
  //-----------------------------MPPT LOOP Ende-------------------------------
  //##########################################################################
}
Benutzeravatar
Admin
Administrator
Beiträge: 1199
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Admin »

Ich habe mich entschlossen, noch eine Funktion nachzurüßten. Ich möchte die Stomaufnahme der Pumpe ein wenig im Blick behalten. Es kann sein dass die Pumpe wegen einem Defekt blockiert und dann eine erheblich höhere Stromaufnahme hat, obwohl sie gar nicht mehr arbeitet. Das möchte ich mit einer Erweiterung abfangen. Ich habe dafür schon mal die Schaltung meiner Steuerung erweitert und diese Erweiterung auch schon in der Schaltung eingezeichnet. Deshalb hier der neue Schaltplan. Da der Motortreiber eine Stromkontrolle schon vorgesehen hat, ist es keine große Sache. Vom Pin "R_IS" des Motortreibers auf einen Spannungsteiler vor dem Arduino Pin "A2". Das Programm ist noch nicht ganz fertig, aber kommt Heute oder Morgen nach.
.
Solar_Pool_Heizung_V03_MPPT.JPG
Solar_Pool_Heizung_V03_MPPT.JPG (499.47 KiB) 418 mal betrachtet
Hier habe ich mal die erste Programm-Version mit der Strombegrenzung. Da kann man unter "Stromgrenze" den Maximal Strom einstellen, wo die Streuerung ausschalten soll. Ich habe die Stromgrenze im Moment auf "4" Amperer stehen, weil ich das am Tisch mit einem kleinen Motor getestet habe, den ich einfach nur mit der Hand aufgehalten habe. Bei meiner Solar-Pumpe im Pool müßte ich wohl so etwa auf 6 Ampere gehen. Das muss ich die Tage noch testen. So niedrig wie möglich, aber hoch genug, dass im Normalbetrieb keinesfalls ausgelöst wird.

Code: Alles auswählen

/*
   Arduino Pool_Solarheizung_Pumpensteuerung mit MPPT Kontrolle
   V0.2 ist Erweiterung vom 09.08.23 Strommessung am Motor
*/
#include <OneWire.h>
#include <DallasTemperature.h>
#include "Wire.h"
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
//###########################################################################
//-------------------------------------MPPT Regler Deklaration---------------
/*************************************
   Für Uno wird SoftwareSerial benutzt
**************************************/
#include <SoftwareSerial.h>
SoftwareSerial tracerSerial(9, 8); // RO, DI  Pins drehen wenn nicht funktioniert
/**********************************************
    Ich verwende  einen MAX485-kompatiblen RS485-Transceiver.
  Rx/Tx ist mit der seriellen Schnittstelle der Hardware an "Serial" verbunden.
  Die Pins "Data Enable" und "Rec3eiver Enable" sind wie folgt beschaltet:
 ********************************************************/
#include <ModbusMaster.h>

#define MAX485_DE      7 // DE und RE dürfen am einen Pin hängen 
#define MAX485_RE_NEG  7

// instantiate ModbusMaster object
ModbusMaster node;

int prozent = 0;
float akkuVolt = 0;
float akkuAmpere = 0;
float pvwat = 0;
float pva = 0;
float pvv = 0;
unsigned long currentMillis = 0;

void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}
unsigned long previousMillis = 0;
const long intervall = 60000;// Daten werden alle 60 Sek ausgelesen
//------------------------------------MPPT Regler Deklaration Ende-----------
//###########################################################################
//-----Motortreiber----
const byte RPWM = 10;
const byte LPWM = 11;
//-------Potis---------
const byte Poti1 = A0;
const byte Poti2 = A1;
const byte R_Amp = A2;
//-------Taster--------
byte Tasterstatur = 0;
const byte Taster = 4;// Display einschalten !!
//-------Merker--------
byte Pumpe = 1;
int P1 = 0;
int P2 = 0;
byte Pool = 1; // Hier 1 oder 2 tauschen mit Solar, wenn Sensoren vertauscht
byte Solar = 2; // Hier 1 oder 2 tauschen mit Pool, wenn Sensoren vertauscht
int Drehzahl = 0;
int Solldrehzahl = 0;
int Sollalt = 10;
byte Anfahren = 0;
int Drehzahlmin = 150;
int Drehzahlmax = 255;
float Motorstrom = 0;
byte Stromgrenze = 4;
unsigned long millisekunden = 0;
//-------------------------------Zeiten---------------------------------------
unsigned long Sekundenablauf01 = 0;      // Messung Potis und Ausgabe Display
const unsigned long Pausezeit01 = 1000;
//------------------------------------------------------------------------------
unsigned long Sekundenablauf02 = 0;      // Display nach Zeit ausschalten
const unsigned long Pausezeit02 = 60000 * 15;
//------------------------------------------------------------------------------
unsigned long Sekundenablauf03 = 0;      //Serial Werte Ausgabezeit
const unsigned long Pausezeit03 = 60000 * 5;
//------------------------------------------------------------------------------
unsigned long Sekundenablauf04 = 0;      // Werte für Pumpe und Pumpe ansteuern
const unsigned long Pausezeit04 = 60000; //Alle 30 Sekunden Daten für Pumpe
//------------------------------------------------------------------------------
#define One_Wire_Bus 2  // Sensor auf Pin 2
OneWire oneWire(One_Wire_Bus);
DallasTemperature sensoren (&oneWire);
int Anzahl_Sensoren = 0;
int is = 0; // Zähler für die Sensoren
int ia = 0; // Zähler für die Adressstellen 0-7
int Sensor = 0;
float temppool = 0;
float tempsolar = 0;
float tempdif = 0;
DeviceAddress tempDeviceAddress; // Für die Adressausgabe
int numberOfDevices; // Für die Adressausgabe
//##########################################################################
//################################  Setup ##################################
//##########################################################################
void setup() {
  Wire.begin();
  sensoren.begin();
  Serial.begin(9600);
  lcd.begin();
  lcd.backlight();
  //##########################################################################
  //-----------------------------------MPPT Setup-----------------------------
  tracerSerial.begin(115200); // Modbus Kommunikation mit 115200 Baud
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  digitalWrite(MAX485_RE_NEG, 0);// Init in receive mode
  digitalWrite(MAX485_DE, 0);
  // Tracer xxxxAN Modbus slave ID 1
  node.begin(1, tracerSerial);  // Begin der Verbindung mit Tracer
  // Rückrufe ermöglichen es uns, den RS485-Transceiver korrekt zu konfigurieren
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  //-------------------------------MPPT Setup Ende--------------------------
  //##########################################################################
  lcd.setCursor (0, 1);
  lcd.print (F("Soll"));
  lcd.setCursor (10, 1);
  lcd.print (F("Ist"));
  lcd.setCursor (0, 2);
  lcd.print (F("Soll"));
  lcd.setCursor (10, 2);
  lcd.print (F("Ist"));
  lcd.setCursor (0, 3);
  lcd.print (F("Soll      Ist"));
  // Anzahl der Sesoren ermitteln-------------------------------------
  Anzahl_Sensoren = sensoren.getDeviceCount();
  // Ermitteln der Sensor-Adressen------------------------------------
  for (is = 0; is < Anzahl_Sensoren; is++)
  {
    if (sensoren.getAddress(tempDeviceAddress, is))
    {
      Serial.println ();
      printAddress(tempDeviceAddress);
    }
  }
  //-----------Aus-/Eingänge einrichten-------------------------------------
  pinMode(RPWM, OUTPUT);              // PWM rechts Pumpensteuerung
  pinMode(LPWM, OUTPUT);              // PWM links Pumpensteuerung
  pinMode(Poti1, INPUT);              // Pool Solltemperatur
  pinMode(Poti2, INPUT);              // Differenz Solltemperatur
  pinMode(R_Amp, INPUT);              // Strommessung Motor
  pinMode(Taster, INPUT_PULLUP);      // Taster Display einschalten
  //Display einschalten
  Sekundenablauf02 = millisekunden;
}
// Ausgabe der Sensor-Adressen
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t ia = 0; ia < 8; ia++)
  {
    if (deviceAddress[ia] < 16)
    {
      Serial.print("0"); //ist die Hex Adresse kleiner 16 dann erste Stelle eine "0"
    }
    Serial.print(deviceAddress[ia], HEX);
  }
  Serial.println();
}
//###########################################################################
//################################## LOOP ###################################
//###########################################################################
void loop()
{
  millisekunden = millis();
  //----------------------- Motorstrom auf überlasst prüfen --------------------
  /*
    Wenn Pumpe auf "0" geht, kann man die Pumpe nur durch Programmneustart
    wieder einschalten, weil die Pumpe offenbar blockiert und dadurch zuviel
    Strom braucht.
  */
  Motorstrom = analogRead (R_Amp);
  Motorstrom = (Motorstrom * 4) / 800;
  if (Motorstrom > Stromgrenze)
  {
    Serial.print(F("Motorstrom "));
    Serial.print(Motorstrom);
    Serial.print(F(" Ampere"));
    Serial.print(F("  Drehzahl "));
    Serial.println(Drehzahl);
    Pumpe = 0;
    Drehzahl = 0;
    analogWrite(RPWM, Drehzahl); // Pumpe Notaus
  }
  //--------------------------Display Lichtkontrolle -------------------------
  Tasterstatur = digitalRead(Taster);
  if (Tasterstatur == LOW)
  {
    lcd.backlight();
    Sekundenablauf02 = millisekunden;
  }
  if (millisekunden - Sekundenablauf02 >= Pausezeit02) // Dislay Zeit abgelaufen?
  {
    lcd.noBacklight();
  }
  //--------------------------Display Licht kontrolle Ende-------------------
  //#########################################################################
  //-------------------------Daten auswerten und aufs Display----------------
  if (millisekunden - Sekundenablauf01 >= Pausezeit01) // Eine Sekunde abgelaufen?
  {
    P1 = analogRead (Poti1);
    P1 = map(P1, 0, 1023, 0, 40); // -------Solltemperatur Einstellung-------
    P2 = analogRead (Poti2);
    P2 = map(P2, 0, 1023, 0, 10); // -------Solldiffderenz Einstellung-------
    lcd.setCursor (5, 1);
    lcd.print (P1);
    lcd.print (F("  "));
    lcd.setCursor (5, 2);
    lcd.print (P2);
    lcd.print (F("  "));
    lcd.setCursor (5, 3);
    lcd.print (Solldrehzahl);
    lcd.print (F("  "));
    lcd.setCursor (14, 3);
    lcd.print (Drehzahl);
    lcd.print (F("  "));
    Sekundenablauf01 = millisekunden;
    // -------------------------Temperatur Sensoren Auswerten---------------------------
    //Temperaturen Aulesen
    sensoren.requestTemperatures();

    // Hier werden die Temp-Sensoren ausgelesen und aufs Display gebracht
    if (Sensor < 2)
    {
      Sensor ++;
      float temperatur = sensoren.getTempCByIndex(Sensor - 1);
      if (Sensor == Pool)
      {
        tempsolar = temperatur; // -----------Temperatur Messung 1------------------
      }
      if (Sensor == Solar)
      {
        temppool = temperatur - 1; // -----------Temperatur Messung 2------------------
        //--------------------------------------Temperatur aufs Display----------------
        lcd.setCursor (14, 1);
        lcd.print (temppool);
        lcd.print (F(" "));
        tempdif = (tempsolar * 10) - (temppool * 10); //---Themperatur Differenz----
        if (tempdif < 0)
        {
          tempdif = 5;
        }
        lcd.setCursor (14, 2);
        lcd.print (tempdif / 10);
        lcd.print (F(" "));
      }
    }
    // ---Alle Sensoren ausgelesen? Dann für nächste Messungen auf Null Stellen---
    if (Sensor == Anzahl_Sensoren)
    {
      Sensor = 0;
    }
  }
  //-------------------------Daten auslesen und Aufs Diplay Ende------------------
  //##############################################################################
  // ------Daten für Pumpensteuerung auswerten und an Pumpe übergeben-------------

  if (millisekunden - Sekundenablauf04 >= Pausezeit04) // 30 Sekunden abgelaufen?
  {
    /*
       Prüfen ob Solartemperatur zum Anlauf der Pumpe sinnvoll ist, obwohl noch
       keine Differenz-Temperatur vorhanden ist, da die Schläuche noch nicht mit
       Wasser gefüllt sind. Wenn genug Wärme am Dach vorhanden ist, wird Differenz
       einfach vorausgesetzt und die Pumpe angefahren. Sind dann die Schläuche
       gefüllt, ist die Differenz höher und ist kein Thema mehr.
    */
    if ((tempsolar > 28) && (tempdif < 10))
    {
      tempdif = 10;
    }
    /*
       Geht die Temperatur am dach wieder zurück und die Differenz ist immer
       noch unter ein Grad, dann wird der Anlauf wieder abgebrochen.
    */
    if ((tempsolar < 26) && (tempdif < 10))
    {
      tempdif = 0;
    }
    //-------------Solldrehzahl aus Temperaturdifferenz ermitteln--------------
    Solldrehzahl = map(tempdif, 10, 40, 150, 255);
    if (Solldrehzahl > Drehzahlmax)
    {
      Solldrehzahl = Drehzahlmax;
    }
    else
    {
      if (Solldrehzahl < Drehzahlmin)
      {
        Solldrehzahl = Drehzahlmin;
      }
    }
    // Ist gemessene tempdif gleich/größer Solldifferenz, dann Max Drehzahl
    if (tempdif >= (P2 * 10))
    {
      Solldrehzahl = Drehzahlmax;
    }
    //------------------Pumpen Ansteuerung------------------------------------
    // Gibt es keine brauchbare TemperaturDifferenz mehr, dann Pumpe auf PWM 0
    if (Anfahren == 0)
    {
      if (tempdif < 10) //---Temp.Differenz kleiner 1 Grad, dann Pumpe aus----
      {
        Solldrehzahl = 0;
      }
      // Ist aber die Wunsch-Temperatur +2 erreicht, dann keine Solar Unterstützung mehr
      if ((temppool > (P1 + 2)) && (tempdif > 20))
      {
        Solldrehzahl = 0;
      }
      // Ist Solldrehzahl erreicht ? Dann Drehzahl auf die Solldrehzahl einstellen
      if (Solldrehzahl < Sollalt)
      {
        Drehzahl = Solldrehzahl;
        Sollalt = Solldrehzahl;
      }
    }
    // Ist Solldrehzahl nicht erreicht dann Drehzahl um 10 erhöhen
    if ((Solldrehzahl > Sollalt) && (tempdif > 13))
    {
      if (Drehzahl < 120)
      {
        Drehzahl = 130;
      }
      Drehzahl = Drehzahl + 20;
      // Wenn über Max, dann die Drehzahl auf Maxdrehzahl anpassen
      if (Drehzahl > Drehzahlmax)
      {
        Drehzahl = Drehzahlmax;
      }
      Sollalt = Drehzahl;
      Anfahren = 1;
    }
    else
    {
      Anfahren = 0;
    }
    /*
      Hier wird geprüft, ob die Batterie noch genug Leistung hat.
      Ist sie schon schwach geht die pume auf weniger Leistung zurück.
      Das ist dann Drehzahl "150", also PWM Wert 150.
      Ist die Batterie schon sehr leer, geht die Drehzahl auf "0", dass
      die Batterie nicht zu tief enladen wird. Dann wird nur noch
      Leistung für die CPU benötigt.
    */
    if ((prozent <= 50) && (prozent > 0) && (tempdif > 12))
    {
      Drehzahl = 150;
    }
    if ((prozent <= 35) && (prozent > 0))
    {
      Drehzahl = 0;
    }
    /*
       Ist die Leistung der Batterie wieder im grünen Bereich und die
       TemperaturDifferenz des Wassers wieder hoch genug, ist davon
       auszugehen, dass wieder genug Sonne vorhanden ist, und somit
       die Pumpe wieder mit Vollgas betrieben werden darf.
    */
    if ((prozent > 60) && ((tempdif / 10) > P2))
    {
      Solldrehzahl = Drehzahlmax;
    }
    if (Pumpe == 1)
    {
      analogWrite(RPWM, Drehzahl); // PWM für Pumpe Vorwärts
      analogWrite(LPWM, 0); //Hier muss immer "0" sein, weil Rückwärts nicht gut ist
    }
    Sekundenablauf04 = millisekunden;
  }
  //------------------------Pumpensteuerung Ende-------------------------------
  //###########################################################################
  // ------------------------Serial Print Ausgabe------------------------------
  if (millisekunden - Sekundenablauf03 >= Pausezeit03) // Serial Ausgabezeit abgelaufen?
  {
    /*
      Serial.println(F("---------------------------------"));
      Serial.print(F("Drehzahl Pumpe = "));
      Serial.print(Drehzahl);
      Serial.print(F("  soll = "));
      Serial.println(Solldrehzahl);
      Serial.print(F("Temp Pool = "));
      Serial.println(temppool);
      Serial.print(F("Temp Solar = "));
      Serial.println(tempsolar);
      Serial.print(F("Tempdif = "));
      Serial.print(tempsolar - temppool);
      Serial.print(F("  Soldif = "));
      Serial.println(P2);
      Serial.println(F("---------------------------------"));
      Serial.print(F("Panel "));
      Serial.print(pvv);
      Serial.print(F("V  "));
      Serial.print(pva);
      Serial.print (F("A  "));
      Serial.print(pvwat);
      Serial.println(F("W"));
      Serial.print(F("Akku  "));
      Serial.print(akkuVolt);
      Serial.print (F("V  "));
      Serial.print(akkuAmpere);
      Serial.print(F("A  "));
      Serial.print(prozent);
      Serial.println (F("%"));
      Serial.println (F("---------------------------------"));
    */

    Sekundenablauf03 = millisekunden;
  }
  //-------------------------Seriale Ausgabe Ende-----------------------------
  //##########################################################################
  //-------------------------------MPPT LOOP----------------------------------
  currentMillis = millis();
  if (currentMillis - previousMillis >= intervall)
  {
    previousMillis = currentMillis; // Zeitpunkt der letzten Schaltung wird festgehalten
    // Read 16 registers beginn mit Adresse  0x3100)
    uint8_t result;
    result = node.readInputRegisters(0x3100, 16);
    if (result == node.ku8MBSuccess)
    { //PV Daten
      pvv = node.getResponseBuffer(0x00) / 100.0f; //Tracer PV Volt
      pva = node.getResponseBuffer(0x01) / 100.0f;//PV Ampere
      //PV Leistung
      pvwat = ((node.getResponseBuffer(0x06) +  node.getResponseBuffer(0x07) ) / 100.0f);
      /*****  Akkustand Anzeigen  *****/
      akkuVolt = node.getResponseBuffer(0x04) / 100.0f; //Tracer Akku Volt
      akkuAmpere = node.getResponseBuffer(0x05) / 100.0f;//Akku Ladedaten in Ampere
    }
    result = node.readInputRegisters(0x311A , 1);//Akkukapazität in Prozent
    if (result == node.ku8MBSuccess) {
      prozent = node.getResponseBuffer(0x00);
    }
    lcd.setCursor (0, 0);
    lcd.print(akkuVolt);
    lcd.print (F("V  "));
    lcd.print(akkuAmpere);
    lcd.print (F("A  "));
    lcd.print(prozent);
    lcd.print (F("%  "));
    lcd.setCursor (0, 2);
    lcd.print (F("Soll"));
  }
  //-----------------------------MPPT LOOP Ende-------------------------------
  //##########################################################################
}
Benutzeravatar
Admin
Administrator
Beiträge: 1199
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Poolwasser mit der Sonne aufheizen.

Beitrag von Admin »

Gestern habe ich bei meinem Programm noch eine Kleinigkeit geändert. Die Sonne ist schon wieder wesentlich tiefer als am Anfang meiner Tests. und meine Sensoren für Poolwasser- und Solarwasser-Temperatur bekommen noch keine Sonne ab, obwohl die Solarwassertaschen schon teilweise Sonne haben. Da ich ja auch die Daten vom MPPT Solar Laderegler habe, nehme ich jetzt zusätzlich die Panelspannung für die Auswertung. Mit meinen beiden Panels habe ich bei 36 Volt (2x18 Volt) genug Leistung um die Pumpe anzufahren und sehe aus dem Wert auch, dass genug Sonne da ist, um das Wasser am Dach zu erhitzen. Also lasse ich die Pumpe bei größer 36 Volt am Panel und Solartemperatur größer 22 Grad starten. So war sie heute um 9:00 Uhr bereits am laufen und es sind schon 6,5 Grad Temp. Differenz zwischen Poolwasser und Solarwasser gewesen. Gestern hat die Steuerung erst nach 11:00 Uhr die Pumpe gestartet, weil erst da der Temperaturfühler am Dach in der Sonne war. Dann startete die Pumpe und die Differenz war zu Beginn schon 22 Grad, weil die Solar Wassertaschen schon von der Sonne total heiß waren. :(o): :(o): Da ist also durch den 2 Std. späteren Start, sehr viel Wärme nicht genutzt worden. Die zusätzliche Abhängikkeit von "Tempsolar" größer 22 Grad ist zur Sicherheit, falls es zu kalt ist. Nicht dass der gegeneffekt eintritt, weil es zwar Sonnig ist, aber Saukalt. :(o):

Franz

PS: Das Programm ist aktuell dieses hier:

Code: Alles auswählen

/*
   Arduino Pool_Solarheizung_Pumpensteuerung mit MPPT Kontrolle
   V0.2 ist Erweiterung vom 09.08.23 Strommessung am Motor
*/
#include <OneWire.h>
#include <DallasTemperature.h>
#include "Wire.h"
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
//###########################################################################
//-------------------------------------MPPT Regler Deklaration---------------
/*************************************
   Für Uno wird SoftwareSerial benutzt
**************************************/
#include <SoftwareSerial.h>
SoftwareSerial tracerSerial(9, 8); // RO, DI  Pins drehen wenn nicht funktioniert
/**********************************************
    Ich verwende  einen MAX485-kompatiblen RS485-Transceiver.
  Rx/Tx ist mit der seriellen Schnittstelle der Hardware an "Serial" verbunden.
  Die Pins "Data Enable" und "Rec3eiver Enable" sind wie folgt beschaltet:
 ********************************************************/
#include <ModbusMaster.h>

#define MAX485_DE      7 // DE und RE dürfen am einen Pin hängen 
#define MAX485_RE_NEG  7

// instantiate ModbusMaster object
ModbusMaster node;

int prozent = 0;
float akkuVolt = 0;
float akkuAmpere = 0;
float pvwat = 0;
float pva = 0;
float pvv = 0;
unsigned long currentMillis = 0;

void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}
unsigned long previousMillis = 0;
const long intervall = 60000;// Daten werden alle 60 Sek ausgelesen
//------------------------------------MPPT Regler Deklaration Ende-----------
//###########################################################################
//-----Motortreiber----
const byte RPWM = 10;
const byte LPWM = 11;
//-------Potis---------
const byte Poti1 = A0;
const byte Poti2 = A1;
const byte R_Amp = A2;
//-------Taster--------
byte Tasterstatur = 0;
const byte Taster = 4;// Display einschalten !!
//-------Merker--------
byte Pumpe = 1;
int P1 = 0;
int P2 = 0;
// Derzeit Pool=1 und Solar=2
byte Pool = 1; // Hier 1 oder 2 tauschen mit Solar, wenn Sensoren vertauscht
byte Solar = 2; // Hier 1 oder 2 tauschen mit Pool, wenn Sensoren vertauscht
int Drehzahl = 0;
int Solldrehzahl = 0;
int Sollalt = 10;
byte Anfahren = 0;
int Drehzahlmin = 150;
int Drehzahlmax = 255;
float Motorstrom = 0;
byte Stromgrenze = 10;
unsigned long millisekunden = 0;
//-------------------------------Zeiten---------------------------------------
unsigned long Sekundenablauf01 = 0;      // Messung Potis und Ausgabe Display
const unsigned long Pausezeit01 = 1000;
//------------------------------------------------------------------------------
unsigned long Sekundenablauf02 = 0;      // Display nach Zeit ausschalten
const unsigned long Pausezeit02 = 60000 * 15;
//------------------------------------------------------------------------------
unsigned long Sekundenablauf03 = 0;      //Serial Werte Ausgabezeit
const unsigned long Pausezeit03 = 60000;
//------------------------------------------------------------------------------
unsigned long Sekundenablauf04 = 0;      // Werte für Pumpe und Pumpe ansteuern
const unsigned long Pausezeit04 = 60000; //Alle 60 Sekunden Daten für Pumpe
//------------------------------------------------------------------------------
#define One_Wire_Bus 2  // Sensor auf Pin 2
OneWire oneWire(One_Wire_Bus);
DallasTemperature sensoren (&oneWire);
int Anzahl_Sensoren = 0;
int is = 0; // Zähler für die Sensoren
int ia = 0; // Zähler für die Adressstellen 0-7
int Sensor = 0;
float temppool = 0;
float tempsolar = 0;
float tempdif = 0;
DeviceAddress tempDeviceAddress; // Für die Adressausgabe
int numberOfDevices; // Für die Adressausgabe
//##########################################################################
//################################  Setup ##################################
//##########################################################################
void setup() {
  Wire.begin();
  sensoren.begin();
  Serial.begin(9600);
  lcd.begin();
  lcd.backlight();
  //##########################################################################
  //-----------------------------------MPPT Setup-----------------------------
  tracerSerial.begin(115200); // Modbus Kommunikation mit 115200 Baud
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  digitalWrite(MAX485_RE_NEG, 0);// Init in receive mode
  digitalWrite(MAX485_DE, 0);
  // Tracer xxxxAN Modbus slave ID 1
  node.begin(1, tracerSerial);  // Begin der Verbindung mit Tracer
  // Rückrufe ermöglichen es uns, den RS485-Transceiver korrekt zu konfigurieren
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  //-------------------------------MPPT Setup Ende--------------------------
  //##########################################################################
  lcd.setCursor (0, 1);
  lcd.print (F("Soll"));
  lcd.setCursor (10, 1);
  lcd.print (F("Ist"));
  lcd.setCursor (0, 2);
  lcd.print (F("Soll"));
  lcd.setCursor (10, 2);
  lcd.print (F("Ist"));
  lcd.setCursor (0, 3);
  lcd.print (F("Soll      Ist"));
  // Anzahl der Sesoren ermitteln-------------------------------------
  Anzahl_Sensoren = sensoren.getDeviceCount();
  // Ermitteln der Sensor-Adressen------------------------------------
  for (is = 0; is < Anzahl_Sensoren; is++)
  {
    if (sensoren.getAddress(tempDeviceAddress, is))
    {
      Serial.println ();
      printAddress(tempDeviceAddress);
    }
  }
  //-----------Aus-/Eingänge einrichten-------------------------------------
  pinMode(RPWM, OUTPUT);              // PWM rechts Pumpensteuerung
  pinMode(LPWM, OUTPUT);              // PWM links Pumpensteuerung
  pinMode(Poti1, INPUT);              // Pool Solltemperatur
  pinMode(Poti2, INPUT);              // Differenz Solltemperatur
  pinMode(R_Amp, INPUT);              // Strommessung Motor
  pinMode(Taster, INPUT_PULLUP);      // Taster Display einschalten
  //Display einschalten
  Sekundenablauf02 = millisekunden;
}
// Ausgabe der Sensor-Adressen
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t ia = 0; ia < 8; ia++)
  {
    if (deviceAddress[ia] < 16)
    {
      Serial.print("0"); //ist die Hex Adresse kleiner 16 dann erste Stelle eine "0"
    }
    Serial.print(deviceAddress[ia], HEX);
  }
  Serial.println();
}
//###########################################################################
//################################## LOOP ###################################
//###########################################################################
void loop()
{
  millisekunden = millis();
  //----------------------- Motorstrom auf überlasst prüfen --------------------
  /*
    Wenn Pumpe auf "0" geht, kann man die Pumpe nur durch Programmneustart
    wieder einschalten, weil die Pumpe offenbar blockiert und dadurch zuviel
    Strom braucht.
  */
  Motorstrom = analogRead (R_Amp);
  Motorstrom = (Motorstrom * 4) / 320;
  if (Motorstrom > Stromgrenze)
  {
    Serial.println(F("#############################################"));
    Serial.print(F("Motorstrom "));
    Serial.print(Motorstrom);
    Serial.print(F(" Ampere"));
    Serial.print(F("  Drehzahl "));
    Serial.println(Drehzahl);
    Serial.println(F("#############################################"));
    Pumpe = 0;
    Drehzahl = 0;
    analogWrite(RPWM, Drehzahl); // Pumpe Notaus
  }
  //--------------------------Display Lichtkontrolle -------------------------
  Tasterstatur = digitalRead(Taster);
  if (Tasterstatur == LOW)
  {
    lcd.backlight();
    Sekundenablauf02 = millisekunden;
  }
  if (millisekunden - Sekundenablauf02 >= Pausezeit02) // Dislay Zeit abgelaufen?
  {
    lcd.noBacklight();
  }
  //--------------------------Display Licht kontrolle Ende-------------------
  //#########################################################################
  //-------------------------Daten auswerten und aufs Display----------------
  if (millisekunden - Sekundenablauf01 >= Pausezeit01) // Eine Sekunde abgelaufen?
  {
    P1 = analogRead (Poti1);
    P1 = map(P1, 0, 1023, 0, 40); // -------Solltemperatur Einstellung-------
    P2 = analogRead (Poti2);
    P2 = map(P2, 0, 1023, 0, 10); // -------Solldiffderenz Einstellung-------
    lcd.setCursor (5, 1);
    lcd.print (P1);
    lcd.print (F("  "));
    lcd.setCursor (5, 2);
    lcd.print (P2);
    lcd.print (F("  "));
    lcd.setCursor (5, 3);
    lcd.print (Solldrehzahl);
    lcd.print (F("  "));
    lcd.setCursor (14, 3);
    lcd.print (Drehzahl);
    lcd.print (F("  "));
    Sekundenablauf01 = millisekunden;
    // -------------------------Temperatur Sensoren Auswerten---------------------------
    //Temperaturen Aulesen
    sensoren.requestTemperatures();

    // Hier werden die Temp-Sensoren ausgelesen und aufs Display gebracht
    if (Sensor < 2)
    {
      Sensor ++;
      float temperatur = sensoren.getTempCByIndex(Sensor - 1);
      if (Sensor == Pool)
      {
        tempsolar = temperatur + 1; // -----------Temperatur Messung 1------------------
      }
      if (Sensor == Solar)
      {
        temppool = temperatur - 1; // -----------Temperatur Messung 2------------------
        //--------------------------------------Temperatur aufs Display----------------
        lcd.setCursor (14, 1);
        lcd.print (temppool);
        lcd.print (F(" "));
        tempdif = (tempsolar * 10) - (temppool * 10); //---Themperatur Differenz----
        if (tempdif < 0)
        {
          tempdif = 5;
        }
        lcd.setCursor (14, 2);
        lcd.print (tempdif / 10);
        lcd.print (F(" "));
      }
    }
    // ---Alle Sensoren ausgelesen? Dann für nächste Messungen auf Null Stellen---
    if (Sensor == Anzahl_Sensoren)
    {
      Sensor = 0;
    }
  }
  //-------------------------Daten auslesen und Aufs Diplay Ende------------------
  //##############################################################################
  // ------Daten für Pumpensteuerung auswerten und an Pumpe übergeben-------------

  if (millisekunden - Sekundenablauf04 >= Pausezeit04) // 30 Sekunden abgelaufen?
  {
    /*
       Prüfen ob Solartemperatur zum Anlauf der Pumpe sinnvoll ist, obwohl noch
       keine Differenz-Temperatur vorhanden ist, da die Schläuche noch nicht mit
       Wasser gefüllt sind. Wenn genug Wärme am Dach vorhanden ist, wird Differenz
       einfach vorausgesetzt und die Pumpe angefahren. Sind dann die Schläuche
       gefüllt, ist die Differenz höher und ist kein Thema mehr.
    */
    if ((tempsolar > 27) && (tempdif < 10))
    {
      tempdif = 10;
      Drehzahl = 150;
    }
    if ((pvv > 36) && (tempdif < 10)&&(tempsolar > 22))
    {
      tempdif = 10;
      Drehzahl = 150;
    }
    /*
       Geht die Temperatur am dach wieder zurück und die Differenz ist immer
       noch unter ein Grad, dann wird der Anlauf wieder abgebrochen.
    */
    if ((tempsolar < 25) && (tempdif < 10))
    {
      tempdif = 0;
    }
    //-------------Solldrehzahl aus Temperaturdifferenz ermitteln--------------
    Solldrehzahl = map(tempdif, 10, 40, 150, 255);
    if (Solldrehzahl > Drehzahlmax)
    {
      Solldrehzahl = Drehzahlmax;
    }
    else
    {
      if (Solldrehzahl < Drehzahlmin)
      {
        Solldrehzahl = Drehzahlmin;
      }
    }
    // Ist gemessene tempdif gleich/größer Solldifferenz, dann Max Drehzahl
    if (tempdif >= (P2 * 10))
    {
      Solldrehzahl = Drehzahlmax;
    }
    //------------------Pumpen Ansteuerung------------------------------------
    // Gibt es keine brauchbare TemperaturDifferenz mehr, dann Pumpe auf PWM 0
    if (Anfahren == 0)
    {
      if (tempdif < 10) //---Temp.Differenz kleiner 1 Grad, dann Pumpe aus----
      {
        Solldrehzahl = 0;
      }
      // Ist aber die Wunsch-Temperatur +2 erreicht, dann keine Solar Unterstützung mehr
      if ((temppool > (P1 + 2)) && (tempdif > 20))
      {
        Solldrehzahl = 0;
      }
      // Ist Solldrehzahl erreicht ? Dann Drehzahl auf die Solldrehzahl einstellen
      if (Solldrehzahl < Sollalt)
      {
        Drehzahl = Solldrehzahl;
        Sollalt = Solldrehzahl;
      }
    }
    // Ist Solldrehzahl nicht erreicht dann Drehzahl um 10 erhöhen
    if ((Solldrehzahl > Sollalt) && (tempdif > 13))
    {
      if (Drehzahl < 120)
      {
        Drehzahl = 130;
      }
      Drehzahl = Drehzahl + 20;
      // Wenn über Max, dann die Drehzahl auf Maxdrehzahl anpassen
      if (Drehzahl > Drehzahlmax)
      {
        Drehzahl = Drehzahlmax;
      }
      Sollalt = Drehzahl;
      Anfahren = 1;
    }
    else
    {
      Anfahren = 0;
    }
    /*
      Hier wird geprüft, ob die Batterie noch genug Leistung hat.
      Ist sie schon schwach geht die pume auf weniger Leistung zurück.
      Das ist dann Drehzahl "150", also PWM Wert 150.
      Ist die Batterie schon sehr leer, geht die Drehzahl auf "0", dass
      die Batterie nicht zu tief enladen wird. Dann wird nur noch
      Leistung für die CPU benötigt.
    */
    if ((prozent <= 50) && (prozent > 0) && (tempdif > 12))
    {
      Drehzahl = 150;
    }
    if ((prozent <= 35) && (prozent > 0))
    {
      Drehzahl = 0;
    }
    /*
       Ist die Leistung der Batterie wieder im grünen Bereich und die
       TemperaturDifferenz des Wassers wieder hoch genug, ist davon
       auszugehen, dass wieder genug Sonne vorhanden ist, und somit
       die Pumpe wieder mit Vollgas betrieben werden darf.
    */
    if ((prozent > 60) && ((tempdif / 10) > P2))
    {
      Solldrehzahl = Drehzahlmax;
    }
    if (Pumpe == 1)
    {
      analogWrite(RPWM, Drehzahl); // PWM für Pumpe Vorwärts
      analogWrite(LPWM, 0); //Hier muss immer "0" sein, weil Rückwärts nicht gut ist
    }
    Sekundenablauf04 = millisekunden;
  }
  //------------------------Pumpensteuerung Ende-------------------------------
  //###########################################################################
  // ------------------------Serial Print Ausgabe------------------------------
  if (millisekunden - Sekundenablauf03 >= Pausezeit03) // Serial Ausgabezeit abgelaufen?
  {

    Serial.println(F("-------------------------------------"));
    Serial.print(F("Drehzahl Pumpe ist = "));
    Serial.print(Drehzahl);
    Serial.print(F("  soll = "));
    Serial.println(Solldrehzahl);
    Serial.print(F("Temp Pool = "));
    Serial.println(temppool);
    Serial.print(F("Temp Solar = "));
    Serial.println(tempsolar);
    Serial.print(F("Tempdif = "));
    Serial.print(tempsolar - temppool);
    Serial.print(F("  Soldif = "));
    Serial.println(P2);
    Serial.println(F("---------------------------------"));
    Serial.print(F("Panel "));
    Serial.print(pvv);
    Serial.print(F("V  "));
    Serial.print(pva);
    Serial.print (F("A  "));
    Serial.print(pvwat);
    Serial.println(F("W"));
    Serial.print(F("Akku  "));
    Serial.print(akkuVolt);
    Serial.print (F("V  "));
    Serial.print(akkuAmpere);
    Serial.print(F("A  "));
    Serial.print(prozent);
    Serial.println (F("%"));
    Serial.println (F("-------------------------------------"));
    Serial.print(F("Motorstrom "));
    Serial.print(Motorstrom);
    Serial.print(F(" Ampere"));
    Serial.print(F("  Drehzahl "));
    Serial.println(Drehzahl);
    if (Pumpe == 1)
    {
      Serial.println(F("Pumpe ein "));
    }
    else
    {
      Serial.println(F("!!!!!!! Pumpe aus !!!!!!!"));
    }
    Serial.println(F("##############################################"));

    Sekundenablauf03 = millisekunden;
  }
  //-------------------------Seriale Ausgabe Ende-----------------------------
  //##########################################################################
  //-------------------------------MPPT LOOP----------------------------------
  currentMillis = millis();
  if (currentMillis - previousMillis >= intervall)
  {
    previousMillis = currentMillis; // Zeitpunkt der letzten Schaltung wird festgehalten
    // Read 16 registers beginn mit Adresse  0x3100)
    uint8_t result;
    result = node.readInputRegisters(0x3100, 16);
    if (result == node.ku8MBSuccess)
    { //PV Daten
      pvv = node.getResponseBuffer(0x00) / 100.0f; //Tracer PV Volt
      pva = node.getResponseBuffer(0x01) / 100.0f;//PV Ampere
      //PV Leistung
      pvwat = ((node.getResponseBuffer(0x06) +  node.getResponseBuffer(0x07) ) / 100.0f);
      /*****  Akkustand Anzeigen  *****/
      akkuVolt = node.getResponseBuffer(0x04) / 100.0f; //Tracer Akku Volt
      akkuAmpere = node.getResponseBuffer(0x05) / 100.0f;//Akku Ladedaten in Ampere
    }
    result = node.readInputRegisters(0x311A , 1);//Akkukapazität in Prozent
    if (result == node.ku8MBSuccess) {
      prozent = node.getResponseBuffer(0x00);
    }
    lcd.setCursor (0, 0);
    lcd.print(akkuVolt);
    lcd.print (F("V  "));
    lcd.print(akkuAmpere);
    lcd.print (F("A  "));
    lcd.print(prozent);
    lcd.print (F("%  "));
    lcd.setCursor (0, 2);
    lcd.print (F("Soll"));
  }
  //-----------------------------MPPT LOOP Ende-------------------------------
  //##########################################################################
}
Antworten

Zurück zu „Hardware / Schaltungstechnik“

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 38 Gäste