); // Set error active if fb has error IF _fbPosolytPumpInlet.xError THEN _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, stMotorAnalogConfig:= stUnitConfig.stConfigNegolytPump, stHMIInterface:= stHMIInterface.stNS21, xWarning=> ); // Set error active if fb has error IF _fbNegolytPumpInlet.xError THEN _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 // =============================== // 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), xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, stHMIInterface => stHMIInterface.stP11); // 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), xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, stHMIInterface => stHMIInterface.stP21); // 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); // 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); // 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); 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); IF _fbTempSensorNegolyt.xError THEN _xErrorActive := TRUE; END_IF IF _fbTempSensorNegolyt.xWarning THEN _xWarningActive := TRUE; 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 // 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 // =============================== // Write Voltage to HMI // =============================== stHMIInterface.rVoltage := _fbVoltageSegment.rScaledValue; // =============================== // 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) 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 // =============================== StateMachine(); // =============================== // Output error and warning flags // =============================== xError := _xErrorActive; xWarning := _xWarningActive; // =============================== // 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;]]> = GVL_CONFIG.rMinimumUnitVoltage) 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 _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 IF (NOT xEnable) THEN _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 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 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 _iState := 0; END_IF END_IF // Check for restart condition IF xEnable AND (NOT _xErrorActive) THEN _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; _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 1000: // Error shutdown _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 xConfirmAlarms THEN xError := FALSE; _iState := 0; END_IF END_CASE]]>