No discharge throught inverter xErrorShutdown : BOOL; // Start in balancing mode xStartBalancing : BOOL; // String in safety check mode xInSafetyCheckMode : BOOL; // Requested inverter power rPowerInverter : REAL; // String HMI interface stHMIInterface : REFERENCE TO ST_STRING_HMI_INTERFACE; // Emergency stop ok xEmergencyStopOk : BOOL; // Reset Safety xResetSafety : BOOL; // Safety communication error {attribute 'analysis' := '-33'} xSafetyComError AT %I* : BOOL; // Release alarms xReleaseErrors : BOOL; // Release analog io limit errors xReleaseLimitErrors : BOOL; // Release manual mode xReleaseManualMode : BOOL; // Input to confirm all errors xConfirmAlarms : BOOL; // Switch all components to manual mode xAllToManualMode : BOOL; // String inverter ip sInverterIP : STRING; xECStateSCS AT %I* : UINT; xIsoErrorL1 AT %I* : BOOL; xIsoErrorL2 AT %I* : BOOL; END_VAR VAR_OUTPUT // Repair switch closed xRepairSwitchOk AT %I* : BOOL; // All safetyinterlocks from safety plc are ok xSafetyIntlksOk AT %I* : BOOL; // All component safety interlocks are ok xSafetyIntlksComponentsOk : BOOL; // Current string voltage rCurrentVoltage : REAL; // Module in shutdown segment discharge mode xInShutdownDischargeMode : BOOL; // Module can be discharged during shutdown sequence xShutdownDischargeAllowed : BOOL; // String ready xReady : BOOL; // String completely off xOff : BOOL; // Signal to close dc circuit breaker xCloseDCCB AT %Q* : BOOL; // Signal that dc circuit breakers are closed xDCCBOpen AT %I* : BOOL; // Reset signal for safety dc circuit breaker xResetSafetyDCCB AT %Q* : BOOL; // All modules in automatic mode xAllModulesInAutoMode : BOOL; xError : BOOL; xWarning : BOOL; eStatus : E_COMPONENT_STATUS; // Inverter status data stInverterData : ST_SUNSPEC_CURRENT_VALUES; // Smallest segment voltage rSmallestSegmentVoltage : REAL; // Highest segment voltage rHighestSegmentVoltage : REAL; // Balancing done xBalancingDone : BOOL; END_VAR VAR _fbModule1 : FB_Module(CONCAT(Name,' - Module 1')); _fbModule2 : FB_Module(CONCAT(Name,' - Module 2')); _fbModule3 : FB_Module(CONCAT(Name,' - Module 3')); // Summed status of all module errors _xModuleError : BOOL; // All modules are ready _xAllModulesReady : BOOL; // All modules in shutdown discharge mode _xAllModulesInShutdownDischargeMode : BOOL; // Flag for module balance checking _xBalanceOk : BOOL; // Modules out of balance alarm message _fbModulesOutOfBalanceAlarm : Fb_TcAlarm; // Safetyinterlocks pending alarm _fbSafetyInterlocksNotOkAlarm : FB_TcAlarm; // Inverter startup error _fbInverterStartupTimeoutAlarm : FB_TcAlarm; // DC Main switch not closed _fbDCMainSwitchNotClosed : FB_TcAlarm; // Connection to SCS lost _fbSCSConnLost : FB_TcAlarm; // Isolatio alarm _fbIsolationAlarm : FB_TcAlarm; // Safety interlock reset timeout _fbSafetyIntlkTimeoutAlarm : FB_TcAlarm; // Shutdown discharge stopped messages _fbSDDCLevel : FB_TcMessage; _fbSDUnitThreshold : FB_TcMessage; // State for start and stop _iState : INT := 0; // Timer for result pulse to safety _tonResetPulseLength : TON := (PT := T#250MS); // Error timer for not closing dc relais _tonErrorDCCBNotClosed : TON := (PT := T#5S); // Delayed balance check signal _fbBalanceNotOkSignal : FB_ReleaseSignal; // String name _sName : STRING; // String inverter //_fbInverter : FB_PowerSupplySunspec(Name); _fbInverter : FB_PowerSupplyKaco(Name); // Internal inverter power command _rPowerInverterInternal : REAL; // Enable inverter flag _xEnableInverter : BOOL; // Fault timer for inverter startup _tonInverterStartupTimeout : TON := (PT := T#3M); // Fault timer for inverter shutdown _tonInverterShutdownError : TON := (PT := T#10S); // Debug delay timer for inverter shutdown _tonInverterShutdownDelay : TON := (PT := T#10S); // Timer for Safety ok timeout _tonSafetyOkTimeout : TON := (PT := T#2M); // Analog input for string current measurement _fbStringCurrent : FB_AnalogInput(CONCAT(Name,' - Current')); xErrorInverter : BOOL; _xReleaseLimitErrorsInternal : BOOL; // Balancing done _xBalancingDone : BOOL; // Enable modules internal signal _xEnable : BOOL; // Start balancing internal signal _xStartBalancing : BOOL; _xIsoError : BOOL; // Iso error timeout _fbTONIsoError : TON; // Internal SOC _rSOC : REAL; _fbTONDCSettlingTime : TON := (PT := T#10S); END_VAR VAR PERSISTENT rCapacityWH : REAL; rCapacityAH : REAL; END_VAR ]]> 8) AND (NOT _fbSCSConnLost.bRaised) AND xReleaseErrors THEN _fbSCSConnLost.Raise(0); END_IF IF (xECStateSCS = 8) AND _fbSCSConnLost.bRaised THEN _fbSCSConnLost.Clear(0, FALSE); END_IF IF _fbSCSConnLost.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xConfirmAlarms THEN _fbSCSConnLost.Confirm(0); END_IF // =============================== // DC Main switch error handling // =============================== IF (NOT xRepairSwitchOk) AND (NOT _fbDCMainSwitchNotClosed.bRaised) THEN _fbDCMainSwitchNotClosed.Raise(0); END_IF IF xRepairSwitchOk AND _fbDCMainSwitchNotClosed.bRaised THEN _fbDCMainSwitchNotClosed.Clear(0, FALSE); END_IF // =============================== // ISO Error handling // =============================== // Mute iso error when inverter is enabled _xIsoError := ((NOT xIsoErrorL1) OR (NOT xIsoErrorL2)) AND (NOT _fbInverter.xActive) AND (xDCCBOpen); _fbTONIsoError(IN := _xIsoError, PT := GVL_CONFIG.timIsoErrorTimeout); // _fbInverter IF _fbTONIsoError.Q AND (NOT _fbIsolationAlarm.bRaised) AND xReleaseErrors THEN _fbIsolationAlarm.Raise(0); END_IF IF (NOT _fbTONIsoError.Q) AND _fbIsolationAlarm.bRaised THEN _fbIsolationAlarm.Clear(0, FALSE); END_IF IF _fbIsolationAlarm.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xConfirmAlarms THEN _fbIsolationAlarm.Confirm(0); END_IF IF _fbTONIsoError.Q THEN xError := TRUE; END_IF // =============================== // DC current measurement // =============================== _fbStringCurrent( stScalingConfig:= GVL_CONFIG.stConfigSCSCurrent, stEWConfig:= GVL_CONFIG.stEWLSCSCurrent, stEWDelayConfig:= GVL_CONFIG.stEWDSCSCurrent, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= FALSE, xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, xError=> , xWarning=> , rScaledValue=> , xErrorLow=> , xWarningLow=> , xWarningHigh=> , xErrorHigh=> , stHMIInterface=> ); // Copy scaled current value to HMI stHMIInterface.rCurrent := _fbStringCurrent.stHMIInterface.rValue; // =============================== // Module 1 // =============================== _fbModule1( xEnable := _xEnable, uiFirstUnitIndex := uiStringNumber * 12, rCurrent := stHMIInterface.rCurrent, xStartBalancing := _xStartBalancing, xInverterEnabled := _fbInverter.xActive, xInSafetyCheckMode := xInSafetyCheckMode, xEmergencyStopOk:= xEmergencyStopOk, refstHMIInterface:= stHMIInterface.stHMIInterfaceModule1, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors AND _xReleaseLimitErrorsInternal, xReleaseManualMode := xReleaseManualMode, xConfirmAlarms:= xConfirmAlarms, xAllToManualMode := xAllToManualMode, rBalancingTargetVoltage := rSmallestSegmentVoltage); // =============================== // Module 2 // =============================== _fbModule2( xEnable := _xEnable, uiFirstUnitIndex := uiStringNumber * 12 + 4, rCurrent := stHMIInterface.rCurrent, xStartBalancing := _xStartBalancing, xInverterEnabled := _fbInverter.xActive, xInSafetyCheckMode := xInSafetyCheckMode, xEmergencyStopOk:= xEmergencyStopOk, refstHMIInterface:= stHMIInterface.stHMIInterfaceModule2, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors AND _xReleaseLimitErrorsInternal, xReleaseManualMode := xReleaseManualMode, xConfirmAlarms:= xConfirmAlarms, xAllToManualMode := xAllToManualMode, rBalancingTargetVoltage := rSmallestSegmentVoltage); // =============================== // Module 3 // =============================== _fbModule3( xEnable := _xEnable, uiFirstUnitIndex := uiStringNumber * 12 + 8, rCurrent := stHMIInterface.rCurrent, xStartBalancing := _xStartBalancing, xInverterEnabled := _fbInverter.xActive, xInSafetyCheckMode := xInSafetyCheckMode, xEmergencyStopOk:= xEmergencyStopOk, refstHMIInterface:= stHMIInterface.stHMIInterfaceModule3, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors AND _xReleaseLimitErrorsInternal, xReleaseManualMode := xReleaseManualMode, xConfirmAlarms:= xConfirmAlarms, xAllToManualMode := xAllToManualMode, rBalancingTargetVoltage := rSmallestSegmentVoltage); // =============================== // Handle component safety interlocks ok // =============================== xSafetyIntlksComponentsOk := _fbModule1.xSafetyIntlksOk AND _fbModule2.xSafetyIntlksOk AND _fbModule3.xSafetyIntlksOk; // =============================== // Handle modules error state // =============================== _xModuleError := _fbModule1.xError OR _fbModule2.xError OR _fbModule3.xError OR (NOT xSafetyIntlksComponentsOk); IF _xModuleError THEN xError := TRUE; END_IF // =============================== // Handle modules warning state // =============================== xWarning := _fbModule1.xWarning OR _fbModule2.xWarning OR _fbModule3.xWarning; // =============================== // Handle modules in auto mode // =============================== xAllModulesInAutoMode := _fbModule1.xAllUnitsInAutomatic AND _fbModule2.xAllUnitsInAutomatic AND _fbModule3.xAllUnitsInAutomatic; // =============================== // Handle shutdown discharge mode // =============================== _xAllModulesInShutdownDischargeMode := _fbModule1.xInShutdownDischargeMode AND _fbModule2.xInShutdownDischargeMode AND _fbModule3.xInShutdownDischargeMode; // =============================== // Handle safety interlock alarm // =============================== IF (NOT xSafetyIntlksOk) AND NOT _fbSafetyInterlocksNotOkAlarm.bRaised THEN _fbSafetyInterlocksNotOkAlarm.Raise(0); END_IF IF xSafetyIntlksOk AND _fbSafetyInterlocksNotOkAlarm.bRaised THEN _fbSafetyInterlocksNotOkAlarm.Clear(0, TRUE); END_IF // =============================== // Modules ready check // =============================== _xAllModulesReady := _fbModule1.xReady AND _fbModule2.xReady AND _fbModule3.xReady; // =============================== // Balancing done check // =============================== _xBalancingDone := _fbModule1.xBalancingDone AND _fbModule2.xBalancingDone AND _fbModule3.xBalancingDone; // =============================== // Modules in shutdown discharge mode // =============================== xInShutdownDischargeMode := _fbModule1.xInShutdownDischargeMode OR _fbModule2.xInShutdownDischargeMode OR _fbModule3.xInShutdownDischargeMode; // =============================== // Units shutdown discharge allowed // =============================== xShutdownDischargeAllowed := _fbModule1.xShutdownDischargeAllowed AND _fbModule2.xShutdownDischargeAllowed AND _fbModule3.xShutdownDischargeAllowed; // =============================== // All modules off // =============================== xOff := _fbModule1.xOff AND _fbModule2.xOff AND _fbModule3.xOff; // =============================== // Handle status // =============================== // String off IF xOff AND (NOT xError) THEN eStatus := E_COMPONENT_STATUS.OFF; END_IF // String starting IF _xEnable AND (NOT _xAllModulesReady) AND (NOT xError) THEN eStatus := E_COMPONENT_STATUS.STARTING; END_IF // String on IF _xAllModulesReady AND _fbInverter.xActive AND (NOT xError) THEN IF _rPowerInverterInternal < 0.0 THEN eStatus := E_COMPONENT_STATUS.CHARGING; ELSIF _rPowerInverterInternal > 0.0 THEN eStatus := E_COMPONENT_STATUS.DISCHARGING; ELSE eStatus := E_COMPONENT_STATUS.ON; END_IF END_IF // String in shutdown IF xInShutdownDischargeMode AND (NOT xError) THEN eStatus := E_COMPONENT_STATUS.SHUTDOWN; END_IF // String in error state IF xError THEN eStatus := E_COMPONENT_STATUS.ERROR; END_IF // =============================== // Calculate string voltage // =============================== rCurrentVoltage := _fbModule1.rCurrentVoltage + _fbModule2.rCurrentVoltage + _fbModule3.rCurrentVoltage; stHMIInterface.rVoltage := stHMIInterface.rVoltage* 0.95 + rCurrentVoltage * 0.05; // =============================== // String balance check // =============================== // Reset balance ok flag _xBalanceOk := TRUE; // Test module 1 with module 2 IF ABS(_fbModule1.rCurrentVoltage - _fbModule2.rCurrentVoltage) > GVL_CONFIG.rMaxAbsDiffVoltageModulesInString THEN _xBalanceOk := FALSE; END_IF // Test module 1 with module 3 IF ABS(_fbModule1.rCurrentVoltage - _fbModule3.rCurrentVoltage) > GVL_CONFIG.rMaxAbsDiffVoltageModulesInString THEN _xBalanceOk := FALSE; END_IF // Test module 2 with module 3 IF ABS(_fbModule2.rCurrentVoltage - _fbModule3.rCurrentVoltage) > GVL_CONFIG.rMaxAbsDiffVoltageModulesInString THEN _xBalanceOk := FALSE; END_IF // Release signal for balance not ok _fbBalanceNotOkSignal( xSignal:= NOT _xBalanceOk, xRelease:= xEnable AND _xAllModulesReady, timOnDelay:= T#10S, timOffDelay:= T#10S, xReleaseSignal=> ); // Signal an error if all units are ready and module is out of balance IF _fbBalanceNotOkSignal.xReleaseSignal THEN xError := TRUE; END_IF // Raise error IF _fbBalanceNotOkSignal.xReleaseSignal AND (NOT _fbModulesOutOfBalanceAlarm.bRaised) THEN _fbModulesOutOfBalanceAlarm.Raise(0); END_IF // Clear error IF (NOT _fbBalanceNotOkSignal.xReleaseSignal) AND _fbModulesOutOfBalanceAlarm.bRaised AND xConfirmAlarms THEN _fbModulesOutOfBalanceAlarm.Clear(0, FALSE); END_IF // Confirm error IF _fbModulesOutOfBalanceAlarm.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xConfirmAlarms THEN _fbModulesOutOfBalanceAlarm.Confirm(0); END_IF // =============================== // String ready validation check // =============================== _tonResetPulseLength(); _tonErrorDCCBNotClosed(); _tonSafetyOkTimeout(); // =============================== // Get smalles segment voltage // of all units // =============================== rSmallestSegmentVoltage := MIN(_fbModule1.rSmallestSegmentVoltage, _fbModule2.rSmallestSegmentVoltage, _fbModule3.rSmallestSegmentVoltage); rHighestSegmentVoltage := MAX(_fbModule1.rHighestSegmentVoltage, _fbModule2.rHighestSegmentVoltage, _fbModule3.rHighestSegmentVoltage); // Only recalculate SOC if all modules are ready IF _xAllModulesReady THEN _rSOC := ((100.0 * rSmallestSegmentVoltage ) / 24.0) - 229.17; END_IF // Call inverter _fbInverter( sInverterIPAddr:= sInverterIP, xEnable:= _xEnableInverter AND xEmergencyStopOk, rPower:= _rPowerInverterInternal, xReset:= xConfirmAlarms, rMaxBattPower:= DINT_TO_REAL(GVL_CONFIG.diMaxStringDischargePower), stCurrentValues => stInverterData); IF (_iState >= 30) AND (_iState < 40) THEN rCapacityAH := rCapacityAH + ((stInverterData.rActDCCurrent * 0.01) / 3600); rCapacityWH := rCapacityWH + ((stInverterData.rActACPower * 0.01) / 3600); END_IF CASE _iState OF 0: // Idle // Start in normal mode IF xEnable AND (NOT xStartBalancing) AND xAllModulesInAutoMode AND xRepairSwitchOk AND (NOT _xModuleError) THEN _xEnable := TRUE; //eStatus := E_COMPONENT_STATUS.STARTING; IF xInSafetyCheckMode THEN _iState := 1; ELSE _iState := 5; END_IF END_IF // Start in balancing mode IF (NOT xEnable) AND xStartBalancing AND xAllModulesInAutoMode AND (NOT _xModuleError) THEN _xStartBalancing := TRUE; _xReleaseLimitErrorsInternal := FALSE; //eStatus := E_COMPONENT_STATUS.STARTING; _iState := 7; END_IF 1: // Wait for ready in safety check mode IF _xAllModulesReady THEN xResetSafetyDCCB := TRUE; _tonResetPulseLength.IN := TRUE; _iState := 10; END_IF 5: // Wait for all modules to be ready in normal mode IF _xAllModulesReady AND _xBalanceOk THEN xResetSafetyDCCB := TRUE; IF (NOT xInSafetyCheckMode) THEN _xReleaseLimitErrorsInternal := TRUE; END_IF _tonResetPulseLength.IN := TRUE; _iState := 10; END_IF IF (NOT xEnable) THEN _xEnable := FALSE; //eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF IF _xModuleError THEN _xEnable := FALSE; _iState := 1000; END_IF 7: // Wait for all modules to be ready in balancing mode IF _xAllModulesReady THEN _iState := 50; END_IF IF (NOT xStartBalancing) THEN _xStartBalancing := FALSE; //eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF IF _xModuleError THEN _xEnable := FALSE; _iState := 1000; END_IF 10: // Reset safety from sensors IF _tonResetPulseLength.Q THEN _tonResetPulseLength.IN := FALSE; xResetSafetyDCCB := FALSE; _tonSafetyOkTimeout.IN := TRUE; _iState := 15; END_IF 15: // Wait for Safety to be ok IF xSafetyIntlksOk THEN _tonSafetyOkTimeout.IN := FALSE; xCloseDCCB := TRUE; _tonErrorDCCBNotClosed.IN := TRUE; _iState := 20; END_IF IF (NOT xEnable) THEN _tonSafetyOkTimeout.IN := FALSE; _xEnable := FALSE; //eStatus := E_COMPONENT_STATUS.SHUTDOWN; _iState := 40; END_IF IF _tonSafetyOkTimeout.Q THEN _tonSafetyOkTimeout.IN := FALSE; xCloseDCCB := TRUE; xError := TRUE; xReady := FALSE; IF (NOT _fbSafetyIntlkTimeoutAlarm.bRaised) THEN _fbSafetyIntlkTimeoutAlarm.Raise(0); END_IF _iState := 1000; END_IF IF _xModuleError THEN _xEnable := FALSE; _iState := 1000; END_IF 20: // Check if DC relais closed and safety is ok IF NOT xDCCBOpen THEN _tonErrorDCCBNotClosed.IN := FALSE; _rPowerInverterInternal := rPowerInverter; //_rPowerInverterInternal := 0.0; IF xInSafetyCheckMode THEN _iState := 29; //eStatus := E_COMPONENT_STATUS.ON; ELSE _iState := 21; END_IF END_IF IF _tonErrorDCCBNotClosed.Q THEN _xEnable := FALSE; xCloseDCCB := FALSE; _tonErrorDCCBNotClosed.IN := FALSE; xError := TRUE; xReady := FALSE; _iState := 1000; END_IF IF (NOT xEnable) THEN _tonSafetyOkTimeout.IN := FALSE; _xEnable := FALSE; //eStatus := E_COMPONENT_STATUS.SHUTDOWN; _iState := 40; END_IF IF _xModuleError THEN _xEnable := FALSE; _iState := 1000; END_IF 21: // Wait some time for inverter dc bus voltage settling _fbTONDCSettlingTime(IN := TRUE); IF _fbTONDCSettlingTime.Q THEN _fbTONDCSettlingTime(IN := FALSE); _xEnableInverter := TRUE; _iState := 22; END_IF 22: // Wait for inverter to be ready _tonInverterStartupTimeout(IN := TRUE); IF _fbInverter.xActive AND (NOT _fbInverter.xError) THEN _iState := 30; //eStatus := E_COMPONENT_STATUS.ON; xReady := TRUE; _tonInverterStartupTimeout(IN := FALSE); END_IF IF (NOT xEnable) OR (NOT _xAllModulesReady) THEN _xEnableInverter := FALSE; _rPowerInverterInternal := 0.0; _xEnable := FALSE; //eStatus := E_COMPONENT_STATUS.SHUTDOWN; _iState := 31; _tonInverterStartupTimeout(IN := FALSE); END_IF // Inverter error or timeout for startup IF _fbInverter.xError OR (NOT xRepairSwitchOk) OR _tonInverterStartupTimeout.Q THEN // _tonInverterStartupTimeout.Q // Shutdown beacause of inverter startup timeout IF _tonInverterStartupTimeout.Q AND (NOT _fbInverterStartupTimeoutAlarm.bRaised) THEN _fbInverterStartupTimeoutAlarm.Raise(0); END_IF _iState := 1000; _xEnableInverter := FALSE; xError := TRUE; xErrorInverter := TRUE; _xEnable := FALSE; _tonInverterStartupTimeout(IN := FALSE); END_IF 29: // Ready in safety check mode IF (NOT xEnable) THEN _xEnable := FALSE; _xReleaseLimitErrorsInternal := FALSE; //eStatus := E_COMPONENT_STATUS.SHUTDOWN; _iState := 31; END_IF 30: // All modules ready // !!! ATTENTION !!! // BMS HAS TO SHUT DOWN THE INVERTER BEFORE DISSABLING THE STRING // OTHERWISE THE DC CIRCUIT BREAKERS WILL OPEN WHILE THE INVERTER IS STILL ACTIVE // THIS CAN DAMAGE THE INVERTER IF rPowerInverter > DINT_TO_REAL(GVL_CONFIG.diMaxStringDischargePower) THEN // Limit discharge power (> because discharging is a positive number) _rPowerInverterInternal := DINT_TO_REAL(GVL_CONFIG.diMaxStringDischargePower); ELSIF rPowerInverter < DINT_TO_REAL(GVL_CONFIG.diMaxStringChargingPower) THEN // Limit charging power (< because charging is a negative number) _rPowerInverterInternal := DINT_TO_REAL(GVL_CONFIG.diMaxStringChargingPower); ELSE // Power command within range _rPowerInverterInternal := rPowerInverter; END_IF (* IF _rPowerInverterInternal > 0.0 THEN eStatus := E_COMPONENT_STATUS.DISCHARGING; ELSIF _rPowerInverterInternal < 0.0 THEN eStatus := E_COMPONENT_STATUS.CHARGING; ELSE eStatus := E_COMPONENT_STATUS.ON; END_IF *) // Shutdown IF (NOT xEnable) THEN _xEnable := FALSE; _xReleaseLimitErrorsInternal := FALSE; IF GVL_CONFIG.xShutdownDischargeWithInverter THEN _rPowerInverterInternal := GVL_CONFIG.rAbsShutdownDischargePower; //eStatus := E_COMPONENT_STATUS.SHUTDOWN; _iState := 31; ELSE _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; //eStatus := E_COMPONENT_STATUS.SHUTDOWN; _iState := 40; END_IF ELSIF (NOT _xAllModulesReady) OR (NOT _xBalanceOk) OR (NOT xSafetyIntlksOk) OR (NOT xRepairSwitchOk) OR (_fbInverter.xError) THEN xError := TRUE; _xReleaseLimitErrorsInternal := FALSE; _xEnable := FALSE; _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; _iState := 1000; END_IF 31: // Wait for String to be in in shutdown discharge mode IF _xAllModulesInShutdownDischargeMode THEN _iState := 32; END_IF IF xError THEN _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; _iState := 40; END_IF 32: // Shutdown discharge mode IF xShutdownDischargeAllowed AND (NOT xErrorShutdown) AND GVL_CONFIG.xShutdownDischargeWithInverter AND xSafetyIntlksOk AND (stInverterData.rActDCVoltage > 620.0) THEN _rPowerInverterInternal := GVL_CONFIG.rAbsShutdownDischargePower; ELSE // Send shutdown message IF NOT xShutdownDischargeAllowed THEN _fbSDUnitThreshold.Send(0); END_IF IF (stInverterData.rActDCVoltage < 620.0) THEN _fbSDDCLevel.Send(0); END_IF _rPowerInverterInternal := 0.0; _xEnableInverter := FALSE; _iState := 40; END_IF // Restart on Enable or StartBalancing IF xEnable OR xStartBalancing THEN _rPowerInverterInternal := 0.0; //_xEnableInverter := FALSE; _iState := 0; END_IF 40: // Wait for inverter to shut down IF NOT _fbInverter.xActive THEN _iState := 41; END_IF 41: // Debug delay time for inverter shutdown _tonInverterShutdownDelay(IN := TRUE); IF _tonInverterShutdownDelay.Q THEN _tonInverterShutdownDelay(IN := FALSE); xCloseDCCB := FALSE; //eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF 50: // Wait for balancing of all units to be done IF _xBalancingDone THEN _xStartBalancing := FALSE; _iState := 51; END_IF 51: // Check if start balancing has been releases to avoid a restart IF (NOT xStartBalancing) THEN //eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF 1000: // Error state _xEnable := FALSE; _xEnableInverter := FALSE; _rPowerInverterInternal := 0.0; xError := TRUE; _xReleaseLimitErrorsInternal := FALSE; // Reset timer _tonResetPulseLength(IN := FALSE); _tonErrorDCCBNotClosed(IN := FALSE); //eStatus := E_COMPONENT_STATUS.ERROR; _iState := 1005; 1005: // Wait for inverter to be off _tonInverterShutdownError(IN := TRUE); // If inverter is not shutting down, hard disconnect it IF (NOT _fbInverter.xActive) OR _tonInverterShutdownError.Q THEN _tonInverterShutdownError(IN := FALSE); xCloseDCCB := FALSE; _iState := 1010; END_IF 1010: // Error idle state // Leave error state only if modules are deactivated IF (NOT xEnable) AND (NOT _xModuleError) THEN xError := FALSE; //eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF END_CASE // Copy inverter data to SCADA interface stHMIInterface.stInverterData := stInverterData; IF _xAllModulesReady AND _xBalanceOk AND ((_iState = 30) OR (_iState = 29)) THEN xReady := TRUE; ELSE xReady := FALSE; END_IF // Reset inverter startup timeout alarm IF _fbInverterStartupTimeoutAlarm.bRaised AND xConfirmAlarms THEN _fbInverterStartupTimeoutAlarm.Clear(0, TRUE); END_IF // Reset safetyinterlock timeout alarm IF _fbSafetyIntlkTimeoutAlarm.bRaised AND xConfirmAlarms THEN _fbInverterStartupTimeoutAlarm.Clear(0, TRUE); END_IF // Copy status to hmi interface stHMIInterface.eStatus := eStatus;]]>