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.

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.
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-------------------------------
//##########################################################################
}