#define VOLTBATT_FAKTOR 10.8904 #define WERTE_AVG 60 // Sekunden #define AVPOWER 5 // Minuten void GetSensorData() { /* Array für Mittelwertbildung über 60s */ float summe; static int oldhour = 0x55; static int head_ubatt = 0; // Index für Mittelwert Arrays static int head_solar = 0; static int head_last = 0; static int head_pow5Min = 0; static float AvSolar[WERTE_AVG + 1]; static float AvLast[WERTE_AVG + 1]; static float AvUBatt[WERTE_AVG + 1]; static int AvPow5Min[AVPOWER * WERTE_AVG]; // 5 Minuten Mittelwert für Watt static bool init = true; if (init) { /* UBatt füllen */ adc.setCompareChannels(ADS1115_COMP_0_GND); for (int i = 0; i < WERTE_AVG; i++) AvUBatt[i] = adc.getResult_mV(); /* Solar füllen */ adc.setCompareChannels(ADS1115_COMP_1_GND); for (int i = 0; i < WERTE_AVG; i++) AvSolar[i] = adc.getResult_mV(); /* Last */ adc.setCompareChannels(ADS1115_COMP_2_GND); for (int i = 0; i < WERTE_AVG; i++) AvLast[i] = adc.getResult_mV(); init = false; } /* ------------ U Batterie --------------------- */ adc.setCompareChannels(ADS1115_COMP_0_GND); AvUBatt[head_ubatt] = adc.getResult_mV(); head_ubatt = (head_ubatt + 1) % WERTE_AVG; summe = 0.0; for (int i = 0; i < WERTE_AVG; i++) { summe = summe + AvUBatt[i]; } float Volt = summe / (WERTE_AVG * 1000.0); USenseVolt = Volt; Data.UBatt = Volt * VOLTBATT_FAKTOR; // Spannungsteiler berücksichtigen Data.UBatt = max(0, min(Data.UBatt, BATT_MAX)); // Grenzen setzen /* ------------ I Solar --------------------- */ adc.setCompareChannels(ADS1115_COMP_1_GND); AvSolar[head_solar] = adc.getResult_mV(); head_solar = (head_solar + 1) % WERTE_AVG; summe = 0; for (int i = 0; i < WERTE_AVG; i++) { summe = summe + AvSolar[i]; } SolarVolt = summe / (WERTE_AVG * 1000.0); Data.ISolar = abs(SolarVolt - Data.ISolSensorCal) / SensorISFaktor; /* WCS 1800 Geradegleichung Spg -> Strom */ /* Bereichsgrenzen ausblenden */ if (Data.ISolar > IMAX_SOLAR) Data.ISolar = IMAX_SOLAR; if (Data.ISolar < 0.5) Data.ISolar = 0.0; /* Wenn Ladebetrieb, dann Strom neu berechnen */ if (Flags.IsMikroinverterMode == false) { Data.ISolar = Data.ISolar * MPPT_FAKTOR; } /* ------------ P Last --------------------- */ adc.setCompareChannels(ADS1115_COMP_2_GND); AvLast[head_last] = adc.getResult_mV(); head_last = (head_last + 1) % WERTE_AVG; summe = 0; for (int i = 0; i < WERTE_AVG; i++) { summe = summe + AvLast[i]; } LastVolt = summe / (WERTE_AVG * 1000.0); Data.ILast = abs(LastVolt - Data.ILastSensorCal) / 0.052; /* WCS 1800 Geradegleichung Spg -> Strom */ /* Sensor Ungenauigkeiten ausblenden */ if (Data.ILast < 1.0) Data.ILast = 0; /* -------- Leistungswerte berechnen --------*/ if (Flags.IsMikroinverterMode) Data.PSolar = Data.ISolar * MPPT_SOLAR; else Data.PSolar = Data.ISolar * Data.UBatt; Data.PLast = Data.ILast * Data.UBatt; /* PSolar mitteln */ AvPow5Min[head_pow5Min] = Data.PSolar; head_pow5Min = (head_pow5Min + 1) % (AVPOWER * WERTE_AVG); summe = 0; for (int i = 0; i < (AVPOWER * WERTE_AVG); i++) { summe = summe + AvPow5Min[i]; } /* Mittelwert für Dot Matrix Display */ AvPower5m = summe / (AVPOWER * WERTE_AVG); /* Bei Netzbetrieb P = 0 */ if (Flags.IsNetzBetrieb) Data.PLast = 0.0; /* Maximalwerte ermitteln */ ISolarMax = max(ISolarMax, Data.ISolar); PSolarMax = max(PSolarMax, Data.PSolar); /* Energiemengen berechnen */ if (Flags.IsMikroinverterMode) Data.WhSolarNetz += (Data.PSolar / 3600.0); // * LADE_WIRKUNGSGRAD); else Data.WhSolarBatt += (Data.PSolar / 3600.0); // * LADE_WIRKUNGSGRAD); Data.AhSolar = Data.AhSolar + (Data.ISolar / 3600.0); Data.WhLast = Data.WhLast + (Data.PLast / 3600.0); /* Eintragen in Struct */ Data.WhSolarCounter += (Data.PSolar / 3600.0); Data.WhSolarHour[Zeit.tm_hour] = Data.WhSolarCounter; /* Neue Stunde, dann Wert zurücksetzen */ if (Zeit.tm_hour != oldhour) { oldhour = Zeit.tm_hour; Data.WhSolarCounter = 0; } } /* ***********************************************/ /* Prüft ob die Batterie lange genug geladen hat */ /* ***********************************************/ #define ILEVELCURRENT 3 void CheckBatteryFull() { if (Data.UBatt < BATT_LOAD_LIMIT) { Flags.BatteryCharged = false; } /* Batterie leer? */ if (Data.UBatt < BATT_LOW_LIMIT) { Flags.MustLoadBattery = true; Flags.BatteryCharged = false; return; } /* Batterie voll? Das Kriterium dafür ist, dass die Vollladespannung von 14V erreicht wird beim 1/2 Solarstrom, also ca 11A */ if (!Flags.BatteryCharged) { tim[0].run = (Data.UBatt >= BATT_BOOST) && (Data.ISolar < 1.5); /* Timer läuft wenn voll */ if (tim[0].val >= BURSTLOAD) { tim[0].run = false; tim[0].val = 0; Flags.BatteryCharged = true; } } } /* Sekündliche Eintragung und Berechnung der Mittelwerte für Entscheidungshilfe über Batteriezustand. Mittelung über 10 Minuten */ void MakeAvgValues() { static bool firstrun = true; if (firstrun) { AvgValues.UBattAvg = Data.UBatt; AvgValues.ISolarAvg = 0; AvgValues.ILastAvg = 0; firstrun = false; return; } /* Batteriespannung */ AvgValues.UBattAvg = ((AvgValues.UBattAvg * (AVG_SEKUNDEN - 1)) + Data.UBatt) / AVG_SEKUNDEN; /* Solarstrom berechnen*/ AvgValues.ISolarAvg = ((AvgValues.ISolarAvg * (AVG_SEKUNDEN - 1)) + Data.ISolar) / AVG_SEKUNDEN; /* Laststrom */ AvgValues.ILastAvg = ((AvgValues.ILastAvg * (AVG_SEKUNDEN - 1)) + Data.ILast) / AVG_SEKUNDEN; } /* ------------------------------------------- Messdatenerfassung -------------------------------------------- */ /* Kalibriere die Sensoren nachts um 3 Uhr */ void CalibrateSensors() { #define AVG_CYCLES 32 debugln("Kalibriere Sensoren"); /* Umschalten auf Netzbetrieb */ digitalWrite(REL_NETZBATT, 0); // Auf Netzbetrieb umschalten delay(100); digitalWrite(REL_INVERTER_12V, 0); // Inverter ausschalten delay(100); digitalWrite(REL_SUNTOINVT, 1); // Solarstrom auf Inverter delay(500); float value = 0; /* Solarsensor neu einstellen */ adc.setCompareChannels(ADS1115_COMP_1_GND); for (int i = 0; i < AVG_CYCLES; i++) { value += adc.getResult_mV(); // ISolar delay(5); } value = (value / AVG_CYCLES) / 1000; debugln("Solar-Mittelwert (V) = " + String(value)); Data.ISolSensorCal = value; /* Last Sensor */ adc.setCompareChannels(ADS1115_COMP_2_GND); value = 0; for (int i = 0; i < AVG_CYCLES; i++) { value += adc.getResult_mV(); // ILast delay(5); } value = (value / AVG_CYCLES) / 1000; debugln("Last Mittelwert (V) = " + String(value)); Data.ILastSensorCal = value; /* Relais zurückschreiben */ digitalWrite(REL_INVERTER_12V, RelStat.Rel_INVERTER_12V_Shadow); if (RelStat.Rel_INVERTER_12V_Shadow) delay(3000); digitalWrite(REL_NETZBATT, RelStat.Rel_NETZBATT_Shadow); delay(100); digitalWrite(REL_SUNTOINVT, RelStat.Rel_SUNTOINVT_Shadow); delay(100); } /* Bedient den Automatik Mode sekündlich */ void AutomaticHandler() { /* Kein Automatik Mode? Dann raus */ if (!Flags.IsAutomaticMode) { return; } /* Laden bis Voll Bedingung erneut erfüllt */ if (Flags.BatteryCharged) { EnableMikroInverter(ON); } else { EnableMikroInverter(OFF); } }