Minor bugfixes and future addons

This commit is contained in:
Matthias Heisig
2025-04-06 10:21:01 +02:00
parent 84e0e174a1
commit 2221f6bab3
22 changed files with 795 additions and 509 deletions

View File

@@ -12,9 +12,6 @@ VAR_INPUT
// Start balancing
xStartBalancing : BOOL;
// Component shortage workaround
stModuleVoltageConfig : ST_MODULE_VOLT_CONFIG;
// Module in safety check mode
xInSafetyCheckMode : BOOL;
@@ -57,6 +54,10 @@ VAR_INPUT
// Leakage tank
xLeakageTank AT %I* : BOOL;
// Current current value from string to copy to HMI interface
rCurrent : REAL;
// Current EtherCAT state
uiECState AT %I* : UINT;
END_VAR
VAR_OUTPUT
@@ -117,16 +118,9 @@ VAR
// Connection lost alarm
_fbConnLostAlarm : FB_TcAlarm;
// Enable balance check
_xEnableBalanceCheck : BOOL;
// Module name
_sName : STRING;
// Moving average filter for module voltage
//_fbMAFVoltage : FB_MovingAverageFilter;
//_arMAFVoltage : ARRAY[0..9] OF REAL;
_fbBalanceNotOkSignal : FB_ReleaseSignal;
_xECModuleInOP : BOOL;
@@ -220,7 +214,6 @@ _fbUnit1(
xEnable := xEnable,
xStartBalancing := xStartBalancing,
xInverterEnabled := xInverterEnabled,
xVoltageSensorIs1500V := stModuleVoltageConfig.xUnit1Is1500V,
xInSafetyCheckMode := xInSafetyCheckMode,
stUnitConfig:= GVL_CONFIG.stUnitConfig,
stHMIInterface:= refstHMIInterface.stHMIInterfaceUnit1,
@@ -230,8 +223,9 @@ _fbUnit1(
xConfirmAlarms:= xConfirmAlarms,
xReleaseManualMode := xReleaseManualMode,
rBalancingTargetVoltage := rBalancingTargetVoltage,
xAllToManualMode := xAllToManualMode,
_xWarningConfirmPending=> );
xAllToManualMode := xAllToManualMode);
refstHMIInterface.stHMIInterfaceUnit1.rCurrent := rCurrent;
IF _fbUnit1.xWarning THEN
xWarning := TRUE;
@@ -258,7 +252,6 @@ _fbUnit2(
xEnable := xEnable,
xStartBalancing := xStartBalancing,
xInverterEnabled := xInverterEnabled,
xVoltageSensorIs1500V := stModuleVoltageConfig.xUnit2Is1500V,
xInSafetyCheckMode := xInSafetyCheckMode,
stUnitConfig:= GVL_CONFIG.stUnitConfig,
stHMIInterface:= refstHMIInterface.stHMIInterfaceUnit2,
@@ -268,8 +261,9 @@ _fbUnit2(
xConfirmAlarms:= xConfirmAlarms,
xReleaseManualMode := xReleaseManualMode,
rBalancingTargetVoltage := rBalancingTargetVoltage,
xAllToManualMode := xAllToManualMode,
_xWarningConfirmPending=> );
xAllToManualMode := xAllToManualMode);
refstHMIInterface.stHMIInterfaceUnit2.rCurrent := rCurrent;
IF _fbUnit2.xWarning THEN
xWarning := TRUE;
@@ -296,7 +290,6 @@ _fbUnit3(
xEnable := xEnable,
xStartBalancing := xStartBalancing,
xInverterEnabled := xInverterEnabled,
xVoltageSensorIs1500V := stModuleVoltageConfig.xUnit3Is1500V,
xInSafetyCheckMode := xInSafetyCheckMode,
stUnitConfig:= GVL_CONFIG.stUnitConfig,
stHMIInterface:= refstHMIInterface.stHMIInterfaceUnit3,
@@ -306,8 +299,9 @@ _fbUnit3(
xConfirmAlarms:= xConfirmAlarms,
xReleaseManualMode := xReleaseManualMode,
rBalancingTargetVoltage := rBalancingTargetVoltage,
xAllToManualMode := xAllToManualMode,
_xWarningConfirmPending=> );
xAllToManualMode := xAllToManualMode);
refstHMIInterface.stHMIInterfaceUnit3.rCurrent := rCurrent;
IF _fbUnit3.xWarning THEN
xWarning := TRUE;
@@ -334,7 +328,6 @@ _fbUnit4(
xEnable := xEnable,
xStartBalancing := xStartBalancing,
xInverterEnabled := xInverterEnabled,
xVoltageSensorIs1500V := stModuleVoltageConfig.xUnit4Is1500V,
xInSafetyCheckMode := xInSafetyCheckMode,
stUnitConfig:= GVL_CONFIG.stUnitConfig,
stHMIInterface:= refstHMIInterface.stHMIInterfaceUnit4,
@@ -344,8 +337,9 @@ _fbUnit4(
xConfirmAlarms:= xConfirmAlarms,
xReleaseManualMode := xReleaseManualMode,
rBalancingTargetVoltage := rBalancingTargetVoltage,
xAllToManualMode := xAllToManualMode,
_xWarningConfirmPending=> );
xAllToManualMode := xAllToManualMode);
refstHMIInterface.stHMIInterfaceUnit4.rCurrent := rCurrent;
IF _fbUnit4.xWarning THEN
xWarning := TRUE;
@@ -394,12 +388,11 @@ xShutdownDischargeAllowed := _fbUnit1.xShutdownDischargeAllowed AND _fbUnit2.xSh
// ===============================
xOff := _fbUnit1.xOff AND _fbUnit2.xOff AND _fbUnit3.xOff AND _fbUnit4.xOff;
// ===============================
// Calculate module voltage
// ===============================
rCurrentVoltage := _fbUnit1.rCurrentVoltage + _fbUnit2.rCurrentVoltage + _fbUnit3.rCurrentVoltage + _fbUnit4.rCurrentVoltage;
//_fbMAFVoltage(pValues := ADR(_arMAFVoltage), iArraySize := 10, rCurrentValue := rCurrentVoltage, rAverage => stHMIInterface.rVoltage);
//stHMIInterface.rVoltage := rCurrentVoltage;
refstHMIInterface.rVoltage := refstHMIInterface.rVoltage * 0.9 + rCurrentVoltage * 0.1;
@@ -484,25 +477,35 @@ END_IF
rSmallestSegmentVoltage := MIN(_fbUnit1.rCurrentVoltage, _fbUnit2.rCurrentVoltage, _fbUnit3.rCurrentVoltage, _fbUnit4.rCurrentVoltage);
rHighestSegmentVoltage := MAX(_fbUnit1.rCurrentVoltage, _fbUnit2.rCurrentVoltage, _fbUnit3.rCurrentVoltage, _fbUnit4.rCurrentVoltage);
// ===============================
// Copy string current to module current
// ===============================
refstHMIInterface.rCurrent := rCurrent;
// ===============================
// Module status sum
// ===============================
// Module ready
IF xReady AND (NOT xError) THEN
refstHMIInterface.eStatus := E_COMPONENT_STATUS.ON;
END_IF
IF (_fbUnit1.eUnitState = E_COMPONENT_STATUS.STARTING OR _fbUnit1.eUnitState = E_COMPONENT_STATUS.STARTING OR _fbUnit1.eUnitState = E_COMPONENT_STATUS.STARTING OR _fbUnit1.eUnitState = E_COMPONENT_STATUS.STARTING) AND (NOT xError) THEN
// Module starting
IF (NOT xOff) AND (NOT xReady) AND xEnable AND (NOT xError) THEN
refstHMIInterface.eStatus := E_COMPONENT_STATUS.STARTING;
END_IF
IF (_fbUnit1.eUnitState = E_COMPONENT_STATUS.SHUTDOWN OR _fbUnit1.eUnitState = E_COMPONENT_STATUS.SHUTDOWN OR _fbUnit1.eUnitState = E_COMPONENT_STATUS.SHUTDOWN OR _fbUnit1.eUnitState = E_COMPONENT_STATUS.SHUTDOWN) AND (NOT xError) THEN
// Module shutdown
IF (NOT xOff) AND (NOT xReady) AND (NOT xEnable) AND (NOT xError) THEN
refstHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN;
END_IF
IF (_fbUnit1.eUnitState = E_COMPONENT_STATUS.OFF AND _fbUnit1.eUnitState = E_COMPONENT_STATUS.OFF AND _fbUnit1.eUnitState = E_COMPONENT_STATUS.OFF AND _fbUnit1.eUnitState = E_COMPONENT_STATUS.OFF) AND (NOT xError) THEN
// Module off
IF xOff AND (NOT xError) THEN
refstHMIInterface.eStatus := E_COMPONENT_STATUS.OFF;
END_IF
// Module error
IF xError THEN
refstHMIInterface.eStatus := E_COMPONENT_STATUS.ERROR;
END_IF
@@ -584,5 +587,37 @@ _fbLeackageSegment34Alarm.ipArguments.Clear().AddString(_sName);]]></ST>
</Implementation>
</Set>
</Property>
<LineIds Name="FB_Module">
<LineId Id="3" Count="81" />
<LineId Id="86" Count="9" />
<LineId Id="371" Count="1" />
<LineId Id="96" Count="25" />
<LineId Id="123" Count="9" />
<LineId Id="373" Count="1" />
<LineId Id="133" Count="25" />
<LineId Id="160" Count="9" />
<LineId Id="375" Count="1" />
<LineId Id="170" Count="25" />
<LineId Id="197" Count="9" />
<LineId Id="377" Count="1" />
<LineId Id="207" Count="135" />
<LineId Id="380" Count="1" />
<LineId Id="383" Count="0" />
<LineId Id="379" Count="0" />
<LineId Id="384" Count="0" />
<LineId Id="343" Count="27" />
<LineId Id="2" Count="0" />
</LineIds>
<LineIds Name="FB_Module.FB_init">
<LineId Id="3" Count="26" />
<LineId Id="2" Count="0" />
</LineIds>
<LineIds Name="FB_Module.Name.Get">
<LineId Id="2" Count="0" />
</LineIds>
<LineIds Name="FB_Module.Name.Set">
<LineId Id="3" Count="16" />
<LineId Id="2" Count="0" />
</LineIds>
</POU>
</TcPlcObject>

View File

@@ -3,49 +3,119 @@
<POU Name="FB_PowerMeter" Id="{9d4159f4-2d3f-4522-a770-c038a26d9d77}" SpecialFunc="None">
<Declaration><![CDATA[FUNCTION_BLOCK FB_PowerMeter
VAR_INPUT
xResetEnergyCounter : BOOL;
xGetEnergyCounters : BOOL;
// IP 75 -> Umrichter
// IP 80 -> Hilfsenergie
sIpAddress : STRING(80);
END_VAR
VAR_OUTPUT
lrEnergyFromGrid : LREAL;
lrEnergyIntoGrid : LREAL;
xBusy : BOOL;
xError : BOOL;
END_VAR
VAR
_fbReadRegs : FB_MBReadInputRegs;
_fbWriteRegs : FB_MBWriteRegs;
_fbReadRegs : FB_MBReadRegs;
_awWordArray : ARRAY[0..3] OF WORD;
_awSwapped : ARRAY[0..3] OF WORD;
_udiErrorId : UDINT;
_fbREResetEnergyCounter : R_TRIG;
_fbGetEnergyCounters : R_TRIG;
_xResetEnergyCounter : BOOL;
_iState : INT := 0;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[_fbREResetEnergyCounter(CLK := xResetEnergyCounter);
<ST><![CDATA[_fbGetEnergyCounters(CLK := xGetEnergyCounters);
IF _fbREResetEnergyCounter.Q THEN
IF _fbGetEnergyCounters.Q THEN
_xResetEnergyCounter := TRUE;
END_IF
CASE _iState OF
0: // Idle
IF _xResetEnergyCounter THEN
xBusy := TRUE;
xError := FALSE;
_xResetEnergyCounter := FALSE;
_iState := 10;
END_IF
10: // Reset energy counters
_fbWriteRegs(
sIPAddr:= '192.168.42.80',
10: // Read energy from grid
_fbReadRegs(
sIPAddr:= sIpAddress,
nTCPPort:= 502,
nUnitID:= 16#FF ,
nQuantity:= ,
nMBAddr:= 16#0600,
cbLength:= ,
pSrcAddr:= ,
bExecute:= ,
nUnitID:= 16#FF,
nQuantity:= 4,
nMBAddr:= 8192,
cbLength:= SIZEOF(_awWordArray),
pDestAddr:= ADR(_awWordArray),
bExecute:= TRUE,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> );
nErrId=> ,
cbRead=> );
IF (NOT _fbReadRegs.bBusy) AND (NOT _fbReadRegs.bError) THEN
_fbReadRegs(bExecute := FALSE);
SwapArray();
MEMCPY(ADR(lrEnergyFromGrid), ADR(_awSwapped), 8);
_iState := 20;
END_IF
IF _fbReadRegs.bError THEN
xBusy := FALSE;
xError := TRUE;
_udiErrorId := _fbReadRegs.nErrId;
lrEnergyFromGrid := 0;
_fbReadRegs(bExecute := FALSE);
_iState := 1000;
END_IF
20: // Read energy to grid
_fbReadRegs(
sIPAddr:= '192.168.42.75',
nTCPPort:= 502,
nUnitID:= 16#FF,
nQuantity:= 4,
nMBAddr:= 8196,
cbLength:= SIZEOF(_awWordArray),
pDestAddr:= ADR(_awWordArray),
bExecute:= TRUE,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> ,
cbRead=> );
IF (NOT _fbReadRegs.bBusy) AND (NOT _fbReadRegs.bError) THEN
_fbReadRegs(bExecute := FALSE);
SwapArray();
MEMCPY(ADR(lrEnergyIntoGrid), ADR(_awSwapped), 8);
_iState := 0;
xBusy := FALSE;
END_IF
IF _fbReadRegs.bError THEN
xBusy := FALSE;
xError := TRUE;
_udiErrorId := _fbReadRegs.nErrId;
lrEnergyIntoGrid := 0;
_fbReadRegs(bExecute := FALSE);
_iState := 0;
END_IF
END_CASE]]></ST>
</Implementation>
<Action Name="SwapArray" Id="{96198008-b45e-42ee-9345-377fed90aab6}">
<Implementation>
<ST><![CDATA[_awSwapped[0] := _awWordArray[3];
_awSwapped[1] := _awWordArray[2];
_awSwapped[2] := _awWordArray[1];
_awSwapped[3] := _awWordArray[0];]]></ST>
</Implementation>
</Action>
</POU>
</TcPlcObject>

View File

@@ -6,6 +6,9 @@ VAR_INPUT
// Enable
xEnable : BOOL;
// Error shutdown -> No discharge throught inverter
xErrorShutdown : BOOL;
// Start in balancing mode
xStartBalancing : BOOL;
@@ -14,11 +17,8 @@ VAR_INPUT
// Requested inverter power
rPowerInverter : REAL;
// Components shortage workaround
stStringModuleVoltageConfig : ST_STRING_VOLT_CONFIG;
// Module 1 HMI interface
// String HMI interface
stHMIInterface : REFERENCE TO ST_STRING_HMI_INTERFACE;
// Emergency stop ok
@@ -31,6 +31,7 @@ VAR_INPUT
xSafetyIntlksOk AT %I* : BOOL;
// Safety communication error
{attribute 'analysis' := '-33'}
xSafetyComError AT %I* : BOOL;
// Release alarms
@@ -294,7 +295,10 @@ _fbStringCurrent(
xWarningLow=> ,
xWarningHigh=> ,
xErrorHigh=> ,
stHMIInterface=> stHMIInterface.stStringCurrent);
stHMIInterface=> );
// Copy scaled current value to HMI
stHMIInterface.rCurrent := _fbStringCurrent.stHMIInterface.rValue;
@@ -303,9 +307,9 @@ _fbStringCurrent(
// ===============================
_fbModule1(
xEnable := _xEnable,
rCurrent := stHMIInterface.rCurrent,
xStartBalancing := _xStartBalancing,
xInverterEnabled := _fbInverter.xActive,
stModuleVoltageConfig := stStringModuleVoltageConfig.stModule1VoltConfig,
xInSafetyCheckMode := xInSafetyCheckMode,
xEmergencyStopOk:= xEmergencyStopOk,
refstHMIInterface:= stHMIInterface.stHMIInterfaceModule1,
@@ -315,6 +319,8 @@ _fbModule1(
xConfirmAlarms:= xConfirmAlarms,
xAllToManualMode := xAllToManualMode,
rBalancingTargetVoltage := rSmallestSegmentVoltage);
// ===============================
@@ -323,9 +329,9 @@ _fbModule1(
_fbModule2(
xEnable := _xEnable,
rCurrent := stHMIInterface.rCurrent,
xStartBalancing := _xStartBalancing,
xInverterEnabled := _fbInverter.xActive,
stModuleVoltageConfig := stStringModuleVoltageConfig.stModule2VoltConfig,
xInSafetyCheckMode := xInSafetyCheckMode,
xEmergencyStopOk:= xEmergencyStopOk,
refstHMIInterface:= stHMIInterface.stHMIInterfaceModule2,
@@ -335,6 +341,8 @@ _fbModule2(
xConfirmAlarms:= xConfirmAlarms,
xAllToManualMode := xAllToManualMode,
rBalancingTargetVoltage := rSmallestSegmentVoltage);
// ===============================
@@ -342,9 +350,9 @@ _fbModule2(
// ===============================
_fbModule3(
xEnable := _xEnable,
rCurrent := stHMIInterface.rCurrent,
xStartBalancing := _xStartBalancing,
xInverterEnabled := _fbInverter.xActive,
stModuleVoltageConfig := stStringModuleVoltageConfig.stModule3VoltConfig,
xInSafetyCheckMode := xInSafetyCheckMode,
xEmergencyStopOk:= xEmergencyStopOk,
refstHMIInterface:= stHMIInterface.stHMIInterfaceModule3,
@@ -355,6 +363,7 @@ _fbModule3(
xAllToManualMode := xAllToManualMode,
rBalancingTargetVoltage := rSmallestSegmentVoltage);
// ===============================
// Handle modules error state
// ===============================
@@ -393,29 +402,63 @@ END_IF
// ===============================
_xAllModulesReady := _fbModule1.xReady AND _fbModule2.xReady AND _fbModule3.xReady;
// ===============================
// Balancing done check
// ===============================
_xBalancingDone := _fbModule1.xBalancingDone AND _fbModule2.xBalancingDone AND _fbModule3.xBalancingDone;
// ===============================
// Modules in shutdown discharge mode
// ===============================
xInShutdownDischargeMode := _fbModule1.xInShutdownDischargeMode AND _fbModule2.xInShutdownDischargeMode AND _fbModule3.xInShutdownDischargeMode;
xInShutdownDischargeMode := _fbModule1.xInShutdownDischargeMode OR _fbModule2.xInShutdownDischargeMode OR _fbModule3.xInShutdownDischargeMode;
// ===============================
// Units shutdown discharge allowed
// ===============================
xShutdownDischargeAllowed := _fbModule1.xShutdownDischargeAllowed AND _fbModule2.xShutdownDischargeAllowed AND _fbModule3.xShutdownDischargeAllowed;
// ===============================
// All modules off
// ===============================
xOff := _fbModule1.xOff AND _fbModule2.xOff AND _fbModule3.xOff;
// ===============================
// Handle status
// ===============================
// String off
IF xOff AND (NOT xError) THEN
eStatus := E_COMPONENT_STATUS.OFF;
END_IF
// String starting
IF _xEnable AND (NOT _xAllModulesReady) AND (NOT xError) THEN
eStatus := E_COMPONENT_STATUS.STARTING;
END_IF
// String on
IF _xAllModulesReady AND _fbInverter.xActive AND (NOT xError) THEN
IF _rPowerInverterInternal < 0.0 THEN
eStatus := E_COMPONENT_STATUS.CHARGING;
ELSIF _rPowerInverterInternal > 0.0 THEN
eStatus := E_COMPONENT_STATUS.DISCHARGING;
ELSE
eStatus := E_COMPONENT_STATUS.ON;
END_IF
END_IF
// String in shutdown
IF xInShutdownDischargeMode AND (NOT xError) THEN
eStatus := E_COMPONENT_STATUS.SHUTDOWN;
END_IF
// String in error state
IF xError THEN
eStatus := E_COMPONENT_STATUS.ERROR;
END_IF
// ===============================
// Calculate string voltage
// ===============================
@@ -512,7 +555,7 @@ CASE _iState OF
// Start in normal mode
IF xEnable AND (NOT xStartBalancing) AND xAllModulesInAutoMode AND xRepairSwitchOk THEN
_xEnable := TRUE;
eStatus := E_COMPONENT_STATUS.STARTING;
//eStatus := E_COMPONENT_STATUS.STARTING;
IF xInSafetyCheckMode THEN
_iState := 1;
ELSE
@@ -524,10 +567,11 @@ CASE _iState OF
IF (NOT xEnable) AND xStartBalancing AND xAllModulesInAutoMode THEN
_xStartBalancing := TRUE;
_xReleaseLimitErrorsInternal := FALSE;
eStatus := E_COMPONENT_STATUS.STARTING;
//eStatus := E_COMPONENT_STATUS.STARTING;
_iState := 7;
END_IF
1: // Wait for ready in safety check mode
IF _xAllModulesReady THEN
xResetSafetyDCCB := TRUE;
@@ -547,7 +591,7 @@ CASE _iState OF
IF (NOT xEnable) THEN
_xEnable := FALSE;
eStatus := E_COMPONENT_STATUS.OFF;
//eStatus := E_COMPONENT_STATUS.OFF;
_iState := 0;
END_IF
@@ -563,7 +607,7 @@ CASE _iState OF
IF (NOT xStartBalancing) THEN
_xStartBalancing := FALSE;
eStatus := E_COMPONENT_STATUS.OFF;
//eStatus := E_COMPONENT_STATUS.OFF;
_iState := 0;
END_IF
@@ -589,10 +633,10 @@ CASE _iState OF
_iState := 20;
END_IF
IF NOT xEnable THEN
IF (NOT xEnable) THEN
_tonSafetyOkTimeout.IN := FALSE;
_xEnable := FALSE;
eStatus := E_COMPONENT_STATUS.SHUTDOWN;
//eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40;
END_IF
@@ -615,6 +659,7 @@ CASE _iState OF
//_rPowerInverterInternal := 0.0;
IF xInSafetyCheckMode THEN
_iState := 29;
//eStatus := E_COMPONENT_STATUS.ON;
ELSE
_iState := 21;
END_IF
@@ -628,10 +673,10 @@ CASE _iState OF
_iState := 1000;
END_IF
IF NOT xEnable THEN
IF (NOT xEnable) THEN
_tonSafetyOkTimeout.IN := FALSE;
_xEnable := FALSE;
eStatus := E_COMPONENT_STATUS.SHUTDOWN;
//eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40;
END_IF
@@ -639,7 +684,7 @@ CASE _iState OF
_tonInverterStartupTimeout(IN := TRUE);
IF _fbInverter.xActive AND (NOT _fbInverter.xError) THEN
_iState := 30;
eStatus := E_COMPONENT_STATUS.ON;
//eStatus := E_COMPONENT_STATUS.ON;
xReady := TRUE;
_tonInverterStartupTimeout(IN := FALSE);
END_IF
@@ -648,7 +693,7 @@ CASE _iState OF
_xEnableInverter := FALSE;
_rPowerInverterInternal := 0.0;
_xEnable := FALSE;
eStatus := E_COMPONENT_STATUS.SHUTDOWN;
//eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 31;
_tonInverterStartupTimeout(IN := FALSE);
END_IF
@@ -674,7 +719,7 @@ CASE _iState OF
IF (NOT xEnable) THEN
_xEnable := FALSE;
_xReleaseLimitErrorsInternal := FALSE;
eStatus := E_COMPONENT_STATUS.SHUTDOWN;
//eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 31;
END_IF
@@ -694,6 +739,7 @@ CASE _iState OF
_rPowerInverterInternal := rPowerInverter;
END_IF
(*
IF _rPowerInverterInternal > 0.0 THEN
eStatus := E_COMPONENT_STATUS.DISCHARGING;
ELSIF _rPowerInverterInternal < 0.0 THEN
@@ -701,6 +747,7 @@ CASE _iState OF
ELSE
eStatus := E_COMPONENT_STATUS.ON;
END_IF
*)
// Shutdown
IF (NOT xEnable) THEN
@@ -708,12 +755,12 @@ CASE _iState OF
_xReleaseLimitErrorsInternal := FALSE;
IF GVL_CONFIG.xShutdownDischargeWithInverter THEN
_rPowerInverterInternal := GVL_CONFIG.rAbsShutdownDischargePower;
eStatus := E_COMPONENT_STATUS.SHUTDOWN;
//eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 31;
ELSE
_rPowerInverterInternal := 0.0;
_xEnableInverter := FALSE;
eStatus := E_COMPONENT_STATUS.SHUTDOWN;
//eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40;
END_IF
@@ -738,7 +785,7 @@ CASE _iState OF
END_IF
32: // Shutdown discharge mode
IF xShutdownDischargeAllowed AND GVL_CONFIG.xShutdownDischargeWithInverter AND xSafetyIntlksOk AND (stInverterData.rActDCVoltage > 620.0) THEN
IF xShutdownDischargeAllowed AND (NOT xErrorShutdown) AND GVL_CONFIG.xShutdownDischargeWithInverter AND xSafetyIntlksOk AND (stInverterData.rActDCVoltage > 620.0) THEN
_rPowerInverterInternal := GVL_CONFIG.rAbsShutdownDischargePower;
ELSE
// Send shutdown message
@@ -773,7 +820,7 @@ CASE _iState OF
IF _tonInverterShutdownDelay.Q THEN
_tonInverterShutdownDelay(IN := FALSE);
xCloseDCCB := FALSE;
eStatus := E_COMPONENT_STATUS.OFF;
//eStatus := E_COMPONENT_STATUS.OFF;
_iState := 0;
END_IF
@@ -785,7 +832,7 @@ CASE _iState OF
51: // Check if start balancing has been releases to avoid a restart
IF (NOT xStartBalancing) THEN
eStatus := E_COMPONENT_STATUS.OFF;
//eStatus := E_COMPONENT_STATUS.OFF;
_iState := 0;
END_IF
@@ -801,7 +848,7 @@ CASE _iState OF
_tonResetPulseLength(IN := FALSE);
_tonErrorDCCBNotClosed(IN := FALSE);
eStatus := E_COMPONENT_STATUS.ERROR;
//eStatus := E_COMPONENT_STATUS.ERROR;
_iState := 1005;
@@ -821,7 +868,7 @@ CASE _iState OF
// Leave error state only if modules are deactivated
IF (NOT xEnable) AND (NOT _xModuleError) THEN
xError := FALSE;
eStatus := E_COMPONENT_STATUS.OFF;
//eStatus := E_COMPONENT_STATUS.OFF;
_iState := 0;
END_IF
END_CASE

View File

@@ -10,7 +10,7 @@ VAR_INPUT
stHMIInterface : REFERENCE TO ST_UNIT_HMI_INTERFACE;
// Components shortage workaround
xVoltageSensorIs1500V : BOOL;
// xVoltageSensorIs1500V : BOOL;
// Start unit
xEnable : BOOL;
@@ -50,7 +50,7 @@ VAR_INPUT
END_VAR
VAR_OUTPUT
// Unit state
eUnitState : E_COMPONENT_STATUS := E_COMPONENT_STATUS.OFF;
//eUnitState : E_COMPONENT_STATUS := E_COMPONENT_STATUS.OFF;
// Unit ready
xReady : BOOL;
@@ -70,9 +70,6 @@ VAR_OUTPUT
// Warning active
xWarning : BOOL;
// Warning confirmation still pending
_xWarningConfirmPending : BOOL;
// Current Unit voltage
rCurrentVoltage : REAL;
@@ -219,6 +216,9 @@ VAR
// Filtered pressure sensor posolyt tank inlet data for HMI
_rFilteredPressNegolytTank : REAL;
// Pumps ready
_xPumpsReady : BOOL;
// Indicate if it ise the first cycle
xFirstCycle : BOOL := TRUE;
END_VAR
@@ -442,6 +442,7 @@ IF NOT stHMIInterface.stNS21.stInterlock.xSafetyINTLKOk THEN
xSafetyIntlksOk := FALSE;
END_IF
_xPumpsReady := stHMIInterface.stNS21.stInterlock.xProcessINTLKOk AND stHMIInterface.stNS21.stInterlock.xSafetyINTLKOk AND stHMIInterface.stNS11.stInterlock.xProcessINTLKOk AND stHMIInterface.stNS11.stInterlock.xSafetyINTLKOk;
// ===============================
// Pressure sensor posolyt segment inlet
@@ -602,29 +603,16 @@ END_IF
// ===============================
// Voltage segment
// ===============================
IF xVoltageSensorIs1500V THEN
_fbVoltageSegment(
stScalingConfig:= GVL_CONFIG.stConfigVoltageSegment1500,
stEWConfig:= GVL_CONFIG.stUnitConfig.stEWLVoltageSegment,
stEWDelayConfig:= GVL_CONFIG.stUnitConfig.stEWDVoltageSegment,
xReleaseErrors:= xReleaseErrors,
xReleaseLimitErrors:= xReleaseLimitErrors AND _xEnableVoltageLimitChecks,
xReleaseHardwareErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface=> stHMIInterface.stE31,
rScaledValue => rCurrentVoltage);
ELSE
_fbVoltageSegment(
stScalingConfig:= GVL_CONFIG.stUnitConfig.stConfigVoltageSegment,
stEWConfig:= GVL_CONFIG.stUnitConfig.stEWLVoltageSegment,
stEWDelayConfig:= GVL_CONFIG.stUnitConfig.stEWDVoltageSegment,
xReleaseErrors:= xReleaseErrors,
xReleaseLimitErrors:= xReleaseLimitErrors AND _xEnableVoltageLimitChecks,
xReleaseHardwareErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface=> stHMIInterface.stE31,
rScaledValue => rCurrentVoltage);
END_IF
_fbVoltageSegment(
stScalingConfig:= GVL_CONFIG.stUnitConfig.stConfigVoltageSegment,
stEWConfig:= GVL_CONFIG.stUnitConfig.stEWLVoltageSegment,
stEWDelayConfig:= GVL_CONFIG.stUnitConfig.stEWDVoltageSegment,
xReleaseErrors:= xReleaseErrors,
xReleaseLimitErrors:= xReleaseLimitErrors AND _xEnableVoltageLimitChecks,
xReleaseHardwareErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface=> stHMIInterface.stE31,
rScaledValue => rCurrentVoltage);
// Set error active if fb has error
IF _fbVoltageSegment.xError THEN
@@ -637,6 +625,14 @@ IF _fbVoltageSegment.xWarning THEN
END_IF
// ===============================
// Check for EStop
// ===============================
IF (NOT xEmergencyStopOk) THEN
_xErrorActive := TRUE;
END_IF
// ===============================
// Write Voltage to HMI
// ===============================
@@ -696,6 +692,8 @@ _rShutdownDischargeVoltageThreshold := GVL_CONFIG.rMinimumUnitVoltage + GVL_CONF
// ===============================
// Run state machine for startup
// and shutdown
// NEEDS TO BE CALLED AFTER ALL COMPONENTS BECAUSE OF RESET AND ALARM ACKNOWLEDGEMENT!!!
// (e.g. restart pumps after estop if segment voltage is still to high)
// ===============================
StateMachine();
@@ -783,7 +781,7 @@ CASE _iState OF
_xReleaseManualMode := FALSE;
_timUnitStartupWaitTime := GVL_CONFIG.timUnitStartupTime;
_iState := 10;
eUnitState := E_COMPONENT_STATUS.STARTING;
stHMIInterface.eStatus := E_COMPONENT_STATUS.STARTING;
END_IF
// Start in balancing mode
@@ -793,6 +791,10 @@ CASE _iState OF
_timUnitStartupWaitTime := GVL_CONFIG.timUnitBalancingStartupTime;
_iState := 10;
END_IF
IF _xErrorActive THEN
_iState := 1000;
END_IF
10: // Open all valves
_fbPosolytValveTankOutlet.ReqAutomaticOpen();
@@ -809,7 +811,7 @@ CASE _iState OF
// If enable signal is lost
IF ((NOT xEnable) AND (NOT xStartBalancing)) THEN
eUnitState := E_COMPONENT_STATUS.SHUTDOWN;
stHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40;
END_IF
@@ -818,6 +820,10 @@ CASE _iState OF
_xReleaseManualMode := TRUE;
_iState := 1000;
END_IF
IF (NOT xEnable) THEN
_iState := 51;
END_IF
20: // Start pumps
_fbPosolytPumpInlet.ReqAutomaticStart();
@@ -835,7 +841,7 @@ CASE _iState OF
// If enable signal is lost, goto shutdown
IF ((NOT xEnable) AND (NOT xStartBalancing)) THEN
eUnitState := E_COMPONENT_STATUS.SHUTDOWN;
stHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40; // 40
END_IF
@@ -859,7 +865,7 @@ CASE _iState OF
// If enable signal is lost, goto shutdown
IF (NOT xEnable) AND (NOT xStartBalancing) THEN
eUnitState := E_COMPONENT_STATUS.SHUTDOWN;
stHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40;
END_IF
@@ -882,7 +888,7 @@ CASE _iState OF
// Continue on normal startup path
IF xEnable THEN
eUnitState := E_COMPONENT_STATUS.ON;
stHMIInterface.eStatus := E_COMPONENT_STATUS.ON;
_iState := 35;
END_IF
@@ -904,7 +910,7 @@ CASE _iState OF
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytOnPower;
IF (NOT xEnable) THEN
eUnitState := E_COMPONENT_STATUS.SHUTDOWN;
stHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40;
END_IF
@@ -961,6 +967,10 @@ CASE _iState OF
_iState := 0;
END_IF
IF _xErrorActive THEN
_iState := 1000;
END_IF
51: // Discharge without inverter
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower;
@@ -978,6 +988,10 @@ CASE _iState OF
_iState := 0;
END_IF
IF _xErrorActive THEN
_iState := 1000;
END_IF
60: // Disable pumps
_fbPosolytPumpInlet.ReqAutomaticStop();
_fbNegolytPumpInlet.ReqAutomaticStop();
@@ -988,14 +1002,14 @@ CASE _iState OF
xOff := TRUE;
_xReleaseManualMode := TRUE;
IF NOT _xErrorActive THEN
eUnitState := E_COMPONENT_STATUS.OFF;
stHMIInterface.eStatus := E_COMPONENT_STATUS.OFF;
_iState := 0;
END_IF
END_IF
// Check for restart condition
IF xEnable AND (NOT _xErrorActive) THEN
eUnitState := E_COMPONENT_STATUS.OFF;
stHMIInterface.eStatus := E_COMPONENT_STATUS.OFF;
_iState := 0;
END_IF
@@ -1059,6 +1073,9 @@ CASE _iState OF
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower;
_fbNegolytPumpInlet.ReqAutomaticStart();
_fbPosolytPumpInlet.ReqAutomaticStart();
_xEnableVoltageLimitChecks := FALSE;
xShutdownDischargeAllowed := FALSE;
xInShutdownDischargeMode := FALSE;
@@ -1082,9 +1099,12 @@ CASE _iState OF
_iState := 0;
END_IF
IF _xErrorActive THEN
_iState := 1000;
END_IF
1000: // Error shutdown
eUnitState := E_COMPONENT_STATUS.ERROR;
stHMIInterface.eStatus := E_COMPONENT_STATUS.ERROR;
_fbNegolytValveTankOutlet.ReqAutomaticClose();
_fbPosolytValveTankOutlet.ReqAutomaticClose();
_fbPosolytPumpInlet.ReqAutomaticStop();
@@ -1100,10 +1120,22 @@ CASE _iState OF
1001: // Alarm active
// Only allow reset when enable is deactivated to avoid an
// automatic restart of the unit
IF (NOT _xErrorActive) AND (NOT xEnable) AND (NOT xStartBalancing) AND xConfirmAlarms THEN
IF (NOT _xErrorActive) AND (NOT xEnable) AND (NOT xStartBalancing) AND _xPumpsReady AND xConfirmAlarms THEN
xError := FALSE;
_iState := 51;
IF (_fbVoltageSegment.rScaledValue >= GVL_CONFIG.rPumpshutoffThreshold) THEN
_iState := 1002;
ELSE
_iState := 0;
END_IF
END_IF
1002:
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower;
_fbNegolytPumpInlet.ReqAutomaticStart();
_fbPosolytPumpInlet.ReqAutomaticStart();
_iState := 51;
END_CASE]]></ST>
</Implementation>
</Action>

View File

@@ -5,7 +5,6 @@
VAR
_xEmergencyStopOk AT %I* : BOOL;
_xShowAckEmergencyStop AT %Q* : BOOL;
_xString1DCSafetyOk AT %I* : BOOL;
_xReleaseErrors : BOOL := TRUE;
_xReleaseLimitsErrors : BOOL := TRUE;
_xConfirmAlarms : BOOL;
@@ -18,9 +17,12 @@ VAR
_afbStrings : ARRAY[0..1] OF FB_String[('String 1'), ('String 2')];
// Variable to detect charge status change
_eLastChargeStatus : E_CHARGE_STATUS;
//_eLastChargeStatus : E_CHARGE_STATUS;
// Variable to detect battery status change
_eLastBatteryStatus : E_BATTERY_STATUS;
//_eLastBatteryStatus : E_BATTERY_STATUS;
// Battery shutdown due to error
_xErrorShutdown : BOOL := FALSE;
// State machine state
_iState : INT;
@@ -46,7 +48,7 @@ VAR
_tonBeginShutdown : TON := (PT := T#30S);
// Not all strings in automatic mode
_fbNoAutomaticModeAlarm : Fb_TcAlarm;
_fbNoAutomaticModeAlarm : FB_TcAlarm;
// Emergency stop not ok alarm
_fbEStopNotOk : FB_TcAlarm;
@@ -73,11 +75,6 @@ VAR
// Release manual mode
_xReleaseManualMode : BOOL;
// Current internal set inverter power value
_diInternalPowerSetpoint : DINT;
_diSetpointActivePower : DINT;
// Current BMS control mode (Auto local, Auto remote, etc...)
// On restart star in manual mode (so the ems can not directly start the bms)
_eBMSControlMode : E_BMS_CONTROL_MODE := E_BMS_CONTROL_MODE.AUTO_LOCAL;
@@ -86,6 +83,7 @@ VAR
_fbUPS : FB_S_UPS_BAPI;
// Safety
{attribute 'analysis' := '-33'}
xSafetyRun AT %Q* : BOOL := TRUE;
xSafetyErrAck AT %Q* : BOOL;
xSafetyResterTaster AT %I* : BOOL;
@@ -126,8 +124,6 @@ VAR
// DEBUG
_xRestart : BOOL;
_xDebug : BOOL;
_ModbusDebugTest : ST_MODBUS_REG_11;
_fbStringReadyTimeout : TON;
@@ -144,15 +140,21 @@ VAR
_xStringsAllInAutomaticMode : BOOL;
_xStringsOff : BOOL;
_xStringsBalancingDone : BOOL;
_xStringsInAutoMode : BOOL;
_rMaxCurrentInverterDCVoltage : REAL;
_rMinCurrentInverterDCVoltage : REAL;
_fbModbusRead : FB_MBReadRegs;
_wLength : WORD := 49;
//_wLength : WORD := 49;
xDebugTest : BOOL;
_wDebug1 : WORD;
_wDebug2 : WORD;
_fbPowerMeterPower : FB_PowerMeter;
_fbPowerMeter24V : FB_PowerMeter;
_xGetPowerMeterData : BOOL;
END_VAR
]]></Declaration>
<Implementation>
@@ -172,6 +174,7 @@ END_IF
IF _xFirstCycle THEN
_xFirstCycle := FALSE;
_xGetPowerMeterData := TRUE;
_fbBatteryFullMessage.CreateEx(stEventEntry := TC_EVENTS.BMSEvents.BatteryFull, 0);
_fbBatteryEmptyMessage.CreateEx(stEventEntry := TC_EVENTS.BMSEvents.BatteryEmpty, 0);
@@ -299,8 +302,8 @@ _tonStartupDelay(IN := TRUE);
// Call string 1
_afbStrings[0](
stStringModuleVoltageConfig := GVL_CONFIG.stString1VoltageConfig,
xEnable := _xEnableString,
xErrorShutdown := _xErrorShutdown,
xStartBalancing := _xStartBalancing,
sInverterIP := GVL_CONFIG.sInverterIpString1,
rPowerInverter := _arPowerString[0],
@@ -320,8 +323,8 @@ END_IF
// Call string 2
_afbStrings[1](
stStringModuleVoltageConfig := GVL_CONFIG.stString2VoltageConfig,
xEnable := _xEnableString,
xErrorShutdown := _xErrorShutdown,
xStartBalancing := _xStartBalancing,
sInverterIP := GVL_CONFIG.sInverterIpString2,
rPowerInverter := _arPowerString[1],
@@ -353,6 +356,7 @@ _rMaxCurrentInverterDCVoltage := 0.0;
_rMinCurrentInverterDCVoltage := 10_000;
_rHighestSegmentVoltage := 0.0;
_rSmallestSegmentVoltage := 1_000.0;
_xStringsInAutoMode := TRUE;
FOR _ui := 0 TO (GVL_CONFIG.uiNumberOfStrings-1) DO
// Check ready state
@@ -409,6 +413,11 @@ FOR _ui := 0 TO (GVL_CONFIG.uiNumberOfStrings-1) DO
IF _rHighestSegmentVoltage < _afbStrings[_ui].rHighestSegmentVoltage THEN
_rHighestSegmentVoltage := _afbStrings[_ui].rHighestSegmentVoltage;
END_IF
// Get auto mode status
IF NOT _afbStrings[_ui].xAllModulesInAutoMode THEN
_xStringsInAutoMode := FALSE;
END_IF
END_FOR
// ===============================
@@ -489,7 +498,6 @@ FOR _ui := 0 TO (GVL_CONFIG.uiNumberOfStrings-1) DO
END_FOR
// Set Modbus mirror values
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diSetpointActivePowerMirror := GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.rSetpointCosPhiMirror := GVL_MODBUS.stModbusEMSComm.stModbusReg12.rSetpointCosPhi;
@@ -563,7 +571,7 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := FALSE;
_xInSafetyCheckMode := FALSE;
_xReleaseManualMode := FALSE;
IF (_iState <> 30) OR _rAutoPowerRequest = 0.0 THEN
IF (_iState <> 30) OR GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic = 0 THEN
_rAutoPowerRequest := DINT_TO_REAL(GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic);
END_IF
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
@@ -578,8 +586,36 @@ GVL_SCADA.eCurrentControlMode := _eBMSControlMode;
// Calculate current battery dc power
GVL_SCADA.diCurrentBatteryPower := REAL_TO_DINT(_afbStrings[0].stInverterData.rActDCPower + _afbStrings[1].stInverterData.rActDCPower);
// Read power values if commanded
_fbPowerMeterPower(
xGetEnergyCounters:= _xGetPowerMeterData,
sIpAddress:= '192.168.42.75',
lrEnergyFromGrid=> GVL_SCADA.lrChargedPowerValueWH,
lrEnergyIntoGrid=> GVL_SCADA.lrDischargedPowerValueWH,
xBusy=> ,
xError=> );
_fbPowerMeter24V(
xGetEnergyCounters:= _xGetPowerMeterData,
sIpAddress:= '192.168.42.80',
lrEnergyFromGrid=> GVL_SCADA.lrLastCycleUtilityPowerValueWh,
lrEnergyIntoGrid=> ,
xBusy=> ,
xError=> );
IF _xGetPowerMeterData THEN
_xGetPowerMeterData := FALSE;
END_IF
// Call safety fb
_fbSafety();
// Check if all modules are in auto mode
IF _xStringsInAutoMode AND _fbNoAutomaticModeAlarm.bRaised THEN
_fbNoAutomaticModeAlarm.Clear(0, TRUE);
END_IF
// Reset automatic buttons
IF GVL_SCADA.stAutomaticModeHMI.stStartAutoButton.xRequest THEN
GVL_SCADA.stAutomaticModeHMI.stStartAutoButton.xRequest := FALSE;
@@ -591,16 +627,24 @@ END_IF
// Reset alarm confirmation
IF _xConfirmAlarms OR _rtHardwareResetButton.Q THEN
_xConfirmAlarms := FALSE;
END_IF]]></ST>
END_IF
_fbPowerMeter24V();]]></ST>
</Implementation>
<Action Name="SM_AUTO" Id="{b5166e16-4fea-442b-9560-02c156f9a9ad}">
<Implementation>
<ST><![CDATA[CASE _iState OF
0: // Idle
// Check for all in auto mode
IF (NOT _xStringsInAutoMode) AND (NOT _fbNoAutomaticModeAlarm.bRaised) THEN
_fbNoAutomaticModeAlarm.Raise(0);
END_IF
// Wait for power command
IF (ABS(_rAutoPowerRequest) > DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) AND (NOT _xStringsErrorActive) AND _xStringsAllInAutomaticMode THEN
_iState := 5;
_xCanChangeMode := FALSE;
_xErrorShutdown := FALSE;
END_IF
5: // Check if power command is within limits
@@ -621,8 +665,12 @@ END_IF]]></ST>
_fbStringReadyTimeout(IN := TRUE, PT := GVL_CONFIG.timStringReadyTimeout);
IF _xStringsReady AND (NOT _xStringsErrorActive) THEN
_xGetPowerMeterData := TRUE;
_fbStringReadyTimeout(IN := FALSE);
_rPowerInverter := 0.0;
// Set active parallel members (modbus)
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := GVL_CONFIG.uiNumberOfStrings;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.ACTIVE;
_iState := 30;
END_IF
@@ -656,10 +704,13 @@ END_IF]]></ST>
// Set battery status
IF _rAutoPowerRequest > 0 THEN
GVL_SCADA.eCycleStatus := E_CYCLE_STATUS.DISCHARGE_STARTED;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.DISCHARGING;
ELSIF _rAutoPowerRequest < 0 THEN
GVL_SCADA.eCycleStatus := E_CYCLE_STATUS.CHARGE_STARTED;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.CHARGING;
ELSE
GVL_SCADA.eCycleStatus := E_CYCLE_STATUS.OFF;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.UNDEFINED;
END_IF
@@ -670,6 +721,12 @@ END_IF]]></ST>
IF _tonBeginShutdown.Q THEN
_tonBeginShutdown(In := FALSE);
IF _rPowerInverter < 0 THEN
GVL_SCADA.eCycleStatus := E_CYCLE_STATUS.CHARGE_ENDED;
ELSIF _rPowerInverter > 0 THEN
GVL_SCADA.eCycleStatus := E_CYCLE_STATUS.DISCHARGE_ENDED;
END_IF
// Set inverter to zero power
_rPowerInverter := 0.0;
@@ -682,11 +739,11 @@ END_IF]]></ST>
// 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
_xGetPowerMeterData := TRUE;
IF (_eBMSControlMode = E_BMS_CONTROL_MODE.CYCLING) THEN
GVL_SCADA.eCycleStatus := E_CYCLE_STATUS.DISCHARGE_STARTED;
_rAutoPowerRequest := _rAutoPowerRequest * -1;
// Change of charge discharge should be handled in next cycle by same state
// GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.DISCHARGING;
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := REAL_TO_DINT(_rAutoPowerRequest);
ELSE
_tonBeginShutdown(In := FALSE);
@@ -712,10 +769,11 @@ END_IF]]></ST>
// Shutdown triggered by battery empty
IF GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus = E_CHARGE_STATUS.DISCHARGING AND ((_rMinCurrentInverterDCVoltage <= GVL_CONFIG.rStringEmptyVoltage) OR _rSmallestSegmentVoltage <= GVL_CONFIG.rMinimumUnitVoltage) THEN
_xGetPowerMeterData := TRUE;
IF (_eBMSControlMode = E_BMS_CONTROL_MODE.CYCLING) THEN
GVL_SCADA.eCycleStatus := E_CYCLE_STATUS.CHARGE_STARTED;
_rAutoPowerRequest := _rAutoPowerRequest * -1;
// Change of charge discharge should be handled in next cycle by same state
// GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.CHARGING;
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := REAL_TO_DINT(_rAutoPowerRequest);
ELSE
_tonBeginShutdown(In := FALSE);
@@ -741,6 +799,7 @@ END_IF]]></ST>
// Check for errors
IF _xStringsErrorActive THEN
_xEnableString := FALSE;
_xErrorShutdown := TRUE;
_tonBeginShutdown(In := FALSE);
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
_xCanChangeMode := TRUE;
@@ -757,12 +816,15 @@ END_IF]]></ST>
_xEnableString := FALSE;
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
_xCanChangeMode := TRUE;
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.OFF;
_iState := 45;
END_IF
END_IF
// Check for errors
IF _xStringsErrorActive THEN
_xErrorShutdown := TRUE;
_iState := 1000;
END_IF
@@ -770,6 +832,8 @@ END_IF]]></ST>
IF _xStringsShutdownDischargeAllowed THEN
_rPowerInverter := GVL_CONFIG.rAbsShutdownDischargePower;
ELSE
_xGetPowerMeterData := TRUE;
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
_rPowerInverter := 0.0;
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
_xEnableString := FALSE;
@@ -779,6 +843,7 @@ END_IF]]></ST>
// Check for errors
IF _xStringsErrorActive THEN
_xErrorShutdown := TRUE;
_iState := 1000;
END_IF
@@ -791,6 +856,7 @@ END_IF]]></ST>
IF (NOT _xStringsInSchutdownDischargeMode) AND _xStringsOff THEN
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.OFF;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.UNDEFINED;
GVL_SCADA.eCycleStatus := E_CYCLE_STATUS.OFF;
_iState := 0;
END_IF
@@ -802,11 +868,13 @@ END_IF]]></ST>
// Check for errors
IF _xStringsErrorActive THEN
_xErrorShutdown := TRUE;
_iState := 1000;
END_IF
1000: // Error state
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
_xEnableString := FALSE;
_rPowerInverter := 0.0;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.ERROR;
@@ -820,6 +888,9 @@ END_IF]]></ST>
// Reset modbus error flag
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.OFF;
// Reset error shutdown flag
_xErrorShutdown := FALSE;
// Goto init state
_iState := 0;

View File

@@ -6,7 +6,7 @@ VAR_INPUT
sInverterIPAddr : STRING;
xEnable : BOOL;
rPower : REAL;
rReactivePower : REAL := 0.0;
//rReactivePower : REAL := 0.0;
xReset : BOOL;
rMaxBattPower : REAL := 40_000; // 24kW
END_VAR
@@ -34,7 +34,7 @@ VAR
_fbWriteRegister : FB_MBWriteRegs;
// Timer for checking if the inverter started in a reasonable amount of time
_tonInverterStartup : TON;
//_tonInverterStartup : TON;
// converter max power scaling factor
_iWMaxSF : INT;
@@ -52,17 +52,17 @@ VAR
_iVarPctSF : INT;
// Reread set power limit
_iWMaxLimPctRead : INT;
_rWMaxLimPctReadScaled : REAL;
//_iWMaxLimPctRead : INT;
//_rWMaxLimPctReadScaled : REAL;
// Scaling factor for power limiting
_iWMaxLimPctSF : INT;
// Unscaled maximum power from type label
_iWRTGSF : INT;
//_iWRTGSF : INT;
// Scaling for maximum power from type label
_rWRTGScaling : REAL;
//_rWRTGScaling : REAL;
// Current state of the inverters internal statemachine
_uiInverterState : UINT;
@@ -121,6 +121,9 @@ VAR
_sName : STRING;
_uiSetPowerLimitErrorCounter : UINT;
_uiLastSetPowerLimitErrorCounter : UINT;
END_VAR
VAR CONSTANT
// Inverter statemachine status register
@@ -157,11 +160,11 @@ VAR CONSTANT
// Maximum inverter output power from type label
// Size 1, uint16 (Range = 0 .. 65534, Not implemented = 0xFFFF)
W_RTG_REGISTER : WORD := 40125;
//W_RTG_REGISTER : WORD := 40125;
// Maximum inverter output power from type label scaling factor
// Size 1, sunssf (int16) (Range = -10 .. 10, Not implemented 0x8000)
W_RTG_SF_REGISTER : WORD := 40126;
//W_RTG_SF_REGISTER : WORD := 40126;
// Start of register with the current dc values
// Size 4
@@ -229,9 +232,6 @@ CASE _iState OF
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
END_IF
1: // Read inverter status
_fbReadRegister(
sIPAddr:= sInverterIPAddr,
@@ -631,18 +631,30 @@ CASE _iState OF
_iState := 50;
_rOldPower := rPower;
_uiMaxLimEn := 1;
_uiLastSetPowerLimitErrorCounter := _uiSetPowerLimitErrorCounter;
_uiSetPowerLimitErrorCounter := 0;
// Calculate reactive power setting
//_iMaxPowerVar := LREAL_TO_INT((rReactivePower*100)/(_iMaxPowerVar * EXPT(10,_iVarPctSF)));
ELSE
xError := TRUE;
// Goto error state
_iState := 1000;
_uiSetPowerLimitErrorCounter := _uiSetPowerLimitErrorCounter + 1;
IF _uiSetPowerLimitErrorCounter > 5 THEN
// Goto error state
_iState := 1000;
ELSE
_iState := 41;
END_IF
END_IF
_fbWriteRegister(bExecute := FALSE);
END_IF
41: // Retry send power limit delay
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
IF _tonPollingTimer.Q THEN
_tonPollingTimer(IN := FALSE);
_iState := 40;
END_IF
41: // Set max reactive power in percent
42: // Set max reactive power in percent
_iErrorInState := _iState;
_fbWriteRegister(
sIPAddr:= sInverterIPAddr,
@@ -672,7 +684,7 @@ CASE _iState OF
END_IF
42: // Enable reactive power percent limiting
43: // Enable reactive power percent limiting
_iErrorInState := _iState;
_fbWriteRegister(
sIPAddr:= sInverterIPAddr,
@@ -799,7 +811,7 @@ CASE _iState OF
_iState := 70;
ELSIF (ABS(rPower - _rOldPower) > 0.1) THEN
//_tonPollingTimer(IN := FALSE);
// If power has ben changed, goto set power limit mode
// If power has been changed, goto set power limit mode
_iState := 40;
// Calculate power to write to register
_iWMaxLimPct := LREAL_TO_INT((rPower*100)/(_rWMax * EXPT(10,_iWMaxLimPctSF)));
@@ -833,7 +845,7 @@ CASE _iState OF
// Check if reading mudbus register is done
IF NOT _fbReadRegister.bBusy THEN
// If there was no error and the converter has no error continue
IF NOT _fbReadRegister.bError AND (_uiInverterState <> 7) THEN
IF (NOT _fbReadRegister.bError) AND (_uiInverterState <> 7) THEN
_iState := 80;
IF (_uiInverterState = 4) OR (_uiInverterState = 5) THEN
xActive := TRUE;
@@ -842,6 +854,7 @@ CASE _iState OF
END_IF
ELSE
xError := TRUE;
xActive := FALSE;
_uiPCSSetOperation := 3;
// Read error register
_iState := 200;