Files
Uniper_PLC/PLC/POUs/FB_Unit.TcPOU
Markus.Neukirch f0e6143997 IBN changes
added sync units for cabinet temperature, changes in modbus interface to EMS (1.0.4 and 1.0.5), added error counter to modbus communication, lot of changes to kaco (faults, consecutive errors, bms error messages), isolation error ledge, allowed startbalancing when on shutdown, tower light integration
2025-09-05 14:24:37 +02:00

1327 lines
40 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;
// Start unit
xEnable : BOOL;
// Star balancing
xStartBalancing : BOOL;
// Unit in safety check mode
xInSafetyCheckMode : BOOL;
// String operation mode
eStringOperatingMode : E_STRING_OPERATING_MODE;
// 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_0111;
// 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_0111;
// 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;
stHMIInterface.stNS11.stInterlock.asSafetyINTLKName[1] := 'Segment inlet pressure to high';
_stPosolytPumpInletSIntlk.1 := NOT _fbPressurePosolytSegmentInlet.xErrorHigh;
stHMIInterface.stNS11.stInterlock.asSafetyINTLKName[2] := 'Segment inlet pressure to low';
_stPosolytPumpInletSIntlk.2 := NOT _fbPressurePosolytSegmentInlet.xErrorLow;
// 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;
stHMIInterface.stNS11.stInterlock.asSafetyINTLKName[1] := 'Segment inlet pressure to high';
_stNegolytPumpInletSIntlk.1 := NOT _fbPressureNegolytSegmentInlet.xErrorHigh;
stHMIInterface.stNS11.stInterlock.asSafetyINTLKName[2] := 'Segment inlet pressure to low';
_stNegolytPumpInletSIntlk.2 := NOT _fbPressureNegolytSegmentInlet.xErrorLow;
// 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);
_fbPosolytPumpInlet.Name :=CONCAT(_sName, ' - Posolyt segment inlet');
_fbNegolytPumpInlet.Name := CONCAT(_sName, ' - Negolyt segment inlet');]]></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 and start pumps
_fbPosolytValveTankOutlet.ReqAutomaticOpen();
_fbNegolytValveTankOutlet.ReqAutomaticOpen();
_fbPosolytPumpInlet.ReqAutomaticStart();
_fbNegolytPumpInlet.ReqAutomaticStart();
_xEnableCheckForDeltaPSegmentInlet := TRUE;
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytOnPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytOnPower;
xOff := FALSE;
_iState := 15;
15: // Wait for all valves to be open and all pumps to be running
IF _fbPosolytValveTankOutlet.IsOpen AND _fbNegolytValveTankOutlet.IsOpen AND _fbPosolytPumpInlet.xInTarget AND _fbNegolytPumpInlet.xInTarget THEN
IF (NOT _fbPosolytValveTankOutlet.xError) AND (NOT _fbNegolytValveTankOutlet.xError) AND (NOT _fbPosolytPumpInlet.xError) AND (NOT _fbNegolytPumpInlet.xError) THEN
_iState := 30;
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) AND NOT xStartBalancing THEN
_iState := 51;
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);
IF (NOT _xErrorActive) AND (NOT _xWarningActive) THEN
CASE eStringOperatingMode OF
E_STRING_OPERATING_MODE.SAFETY_CHECK:
_xEnableVoltageLimitChecks := TRUE;
_tonVoltageCheckTimeput(IN := FALSE);
xReady := TRUE;
stHMIInterface.eStatus := E_COMPONENT_STATUS.ON;
_iState := 35;
E_STRING_OPERATING_MODE.PRECHARGE:
_tonVoltageCheckTimeput(IN := FALSE);
_xEnableVoltageLimitChecks := FALSE;
xReady := TRUE;
stHMIInterface.eStatus := E_COMPONENT_STATUS.ON;
_iState := 35;
ELSE
IF (_fbVoltageSegment.rScaledValue >= GVL_CONFIG.rMinimumUnitVoltage) THEN
_xEnableVoltageLimitChecks := TRUE;
xReady := TRUE;
_iState := 35;
END_IF
END_CASE
END_IF
// 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
*)
// Voltage check timeout
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
// check for balancing condition
IF xStartBalancing 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();
_rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower;
_rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower;
_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>