diff --git a/PLC/GVLs/GVL_CONFIG.TcGVL b/PLC/GVLs/GVL_CONFIG.TcGVL
index 6f4ef4e..e9596ba 100644
--- a/PLC/GVLs/GVL_CONFIG.TcGVL
+++ b/PLC/GVLs/GVL_CONFIG.TcGVL
@@ -289,7 +289,18 @@ VAR_GLOBAL PERSISTENT
rBalancingFactor : REAL := 20.0;
// Timeout heartbeat from EMS
- timEMSHeartbeatTimeout : TIME := t#5s;
+ timEMSHeartbeatTimeout : TIME := T#5S;
+
+ // Flag if charging should be done with cv phase at end
+ xCVCharging : BOOL := FALSE;
+
+ // Controller parameters for cv charging
+ rCVKp : REAL := 0.0;
+ // In ms
+ rCVTn : REAL := 0.0;
+
+ // Minimum current for cv charging in Amps
+ rMinCVCurrentForFull : REAL := -5.0;
// Dummy to deactivate functions
{attribute 'analysis' := '-33'}
diff --git a/PLC/POUs/FB_String.TcPOU b/PLC/POUs/FB_String.TcPOU
index 700aef9..d0ecba8 100644
--- a/PLC/POUs/FB_String.TcPOU
+++ b/PLC/POUs/FB_String.TcPOU
@@ -389,7 +389,7 @@ xOff := _fbModule1.xOff AND _fbModule2.xOff AND _fbModule3.xOff;
_fbInverter(
sInverterIPAddr:= sInverterIP,
xEnable:= _xEnableInverter AND xEmergencyStopOk,
- xReleasePower := xReleaseInverterPower,
+ xReleasePower := xReleaseInverterPower AND _xEnableInverter,
rPower:= _rPowerInverterInternal,
xReset:= xConfirmAlarms,
rMaxBattPower:= DINT_TO_REAL(GVL_CONFIG.diMaxStringDischargePower),
diff --git a/PLC/POUs/MAIN.TcPOU b/PLC/POUs/MAIN.TcPOU
index bf76f7a..9ea5586 100644
--- a/PLC/POUs/MAIN.TcPOU
+++ b/PLC/POUs/MAIN.TcPOU
@@ -210,6 +210,12 @@ VAR
_xGetPowerMeterData : BOOL;
+ _fbPIControl : FB_PI;
+ _fbLimit : FB_Limit;
+ _xCVChargingLatched : BOOL;
+ _rCVSetpoint : REAL;
+ _xStringsFullCV : BOOL;
+
_rPowerDH : REAL;
_xDHActive : BOOL;
_fbTONDHCycleTime : TON := (PT := T#15M);
@@ -1087,7 +1093,7 @@ _fbTowerLight(
IF _xStringsErrorActive OR _fbStringReadyTimeout.Q THEN
_fbStringReadyTimeout(IN := FALSE);
- _xStringNotReadyInTime := TRUE;
+ _xStringNotReadyInTime := _fbStringReadyTimeout.Q;
_xEnableString := FALSE;
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
_xCanChangeMode := TRUE;
@@ -1148,11 +1154,54 @@ _fbTowerLight(
_xEnableString := FALSE;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.DISCHARGING;
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
+ _xCVChargingLatched := FALSE;
+ _fbPIControl.Reset();
_iState := 35;
END_IF
+ // Charge with constant Voltage at charging end
+ IF GVL_CONFIG.xCVCharging AND (_rAutoPowerRequest < 0.0) AND (_rHighestSegmentVoltage >= (GVL_CONFIG.rMaximumUnitVoltage)) THEN
+ _xCVChargingLatched := TRUE;
+ END_IF
+
+ // Delatch if charging power requested is lower than cv power
+ //IF _xCVChargingLatched AND (_rAutoPowerRequest > _rPowerInverter) THEN
+ // _xCVChargingLatched := FALSE;
+ //END_IF
+
+ IF _xCVChargingLatched THEN
+ // Reglerfreigabe
+ _rCVSetpoint := GVL_CONFIG.rMaximumUnitVoltage;
+ ELSE
+ // Nachführbetrieb
+ _rCVSetpoint := _rHighestSegmentVoltage;
+ END_IF
+
+ _fbPIControl(
+ rSP:= _rCVSetpoint,
+ rPV:= _rHighestSegmentVoltage,
+ rKp:= GVL_CONFIG.rCVKp,
+ rTn:= GVL_CONFIG.rCVTn,
+ xSaturated:= _fbLimit.xClamped);
+
+ _rPowerInverter := _rAutoPowerRequest - _fbPIControl.rMV;
+
+ _fbLimit(
+ rIn := _rPowerInverter,
+ rMin := _rMinPower,
+ rMax := _rMaxPower,
+ rOut => _rPowerInverter);
+
+ IF ((GVL_SCADA.stHMIInterface[0].stInverterData.rActDCCurrent > GVL_CONFIG.rMinCVCurrentForFull) AND GVL_CONFIG.axStringEnabled[0]) OR ((GVL_SCADA.stHMIInterface[1].stInverterData.rActDCCurrent > GVL_CONFIG.rMinCVCurrentForFull) AND GVL_CONFIG.axStringEnabled[1]) THEN
+ _xStringsFullCV := TRUE;
+ ELSE
+ _xStringsFullCV := FALSE;
+ END_IF
+
// Shutdown triggered by battery fully charged
- IF GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus = E_CHARGE_STATUS.CHARGING AND ((_rMaxCurrentInverterDCVoltage >= GVL_CONFIG.rStringFullyChargedVoltage) OR _rHighestSegmentVoltage >= GVL_CONFIG.rMaximumUnitVoltage) THEN
+ IF GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus = E_CHARGE_STATUS.CHARGING
+ AND ((_rMaxCurrentInverterDCVoltage >= GVL_CONFIG.rStringFullyChargedVoltage) OR (_rHighestSegmentVoltage >= GVL_CONFIG.rMaximumUnitVoltage AND (NOT _xCVChargingLatched)) OR _xStringsFullCV) THEN
+//OR (_xCVChargingLatched AND ((ABS(GVL_SCADA.stHMIInterface[0].rCurrent) < 8.0) OR (ABS(GVL_SCADA.stHMIInterface[0].rCurrent) < 8.0)))
_xGetPowerMeterData := TRUE;
IF (_eBMSControlMode = E_BMS_CONTROL_MODE.CYCLING) THEN
GVL_SCADA.eCycleStatus := E_CYCLE_STATUS.DISCHARGE_STARTED;
@@ -1176,9 +1225,10 @@ _fbTowerLight(
// Change battery status
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.FULL;
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
+ _xCVChargingLatched := FALSE;
+ _fbPIControl.Reset();
_iState := 35;
END_IF
-
END_IF
// Shutdown triggered by battery empty
@@ -1206,6 +1256,8 @@ _fbTowerLight(
// Change battery status
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.EMPTY;
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
+ _xCVChargingLatched := FALSE;
+ _fbPIControl.Reset();
_iState := 35;
END_IF
END_IF
@@ -1218,6 +1270,8 @@ _fbTowerLight(
_tonBeginShutdown(In := FALSE);
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
_xCanChangeMode := TRUE;
+ _xCVChargingLatched := FALSE;
+ _fbPIControl.Reset();
_iState := 45;
END_IF
diff --git a/PLC/POUs/Utility/Controller/FB_Limit.TcPOU b/PLC/POUs/Utility/Controller/FB_Limit.TcPOU
new file mode 100644
index 0000000..f989711
--- /dev/null
+++ b/PLC/POUs/Utility/Controller/FB_Limit.TcPOU
@@ -0,0 +1,30 @@
+
+
+
+
+
+ rMax THEN
+ rOut := rMax;
+ xClamped := TRUE;
+ELSIF rIn < rMin THEN
+ rOut := rMin;
+ xClamped := TRUE;
+ELSE
+ rOut := rIn;
+ xClamped := FALSE;
+END_IF]]>
+
+
+
\ No newline at end of file
diff --git a/PLC/POUs/Utility/Controller/FB_PI.TcPOU b/PLC/POUs/Utility/Controller/FB_PI.TcPOU
new file mode 100644
index 0000000..64be941
--- /dev/null
+++ b/PLC/POUs/Utility/Controller/FB_PI.TcPOU
@@ -0,0 +1,68 @@
+
+
+
+
+
+ 0) THEN
+ _rIntegral := _rIntegral + (rKp * _rT / rTn) * _rError;
+END_IF
+
+// Reset integral with deactivated integral time
+IF (rTn = 0.0) AND (_rIntegral <> 0) THEN
+ _rIntegral := 0.0;
+END_IF]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file