Files
Uniper_PLC/PLC/POUs/FB_Unit.TcPOU
2025-04-14 19:38:17 +02:00

1301 lines
38 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1" ProductVersion="3.1.4026.12">
<POU Name="FB_Unit" Id="{e9bb815b-eb46-4920-800d-910484e58b22}" SpecialFunc="None">
<Declaration><![CDATA[FUNCTION_BLOCK FB_Unit
VAR_INPUT
// Unit configuration
stUnitConfig : REFERENCE TO ST_UNIT_CONFIG;
// HMI interface
stHMIInterface : REFERENCE TO ST_UNIT_HMI_INTERFACE;
// Components shortage workaround
// xVoltageSensorIs1500V : BOOL;
// Start unit
xEnable : BOOL;
// Star balancing
xStartBalancing : BOOL;
// Unit in safety check mode
xInSafetyCheckMode : BOOL;
// Emergency stop ok
xEmergencyStopOk : BOOL;
// All safetyinterlocks are ok
xSafetyIntlksOk : BOOL;
// Release alarms
xReleaseErrors : BOOL;
// Release analog io limit errors
xReleaseLimitErrors : BOOL;
// Release manual mode
xReleaseManualMode : BOOL;
// Input to confirm all errors
xConfirmAlarms : BOOL;
// Balancing target Voltage
rBalancingTargetVoltage : REAL;
// Switch all components to manual mode
xAllToManualMode : BOOL;
// Inverter enabled status
xInverterEnabled : BOOL;
END_VAR
VAR_IN_OUT
// Modbus warning register
stModbusWarnings : U_UNIT_WARNING_REGISTER;
// Modbus error register
stModbusErrors : U_UNIT_ERROR_REGISTER;
END_VAR
VAR_OUTPUT
// Unit state
//eUnitState : E_COMPONENT_STATUS := E_COMPONENT_STATUS.OFF;
// Unit ready
xReady : BOOL;
// Unit completely off
xOff : BOOL := TRUE;
// Unit can be discharged during shutdown sequence
xShutdownDischargeAllowed : BOOL;
// Unit in shutdown segment discharge mode
xInShutdownDischargeMode : BOOL;
// Error active
xError : BOOL;
// Warning active
xWarning : BOOL;
// Current Unit voltage
rCurrentVoltage : REAL;
// All components in automatic mode
xAllComponentsInAuto : BOOL;
// Balancing done
xBalancingDone : BOOL;
// Reset MCB
xResetMCB AT %Q* : BOOL;
END_VAR
VAR
// Check unit condition after some time during startup
_timUnitStartupWaitTime : TIME := T#1M;
// Valves posolyt
_fbPosolytValveTankOutlet : FB_Valve(CONCAT(_sName, ' - Posolyt tank outlet'));
// Valves negolyt
_fbNegolytValveTankOutlet : FB_Valve(CONCAT(_sName, ' - Negolyt tank outlet'));
// Pumps posolyt
_fbPosolytPumpInlet : FB_MotorAnalog(CONCAT(_sName, ' - Posolyt segment inlet'));
// Pumps negolyt
_fbNegolytPumpInlet : FB_MotorAnalog(CONCAT(_sName, ' - Negolyt segment inlet'));
// Pressure sensors posolyt
_fbPressurePosolytSegmentInlet : FB_AnalogInput(CONCAT(_sName, ' - P1_P'));
_fbPressurePosolytTankInlet : FB_AnalogInput(CONCAT(_sName, ' - P3_P'));
// Pressure sensors negolyt
_fbPressureNegolytSegmentInlet : FB_AnalogInput(CONCAT(_sName, ' - P1_N'));
_fbPressureNegolytTankInlet : FB_AnalogInput(CONCAT(_sName, ' - P3_N'));
// Temperature sensor posolyt
_fbTempSensorPosolyt : FB_AnalogInput(CONCAT(Name, ' - T1_P'));
// Temperature sensor negolyt
_fbTempSensorNegolyt : FB_AnalogInput(CONCAT(Name, ' - T1_N'));
// Unit voltage
_fbVoltageSegment : FB_AnalogInput('Voltage');
// Valve posolyt tank outlet interlocks
_stPosolytValveTankOutletPIntlk : T_INTERLOCK;
_stPosolytValveTankOutletPIntlkUsed : T_INTERLOCK := 2#0000_0000_0000_0000;
_stPosolytValveTankOutletSIntlk : T_INTERLOCK;
_stPosolytValveTankOutletSIntlkUsed : T_INTERLOCK := 2#0000_0000_0000_0001;
// Valve negolyt tank outlet interlocks
_stNegolytValveTankOutletPIntlk : T_INTERLOCK;
_stNegolytValveTankOutletPIntlkUsed : T_INTERLOCK := 2#0000_0000_0000_0000;
_stNegolytValveTankOutletSIntlk : T_INTERLOCK;
_stNegolytValveTankOutletSIntlkUsed : T_INTERLOCK := 2#0000_0000_0000_0001;
// Pump posolyt inlet interlocks
_stPosolytPumpInletPIntlk : T_INTERLOCK;
_stPosolytPumpInletPIntlkUsed : T_INTERLOCK := 2#0000_0000_0000_0001;
_stPosolytPumpInletSIntlk : T_INTERLOCK;
_stPosolytPumpInletSIntlkUsed : T_INTERLOCK := 2#0000_0000_0000_0001;
// Pump negolyt inlet interlocks
_stNegolytPumpInletPIntlk : T_INTERLOCK;
_stNegolytPumpInletPIntlkUsed : T_INTERLOCK := 2#0000_0000_0000_0001;
_stNegolytPumpInletSIntlk : T_INTERLOCK;
_stNegolytPumpInletSIntlkUsed : T_INTERLOCK := 2#0000_0000_0000_0001;
// Error active
_xErrorActive : BOOL;
// Warning active
_xWarningActive : BOOL;
// Shutdown discharge allowed voltage
_rShutdownDischargeVoltageThreshold : REAL;
// Current state
_iState: INT;
// All components in automatic mode
_xAllComponentsInAutomatic : BOOL;
// Not all components in automatic mode alarm
_fbNotAllAutomaticAlarm : FB_TcAlarm;
// Pressure difference between pos and neg inlet to big
_fbPressureDiffToBig : FB_TcAlarm;
// General unit error
_fbUnitError : FB_TcAlarm;
// Unit name
_sName : STRING;
// Unit startup check timer
_tonStartupCheck : TON;
// Enable voltage limit checks
_xEnableVoltageLimitChecks : BOOL;
// Manual mode allowed flag
_xReleaseManualMode : BOOL;
_xReleaseSignalDeltaPSegment : FB_ReleaseSignal;
_xDeltaPSegmentInletToHigh : BOOL;
_xEnableCheckForDeltaPSegmentInlet : BOOL;
_xErrorDeltaPSegmentInlet : BOOL;
// Setpoint posolyt pump inlet
_rSetpointPosolytPumpInlet : REAL;
// Setpoint negolyt pump inlet
_rSetpointNegolytPumpInlet : REAL;
// Timer for resetting the MCB (minimum on time 0,5s)
_tofResetMCB : TOF := (PT := T#0.75S);
// Timeout Voltage not reached
_tonVoltageCheckTimeput : TON := (PT := T#2M);
// Freezed balancing target voltage
_rBalancingTargetVoltage : REAL;
// Trigger for switching to manual mode
_rtrigSwitchToManualMode : R_TRIG;
// Trigger for switching to automatic mode
_rtrigSwitchToAutoMode : R_TRIG;
_tonManualMode : TON;
// Filtered pressure sensor posolyt segment inlet data for HMI
_rFilteredPressPosolytInlet : REAL;
// Filtered pressure sensor posolyt segment inlet data for HMI
_rFilteredPressNegolytInlet : REAL;
// Filtered pressure sensor posolyt tank inlet data for HMI
_rFilteredPressPosolytTank : REAL;
// 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
]]></Declaration>
<Implementation>
<ST><![CDATA[IF xFirstCycle THEN
_fbPosolytValveTankOutlet.Name := CONCAT(_sName, ' - Posolyt tank outlet');
stHMIInterface.stNS12.sName := 'Posolyt tank outlet';
_fbNegolytValveTankOutlet.Name := CONCAT(_sName, ' - Negolyt tank outlet');
stHMIInterface.stNS22.sName := 'Negolyt tank outlet';
_fbPosolytPumpInlet.Name := CONCAT(_sName, ' - Posolyt segment inlet');
stHMIInterface.stNS11.sName := 'Posolyt segment inlet';
_fbNegolytPumpInlet.Name := CONCAT(_sName, ' - Negolyt segment inlet');
stHMIInterface.stNS21.sName := 'Negolyt segment inlet';
_fbPressurePosolytSegmentInlet.Name := CONCAT(_sName, ' - Pressure Posolyt Segment Inlet');
_fbPressurePosolytTankInlet.Name := CONCAT(_sName, ' - Pressure Posolyt Tank inlet');
_fbPressureNegolytSegmentInlet.Name := CONCAT(_sName, ' - Pressure Negolyt Segment Inlet');
_fbPressureNegolytTankInlet.Name := CONCAT(_sName, ' - Pressure Negolyt Tank Inlet');
_fbTempSensorPosolyt.Name := CONCAT(_sName, ' - Temperature Posolyt Tank Inlet');
_fbTempSensorNegolyt.Name := CONCAT(_sName, ' - Temperature Negolyt Tank Inlet');
_fbVoltageSegment.Name := CONCAT(_sName, ' - Voltage');
_fbUnitError.ipArguments.Clear().AddString(_sName);
_fbPressureDiffToBig.CreateEx(stEventEntry := TC_EVENTS.General.PressureDiffToBig, TRUE, 0);
_fbPressureDiffToBig.ipArguments.Clear().AddString(_sName);
xFirstCycle := FALSE;
END_IF
// Manual mode trigger
_tonManualMode(IN := (xAllToManualMode AND xReleaseManualMode), PT := T#10S);
_rtrigSwitchToManualMode(CLK := _tonManualMode.Q);
IF _rtrigSwitchToManualMode.Q THEN
_fbPosolytValveTankOutlet.ReqManualMode();
_fbNegolytValveTankOutlet.ReqManualMode();
_fbPosolytPumpInlet.ReqManualMode();
_fbNegolytPumpInlet.ReqManualMode();
END_IF
// Auto mode trigger
_rtrigSwitchToAutoMode(CLK := (NOT _tonManualMode.Q));
IF _rtrigSwitchToAutoMode.Q THEN
_fbPosolytValveTankOutlet.ReqAutomaticMode();
_fbNegolytValveTankOutlet.ReqAutomaticMode();
_fbPosolytPumpInlet.ReqAutomaticMode();
_fbNegolytPumpInlet.ReqAutomaticMode();
END_IF
// Reset MCB logic
_tofResetMCB(IN := xConfirmAlarms);
xResetMCB := _tofResetMCB.Q;
// Reset error active
_xErrorActive := FALSE;
// Reset warning active
_xWarningActive := FALSE;
// Reset safety interlocks flag
xSafetyIntlksOk := TRUE;
// Copy release manual mode
_xReleaseManualMode := xReleaseManualMode;
// ===============================
// Valve posolyt tank outlet
// ===============================
// Safety Interlocks
stHMIInterface.stNS12.stInterlock.asSafetyINTLKName[0] := 'Emergency stop ok';
_stPosolytValveTankOutletSIntlk.0 := xEmergencyStopOk;
// Valve fb
_fbPosolytValveTankOutlet(
xReleaseManualMode:= _xReleaseManualMode,
wProcessINTLK:= _stPosolytValveTankOutletPIntlk,
wProcessINTLKUsed:= _stPosolytValveTankOutletPIntlkUsed,
wSafetyINTLK:= _stPosolytValveTankOutletSIntlk,
wSafetyINTLKUsed:= _stPosolytValveTankOutletSIntlkUsed,
xConfirmAlarms:= xConfirmAlarms,
xReleaseErrors:= xReleaseErrors,
stValveConfig:= stUnitConfig.stConfigPosolytValve,
stHMIInterface:= stHMIInterface.stNS12);
// Set error active if fb has error
IF _fbPosolytValveTankOutlet.xError THEN
stModbusErrors.stBitmap.bValvePos := 1;
_xErrorActive := TRUE;
END_IF
// Set safety interlock flag if fb has safety interlocks active
IF NOT stHMIInterface.stNS12.stInterlock.xSafetyINTLKOk THEN
xSafetyIntlksOk := FALSE;
END_IF
// ===============================
// Valve negolyt tank outlet
// ===============================
// Safety Interlocks
stHMIInterface.stNS22.stInterlock.asSafetyINTLKName[0] := 'Emergency stop ok';
_stNegolytValveTankOutletSIntlk.0 := xEmergencyStopOk;
// Valve fb
_fbNegolytValveTankOutlet(
xReleaseManualMode:= _xReleaseManualMode,
wProcessINTLK:= _stNegolytValveTankOutletPIntlk,
wProcessINTLKUsed:= _stNegolytValveTankOutletPIntlkUsed,
wSafetyINTLK:= _stNegolytValveTankOutletSIntlk,
wSafetyINTLKUsed:= _stNegolytValveTankOutletSIntlkUsed,
xConfirmAlarms:= xConfirmAlarms,
xReleaseErrors:= xReleaseErrors,
stValveConfig:= stUnitConfig.stConfigNegolytValve,
stHMIInterface:= stHMIInterface.stNS22);
// Set error active if fb has error
IF _fbNegolytValveTankOutlet.xError THEN
stModbusErrors.stBitmap.bValveNeg := 1;
_xErrorActive := TRUE;
END_IF
// Set safety interlock flag if fb has safety interlocks active
IF NOT stHMIInterface.stNS22.stInterlock.xSafetyINTLKOk THEN
xSafetyIntlksOk := FALSE;
END_IF
// ===============================
// Pump posolyt segment inlet
// ===============================
// Safety Interlocks
stHMIInterface.stNS11.stInterlock.asSafetyINTLKName[0] := 'Emergency stop ok';
_stPosolytPumpInletSIntlk.0 := xEmergencyStopOk;
// Process interlocks
stHMIInterface.stNS21.stInterlock.asProcessINTLKName[0] := 'Negolyt Pump Error';
_stPosolytPumpInletPIntlk.0 := NOT _fbNegolytPumpInlet.xError;
// Pump fb
_fbPosolytPumpInlet(
xReleaseManualMode:= _xReleaseManualMode,
wProcessINTLK:= _stPosolytPumpInletPIntlk,
wProcessINTLKUsed:= _stPosolytPumpInletPIntlkUsed,
wSafetyINTLK:= _stPosolytPumpInletSIntlk,
wSafetyINTLKUsed:= _stPosolytPumpInletSIntlkUsed,
xReleaseErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
rSPautomatic:= _rSetpointPosolytPumpInlet,
xReleaseAnalogInLimitErrors:= xReleaseLimitErrors AND GVL_SCADA.xDummy,
stMotorAnalogConfig:= stUnitConfig.stConfigPosolytPump,
stHMIInterface:= stHMIInterface.stNS11,
xWarning=> );
// Set error active if fb has error
IF _fbPosolytPumpInlet.xError THEN
stModbusErrors.stBitmap.bPumpPos := 1;
_xErrorActive := TRUE;
END_IF
// Set warning if fb has warning
IF _fbPosolytPumpInlet.xWarning THEN
_xWarningActive := TRUE;
END_IF
// Set safety interlock flag if fb has safety interlocks active
IF NOT stHMIInterface.stNS11.stInterlock.xSafetyINTLKOk THEN
xSafetyIntlksOk := FALSE;
END_IF
// ===============================
// Pump negolyt segment inlet
// ===============================
// Safety Interlocks
stHMIInterface.stNS21.stInterlock.asSafetyINTLKName[0] := 'Emergency stop ok';
_stNegolytPumpInletSIntlk.0 := xEmergencyStopOk;
// Process interlocks
stHMIInterface.stNS11.stInterlock.asProcessINTLKName[0] := 'Posolyt Pump Error';
_stNegolytPumpInletPIntlk.0 := NOT _fbPosolytPumpInlet.xError;
// Pump fb
_fbNegolytPumpInlet(
xReleaseManualMode:= _xReleaseManualMode,
wProcessINTLK:= _stNegolytPumpInletPIntlk,
wProcessINTLKUsed:= _stNegolytPumpInletPIntlkUsed,
wSafetyINTLK:= _stNegolytPumpInletSIntlk,
wSafetyINTLKUsed:= _stNegolytPumpInletSIntlkUsed,
xReleaseErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
rSPautomatic:= _rSetpointNegolytPumpInlet,
xReleaseAnalogInLimitErrors:= xReleaseLimitErrors AND GVL_SCADA.xDummy,
stMotorAnalogConfig:= stUnitConfig.stConfigNegolytPump,
stHMIInterface:= stHMIInterface.stNS21,
xWarning=> );
// Set error active if fb has error
IF _fbNegolytPumpInlet.xError THEN
stModbusErrors.stBitmap.bPumpNeg := 1;
_xErrorActive := TRUE;
END_IF
// Set warning if fb has warning
IF _fbNegolytPumpInlet.xWarning THEN
_xWarningActive := TRUE;
END_IF
// Set safety interlock flag if fb has safety interlocks active
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
// ===============================
_fbPressurePosolytSegmentInlet(
stScalingConfig:= stUnitConfig.stConfigPosolytPressureSegmentInlet,
stEWConfig:= stUnitConfig.stEWLPosolytPressureSegmentInlet,
stEWDelayConfig:= stUnitConfig.stEWDPosolytPressureSegmentInlet,
xReleaseErrors:= xReleaseErrors,
xReleaseLimitErrors:= xReleaseLimitErrors AND _fbPosolytPumpInlet.IsRunning AND _fbPosolytPumpInlet.xInTarget AND (NOT xStartBalancing) AND (_fbPosolytPumpInlet.rSPautomatic > 40),
xReleaseHardwareErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface => stHMIInterface.stP11);
// Filter pressure sensor data for HMI
_rFilteredPressPosolytInlet := _rFilteredPressPosolytInlet * 0.9 + stHMIInterface.stP11.rValue * 0.1;
stHMIInterface.stP11.rValue := _rFilteredPressPosolytInlet;
// Set modbus error register bits
IF _fbPressurePosolytSegmentInlet.xErrorLow THEN
stModbusErrors.stBitmap.bPInPosLow := 1;
END_IF
IF _fbPressurePosolytSegmentInlet.xErrorHigh THEN
stModbusErrors.stBitmap.bPInPosHigh := 1;
END_IF
IF _fbPressurePosolytSegmentInlet.xError THEN
stModbusErrors.stBitmap.bPInPosError := 1;
END_IF
// Set modbus warning register bits
IF _fbPressurePosolytSegmentInlet.xWarningLow THEN
stModbusWarnings.stBitmap.bPInPosLow := 1;
END_IF
IF _fbPressurePosolytSegmentInlet.xWarningHigh THEN
stModbusWarnings.stBitmap.bPInPosHigh := 1;
END_IF
// Set error active if fb has error
IF _fbPressurePosolytSegmentInlet.xError THEN
_xErrorActive := TRUE;
END_IF
// Set warning if fb has warning
IF _fbPressurePosolytSegmentInlet.xWarning THEN
_xWarningActive := TRUE;
END_IF
// ===============================
// Pressure sensors negolyt segment inlet
// ===============================
_fbPressureNegolytSegmentInlet(
stScalingConfig:= stUnitConfig.stConfigNegolytPressureSegmentInlet,
stEWConfig:= stUnitConfig.stEWLNegolytPressureSegmentInlet,
stEWDelayConfig:= stUnitConfig.stEWDNegolytPressureSegmentInlet,
xReleaseErrors:= xReleaseErrors,
xReleaseLimitErrors:= xReleaseLimitErrors AND _fbNegolytPumpInlet.IsRunning AND _fbNegolytPumpInlet.xInTarget AND (NOT xStartBalancing) AND (_fbNegolytPumpInlet.rSPautomatic > 40),
xReleaseHardwareErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface => stHMIInterface.stP21);
// Filter pressure sensor data for HMI
_rFilteredPressNegolytInlet := _rFilteredPressNegolytInlet * 0.9 + stHMIInterface.stP21.rValue * 0.1;
stHMIInterface.stP21.rValue := _rFilteredPressNegolytInlet;
// Set modbus error register bits
IF _fbPressureNegolytSegmentInlet.xErrorLow THEN
stModbusErrors.stBitmap.bPInNegLow := 1;
END_IF
IF _fbPressureNegolytSegmentInlet.xErrorHigh THEN
stModbusErrors.stBitmap.bPInNegHigh := 1;
END_IF
IF _fbPressureNegolytSegmentInlet.xError THEN
stModbusErrors.stBitmap.bPInNegError := 1;
END_IF
// Set modbus warning register bits
IF _fbPressureNegolytSegmentInlet.xWarningLow THEN
stModbusWarnings.stBitmap.bPInNegLow := 1;
END_IF
IF _fbPressureNegolytSegmentInlet.xWarningHigh THEN
stModbusWarnings.stBitmap.bPInNegHigh := 1;
END_IF
// Set error active if fb has error
IF _fbPressureNegolytSegmentInlet.xError THEN
_xErrorActive := TRUE;
END_IF
// Set warning if fb has warning
IF _fbPressureNegolytSegmentInlet.xWarning THEN
_xWarningActive := TRUE;
END_IF
// ===============================
// Pressure sensors posolyt tank inlet
// ===============================
_fbPressurePosolytTankInlet(
stScalingConfig:= stUnitConfig.stConfigPosolytPressureTankInlet,
stEWConfig:= stUnitConfig.stEWLPosolytPressureTankInlet,
stEWDelayConfig:= stUnitConfig.stEWDPosolytPressureTankInlet,
xReleaseErrors:= xReleaseErrors,
xReleaseLimitErrors:= xReleaseLimitErrors,
xReleaseHardwareErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface => stHMIInterface.stP12);
// Filter pressure sensor data for HMI
_rFilteredPressPosolytTank := _rFilteredPressPosolytTank * 0.9 + stHMIInterface.stP12.rValue * 0.1;
stHMIInterface.stP12.rValue := _rFilteredPressPosolytTank;
// Set modbus error register bits
IF _fbPressurePosolytTankInlet.xErrorLow THEN
stModbusErrors.stBitmap.bPTankPosLow := 1;
END_IF
IF _fbPressurePosolytTankInlet.xErrorHigh THEN
stModbusErrors.stBitmap.bPTankPosHigh := 1;
END_IF
IF _fbPressurePosolytTankInlet.xError THEN
stModbusErrors.stBitmap.bPTankPosError := 1;
END_IF
// Set modbus warning register bits
IF _fbPressurePosolytTankInlet.xWarningLow THEN
stModbusWarnings.stBitmap.bPTankPosLow := 1;
END_IF
IF _fbPressurePosolytTankInlet.xWarningHigh THEN
stModbusWarnings.stBitmap.bPTankPosHigh := 1;
END_IF
// Set error active if fb has error
IF _fbPressurePosolytTankInlet.xError THEN
_xErrorActive := TRUE;
END_IF
// Set warning if fb has warning
IF _fbPressurePosolytTankInlet.xWarning THEN
_xWarningActive := TRUE;
END_IF
// ===============================
// Pressure sensors negolyt tank inlet
// ===============================
_fbPressureNegolytTankInlet(
stScalingConfig:= stUnitConfig.stConfigNegolytPressureTankInlet,
stEWConfig:= stUnitConfig.stEWLNegolytPressureTankInlet,
stEWDelayConfig:= stUnitConfig.stEWDNegolytPressureTankInlet,
xReleaseErrors:= xReleaseErrors,
xReleaseLimitErrors:= xReleaseLimitErrors,
xReleaseHardwareErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface => stHMIInterface.stP22);
// Filter pressure sensor data for HMI
_rFilteredPressNegolytTank := _rFilteredPressNegolytTank * 0.9 + stHMIInterface.stP22.rValue * 0.1;
stHMIInterface.stP22.rValue := _rFilteredPressNegolytTank;
// Set modbus error register bits
IF _fbPressureNegolytTankInlet.xErrorLow THEN
stModbusErrors.stBitmap.bPTankNegLow := 1;
END_IF
IF _fbPressureNegolytTankInlet.xErrorHigh THEN
stModbusErrors.stBitmap.bPTankNegHigh := 1;
END_IF
IF _fbPressureNegolytTankInlet.xError THEN
stModbusErrors.stBitmap.bPTankNegError := 1;
END_IF
// Set modbus warning register bits
IF _fbPressureNegolytTankInlet.xWarningLow THEN
stModbusWarnings.stBitmap.bPTankNegLow := 1;
END_IF
IF _fbPressureNegolytTankInlet.xWarningHigh THEN
stModbusWarnings.stBitmap.bPTankNegHigh := 1;
END_IF
// Set error active if fb has error
IF _fbPressureNegolytTankInlet.xError THEN
_xErrorActive := TRUE;
END_IF
// Set warning if fb has warning
IF _fbPressureNegolytTankInlet.xWarning THEN
_xWarningActive := TRUE;
END_IF
// ===============================
// Temperature sensor posolyt tank inlet
// ===============================
_fbTempSensorPosolyt(
stScalingConfig:= stUnitConfig.stConfigPosolytTempTankInlet,
stEWConfig:= GVL_CONFIG.stUnitConfig.stEWLPosolytTempTankInlet,
stEWDelayConfig:= GVL_CONFIG.stUnitConfig.stEWDPosolytTempTankInlet,
xReleaseErrors:= xReleaseErrors,
xReleaseLimitErrors:= xReleaseLimitErrors,
xReleaseHardwareErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface=> stHMIInterface.stT11);
// Set modbus error register bits
IF _fbTempSensorPosolyt.xErrorLow THEN
stModbusErrors.stBitmap.bTPosLow := 1;
END_IF
IF _fbTempSensorPosolyt.xErrorHigh THEN
stModbusErrors.stBitmap.bTPosHigh := 1;
END_IF
IF _fbTempSensorPosolyt.xError THEN
stModbusErrors.stBitmap.bTPosError := 1;
END_IF
// Set modbus warning register bits
IF _fbTempSensorPosolyt.xWarningLow THEN
stModbusWarnings.stBitmap.bTPosLow := 1;
END_IF
IF _fbTempSensorPosolyt.xWarningHigh THEN
stModbusWarnings.stBitmap.bTPosHigh := 1;
END_IF
IF _fbTempSensorPosolyt.xError THEN
_xErrorActive := TRUE;
END_IF
IF _fbTempSensorPosolyt.xWarning THEN
_xWarningActive := TRUE;
END_IF
// ===============================
// Temperature sensor negolyt tank inlet
// ===============================
_fbTempSensorNegolyt(
stScalingConfig:= stUnitConfig.stConfigNegolytTempTankInlet,
stEWConfig:= GVL_CONFIG.stUnitConfig.stEWLNegolytTempTankInlet,
stEWDelayConfig:= GVL_CONFIG.stUnitConfig.stEWDNegolytTempTankInlet,
xReleaseErrors:= xReleaseErrors,
xReleaseLimitErrors:= xReleaseLimitErrors,
xReleaseHardwareErrors:= xReleaseErrors,
xConfirmAlarms:= xConfirmAlarms,
stHMIInterface=> stHMIInterface.stT21);
// Set modbus error register bits
IF _fbTempSensorNegolyt.xErrorLow THEN
stModbusErrors.stBitmap.bTNegLow := 1;
END_IF
IF _fbTempSensorNegolyt.xErrorHigh THEN
stModbusErrors.stBitmap.bTNegHigh := 1;
END_IF
IF _fbTempSensorNegolyt.xError THEN
stModbusErrors.stBitmap.bTNegError := 1;
END_IF
// Set modbus warning register bits
IF _fbTempSensorNegolyt.xWarningLow THEN
stModbusWarnings.stBitmap.bTNegLow := 1;
END_IF
IF _fbTempSensorNegolyt.xWarningHigh THEN
stModbusWarnings.stBitmap.bTNegHigh := 1;
END_IF
IF _fbTempSensorNegolyt.xError THEN
_xErrorActive := TRUE;
END_IF
IF _fbTempSensorNegolyt.xWarning THEN
_xWarningActive := TRUE;
END_IF
// ===============================
// Voltage segment
// ===============================
_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 modbus error register bits
IF _fbVoltageSegment.xErrorLow THEN
stModbusErrors.stBitmap.bVLow := 1;
END_IF
IF _fbVoltageSegment.xErrorHigh THEN
stModbusErrors.stBitmap.bVHigh := 1;
END_IF
IF _fbVoltageSegment.xError THEN
stModbusErrors.stBitmap.bVError := 1;
END_IF
// Set modbus warning register bits
IF _fbVoltageSegment.xWarningLow THEN
stModbusWarnings.stBitmap.bVLow := 1;
END_IF
IF _fbVoltageSegment.xWarningHigh THEN
stModbusWarnings.stBitmap.bVHigh := 1;
END_IF
// Set error active if fb has error
IF _fbVoltageSegment.xError THEN
_xErrorActive := TRUE;
END_IF
// Set warning if fb has warning
IF _fbVoltageSegment.xWarning THEN
_xWarningActive := TRUE;
END_IF
// ===============================
// Check for EStop
// ===============================
IF (NOT xEmergencyStopOk) THEN
_xErrorActive := TRUE;
END_IF
// ===============================
// Write Voltage to HMI
// ===============================
stHMIInterface.rVoltage := stHMIInterface.rVoltage * 0.9 + _fbVoltageSegment.rScaledValue * 0.1;
// ===============================
// Check for pressure difference
// ===============================
_xDeltaPSegmentInletToHigh := (ABS(_fbPressurePosolytSegmentInlet.rScaledValue - _fbPressureNegolytSegmentInlet.rScaledValue) > GVL_CONFIG.stUnitConfig.rMaxDeltaPSegmentInlet);
_xReleaseSignalDeltaPSegment(
xSignal:= _xDeltaPSegmentInletToHigh,
xRelease:= _xEnableCheckForDeltaPSegmentInlet,
timOnDelay:= T#5S,
timOffDelay:= T#2S,
xReleaseSignal=> _xErrorDeltaPSegmentInlet);
IF _xErrorDeltaPSegmentInlet AND (NOT _fbPressureDiffToBig.bRaised) THEN
_fbPressureDiffToBig.Raise(0);
END_IF
IF (NOT _xErrorDeltaPSegmentInlet) AND _fbPressureDiffToBig.bRaised THEN
_fbPressureDiffToBig.Clear(0, FALSE);
END_IF
IF _fbPressureDiffToBig.eConfirmationState = TcEventConfirmationState.WaitForConfirmation THEN
_fbPressureDiffToBig.Confirm(0);
END_IF
IF _xErrorDeltaPSegmentInlet THEN
_xErrorActive := TRUE;
END_IF
// ===============================
// Check if all components are in automatic
// ===============================
_xAllComponentsInAutomatic := _fbPosolytValveTankOutlet.IsInAutomaticMode
AND _fbNegolytValveTankOutlet.IsInAutomaticMode
AND _fbPosolytPumpInlet.IsInAutomaticMode
AND _fbNegolytPumpInlet.IsInAutomaticMode;
// Raise warning
IF NOT _fbNotAllAutomaticAlarm.bRaised AND (NOT _xAllComponentsInAutomatic) AND (NOT xAllToManualMode) THEN
_fbNotAllAutomaticAlarm.Raise(0);
END_IF
// Clear warning and reset
IF _fbNotAllAutomaticAlarm.bRaised AND _xAllComponentsInAutomatic THEN
_fbNotAllAutomaticAlarm.Clear(0, TRUE);
END_IF
// Calculate shutdown discharge threshold
_rShutdownDischargeVoltageThreshold := GVL_CONFIG.rMinimumUnitVoltage + GVL_CONFIG.rDeltaUnitVoltageShutdownDischarge;
// ===============================
// 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();
// ===============================
// Output error and warning flags
// ===============================
xError := _xErrorActive;
xWarning := _xWarningActive;
IF (NOT xSafetyIntlksOk) THEN
stModbusErrors.stBitmap.bSafetyIntlk := 1;
END_IF
// ===============================
// Reset modbus error register with alarm confirmation
// ===============================
IF xConfirmAlarms THEN
stModbusErrors.dwRegister := 0;
stModbusWarnings.dwRegister := 0;
END_IF
// ===============================
// Handle general error message
// ===============================
IF xError AND (NOT _fbUnitError.bRaised) THEN
_fbUnitError.Raise(0);
END_IF
IF (NOT xError) AND _fbUnitError.bRaised THEN
_fbUnitError.Clear(0, FALSE);
END_IF
IF _fbUnitError.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xConfirmAlarms THEN
_fbUnitError.Confirm(0);
END_IF
// ===============================
// Output all components in auto mode
// ===============================
xAllComponentsInAuto := _xAllComponentsInAutomatic;]]></ST>
</Implementation>
<Method Name="FB_init" Id="{08f1cd44-6483-4d20-ab45-d1938e8ec885}">
<Declaration><![CDATA[METHOD FB_init : BOOL
VAR_INPUT
bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change)
sName : STRING;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[_sName := sName;
// Create not all components in automatic mode alarm
_fbNotAllAutomaticAlarm.CreateEx(TC_EVENTS.General.NotAllCompInAutomatic, bWithConfirmation := FALSE, 0);
_fbNotAllAutomaticAlarm.ipArguments.Clear().AddString(_sName);
// Create unit error
_fbUnitError.CreateEx(stEventEntry := TC_EVENTS.General.UnitError, bWithConfirmation := TRUE, 0);
_fbUnitError.ipArguments.Clear().AddString(_sName);]]></ST>
</Implementation>
</Method>
<Property Name="Name" Id="{a82783d4-f1f5-481b-bbb0-7ea8279de793}">
<Declaration><![CDATA[PROPERTY Name : String]]></Declaration>
<Get Name="Get" Id="{62ca6bce-5aa4-40f1-aa68-f3e5d22ad4a4}">
<Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[Name := _sName;]]></ST>
</Implementation>
</Get>
<Set Name="Set" Id="{b2e0f6da-5412-45b8-aacd-c140a5beab95}">
<Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[_sName := Name;
// Create alarm message
_fbNotAllAutomaticAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
</Implementation>
</Set>
</Property>
<Action Name="StateMachine" Id="{2467f04e-fe89-4b6c-a53d-a49981dd0ce6}">
<Implementation>
<ST><![CDATA[// ===============================
// Run state machine for startup and shutdown
// ===============================
CASE _iState OF
0: // Off
// Start in enable
IF xEnable AND (NOT xStartBalancing) AND _xAllComponentsInAutomatic AND (NOT _xErrorActive) THEN
_xReleaseManualMode := FALSE;
_timUnitStartupWaitTime := GVL_CONFIG.timUnitStartupTime;
_iState := 10;
stHMIInterface.eStatus := E_COMPONENT_STATUS.STARTING;
END_IF
// Start in balancing mode
IF (NOT xEnable) AND xStartBalancing AND _xAllComponentsInAutomatic AND (NOT _xErrorActive) THEN
_xReleaseManualMode := FALSE;
xBalancingDone := FALSE;
_timUnitStartupWaitTime := GVL_CONFIG.timUnitBalancingStartupTime;
_iState := 10;
END_IF
IF _xErrorActive THEN
_iState := 1000;
END_IF
10: // Open all valves
_fbPosolytValveTankOutlet.ReqAutomaticOpen();
_fbNegolytValveTankOutlet.ReqAutomaticOpen();
xOff := FALSE;
_iState := 15;
15: // Wait for all valves to be open
IF _fbPosolytValveTankOutlet.IsOpen AND _fbNegolytValveTankOutlet.IsOpen THEN
IF (NOT _fbPosolytValveTankOutlet.xError) AND (NOT _fbNegolytValveTankOutlet.xError) THEN
_iState := 20;
END_IF
END_IF
// If enable signal is lost
IF ((NOT xEnable) AND (NOT xStartBalancing)) THEN
stHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40;
END_IF
// If enable signal is lost, or there is an error, goto shutdown
IF _xErrorActive THEN
_xReleaseManualMode := TRUE;
_iState := 1000;
END_IF
IF (NOT xEnable) THEN
_iState := 51;
END_IF
20: // Start pumps
_fbPosolytPumpInlet.ReqAutomaticStart();
_fbNegolytPumpInlet.ReqAutomaticStart();
_xEnableCheckForDeltaPSegmentInlet := TRUE;
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytOnPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytOnPower;
_iState := 25;
25: // Wait for all pumps to run
IF _fbPosolytPumpInlet.xInTarget AND _fbNegolytPumpInlet.xInTarget THEN
_iState := 30;
END_IF
// If enable signal is lost, goto shutdown
IF ((NOT xEnable) AND (NOT xStartBalancing)) THEN
stHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40; // 40
END_IF
IF _xErrorActive THEN
_iState := 900;
END_IF
30: // Wait some time
_tonStartupCheck(In := TRUE, PT := _timUnitStartupWaitTime);
// After some time, check if all values are ok
IF _tonStartupCheck.Q THEN
_tonStartupCheck(In := FALSE);
IF xEnable AND (NOT xStartBalancing) THEN
_iState := 31;
ELSIF (NOT xEnable) AND xStartBalancing THEN
xReady := TRUE;
_iState := 69;
END_IF
END_IF
// If enable signal is lost, goto shutdown
IF (NOT xEnable) AND (NOT xStartBalancing) THEN
stHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40;
END_IF
IF _xErrorActive THEN
_iState := 900;
END_IF
31: // Check if voltage limit can be reached
_tonVoltageCheckTimeput(IN := TRUE);
// Check for minimum unit voltage
IF ((_fbVoltageSegment.rScaledValue >= GVL_CONFIG.rMinimumUnitVoltage) OR xInSafetyCheckMode) AND (NOT _xErrorActive) AND (NOT _xWarningActive) THEN
_tonVoltageCheckTimeput(IN := FALSE);
xReady := TRUE;
// Only enable Voltage Checks if not in safety check mode
IF (NOT xInSafetyCheckMode) THEN
_xEnableVoltageLimitChecks := TRUE;
END_IF
// Continue on normal startup path
IF xEnable THEN
stHMIInterface.eStatus := E_COMPONENT_STATUS.ON;
_iState := 35;
END_IF
END_IF
IF _tonVoltageCheckTimeput.Q OR _xErrorActive THEN
_tonVoltageCheckTimeput(IN := FALSE);
xError := TRUE;
_iState := 900;
END_IF
// If enable signal is lost, goto shutdown
IF (NOT xEnable) THEN
_iState := 40;
END_IF
35: // Unit in enabled state
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytOnPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytOnPower;
IF (NOT xEnable) THEN
stHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN;
_iState := 40;
END_IF
// Goto error shutdown if an error occured
IF _xErrorActive THEN
_iState := 900;
END_IF
40: // Close all valves
_fbNegolytValveTankOutlet.ReqAutomaticClose();
_fbPosolytValveTankOutlet.ReqAutomaticClose();
xReady := FALSE;
_iState := 45;
45: // Wait for valves to be closed
IF _fbNegolytValveTankOutlet.IsClosed AND _fbPosolytValveTankOutlet.IsClosed THEN
xInShutdownDischargeMode := TRUE;
IF (_fbVoltageSegment.rScaledValue > _rShutdownDischargeVoltageThreshold) THEN
xShutdownDischargeAllowed := TRUE;
ELSE
xShutdownDischargeAllowed := FALSE;
END_IF
_iState := 50;
END_IF
// When there is an error trying to close the valves,
// dont try to discharge the segment
IF _fbNegolytValveTankOutlet.xError OR _fbPosolytValveTankOutlet.xError THEN
_xEnableVoltageLimitChecks := FALSE;
_iState := 60;
END_IF
// Check for restart condition
IF xEnable AND (NOT _xErrorActive) THEN
_iState := 0;
END_IF
50: // Wait for unit voltage to drop below a certain threshold
IF (_fbVoltageSegment.rScaledValue > _rShutdownDischargeVoltageThreshold) AND xInverterEnabled THEN
xShutdownDischargeAllowed := TRUE;
ELSE
xShutdownDischargeAllowed := FALSE;
_xEnableVoltageLimitChecks := FALSE;
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower;
_xEnableCheckForDeltaPSegmentInlet := FALSE;
_iState := 51;
END_IF
// Check for restart condition
IF (xEnable OR xStartBalancing) AND (NOT _xErrorActive) THEN
xShutdownDischargeAllowed := FALSE;
xInShutdownDischargeMode := FALSE;
_iState := 0;
END_IF
IF _xErrorActive THEN
_iState := 1000;
END_IF
51: // Discharge without inverter
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower;
IF (_fbVoltageSegment.rScaledValue <= GVL_CONFIG.rPumpshutoffThreshold) THEN
xShutdownDischargeAllowed := FALSE;
xInShutdownDischargeMode := FALSE;
_iState := 60;
END_IF
// Check for restart condition
IF xEnable AND (NOT _xErrorActive) THEN
xShutdownDischargeAllowed := FALSE;
xInShutdownDischargeMode := FALSE;
_iState := 0;
END_IF
IF _xErrorActive THEN
_iState := 1000;
END_IF
60: // Disable pumps
_fbPosolytPumpInlet.ReqAutomaticStop();
_fbNegolytPumpInlet.ReqAutomaticStop();
_iState := 65;
65: // Wait for pumps to be stopped
IF _fbPosolytPumpInlet.IsStopped AND _fbNegolytPumpInlet.IsStopped THEN
xOff := TRUE;
_xReleaseManualMode := TRUE;
IF NOT _xErrorActive THEN
stHMIInterface.eStatus := E_COMPONENT_STATUS.OFF;
_iState := 0;
END_IF
END_IF
// Check for restart condition
IF xEnable AND (NOT _xErrorActive) THEN
stHMIInterface.eStatus := E_COMPONENT_STATUS.OFF;
_iState := 0;
END_IF
// Check for error
IF _xErrorActive THEN
_iState := 1000;
END_IF
69: // Check for minimum voltage
IF (_fbVoltageSegment.rScaledValue <= GVL_CONFIG.rMinimumUnitVoltage) THEN
_iState := 900;
ELSE
_rBalancingTargetVoltage := rBalancingTargetVoltage;
_istate := 70;
END_IF
70: // Wait for segment voltage to be in the range of the target voltage
IF (_fbVoltageSegment.rScaledValue <= _rBalancingTargetVoltage) THEN
xBalancingDone := TRUE;
_iState := 71;
END_IF
// If enable signal is lost, goto shutdown
IF (NOT xStartBalancing) THEN
_iState := 40;
END_IF
IF _xErrorActive THEN
_iState := 900;
END_IF
71: // Close valves
_fbNegolytValveTankOutlet.ReqAutomaticClose();
_fbPosolytValveTankOutlet.ReqAutomaticClose();
xReady := FALSE;
_iState := 72;
72: // Wait for all valves to be closed
IF _fbNegolytValveTankOutlet.IsClosed AND _fbPosolytValveTankOutlet.IsClosed THEN
xInShutdownDischargeMode := TRUE;
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower;
_iState := 73;
END_IF
73: // Wait for start balancing signal to be off to prevent automatic restart
IF (NOT xStartBalancing) THEN
_iState := 50;
END_IF
700: // Debug step
IF (NOT xStartBalancing) THEN
_iState := 40;
END_IF
900: // Soft error shutdown
_fbNegolytValveTankOutlet.ReqAutomaticClose();
_fbPosolytValveTankOutlet.ReqAutomaticClose();
_xEnableCheckForDeltaPSegmentInlet := FALSE;
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower;
_fbNegolytPumpInlet.ReqAutomaticStart();
_fbPosolytPumpInlet.ReqAutomaticStart();
_xEnableVoltageLimitChecks := FALSE;
xShutdownDischargeAllowed := FALSE;
xInShutdownDischargeMode := FALSE;
xReady := FALSE;
_iState := 910;
910: // Wait for discharged or restart
IF (_fbVoltageSegment.rScaledValue <= GVL_CONFIG.rPumpshutoffThreshold) THEN
xShutdownDischargeAllowed := FALSE;
xInShutdownDischargeMode := FALSE;
_iState := 1000;
END_IF
// Check for restart condition
IF (NOT xEnable) AND xError THEN
xError := FALSE;
END_IF
IF (NOT xError) AND (xEnable OR xStartBalancing) THEN
_iState := 0;
END_IF
IF _xErrorActive THEN
_iState := 1000;
END_IF
1000: // Error shutdown
stHMIInterface.eStatus := E_COMPONENT_STATUS.ERROR;
_fbNegolytValveTankOutlet.ReqAutomaticClose();
_fbPosolytValveTankOutlet.ReqAutomaticClose();
_fbPosolytPumpInlet.ReqAutomaticStop();
_fbNegolytPumpInlet.ReqAutomaticStop();
_xEnableVoltageLimitChecks := FALSE;
xShutdownDischargeAllowed := FALSE;
xInShutdownDischargeMode := FALSE;
xReady := FALSE;
xOff := TRUE;
xError := TRUE;
_iState := 1001;
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 _xPumpsReady AND xConfirmAlarms THEN
xError := FALSE;
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>
</POU>
</TcPlcObject>