|
|
|
|
@@ -134,6 +134,21 @@ VAR
|
|
|
|
|
|
|
|
|
|
_fbStringReadyTimeout : TON;
|
|
|
|
|
|
|
|
|
|
// Sum of voltage of all active strings
|
|
|
|
|
_rStringsSumVoltage : REAL;
|
|
|
|
|
_arPowerString : ARRAY[0..(GVL_CONFIG.uiNumberOfStrings-1)] OF REAL;
|
|
|
|
|
|
|
|
|
|
_ui : UINT := 0;
|
|
|
|
|
_xStringsReady : BOOL;
|
|
|
|
|
_xStringsErrorActive : BOOL;
|
|
|
|
|
_xStringsInSchutdownDischargeMode : BOOL;
|
|
|
|
|
_xStringsShutdownDischargeAllowed : BOOL;
|
|
|
|
|
_xStringsAllInAutomaticMode : BOOL;
|
|
|
|
|
_xStringsOff : BOOL;
|
|
|
|
|
|
|
|
|
|
_rMaxCurrentInverterDCVoltage : REAL;
|
|
|
|
|
_rMinCurrentInverterDCVoltage : REAL;
|
|
|
|
|
|
|
|
|
|
_fbModbusRead : FB_MBReadRegs;
|
|
|
|
|
_wLength : WORD := 49;
|
|
|
|
|
xDebugTest : BOOL;
|
|
|
|
|
@@ -286,15 +301,15 @@ _tonStartupDelay(IN := TRUE);
|
|
|
|
|
// Call string 1
|
|
|
|
|
_afbStrings[0](
|
|
|
|
|
stStringModuleVoltageConfig := GVL_CONFIG.stString1VoltageConfig,
|
|
|
|
|
xEnable := _xEnableString, //AND GVL_CONFIG.xDummy,
|
|
|
|
|
xStartBalancing := _xStartBalancing, // AND GVL_CONFIG.xDummy,
|
|
|
|
|
xEnable := _xEnableString,
|
|
|
|
|
xStartBalancing := _xStartBalancing,
|
|
|
|
|
sInverterIP := GVL_CONFIG.sInverterIpString1,
|
|
|
|
|
rPowerInverter := _rPowerInverter,
|
|
|
|
|
rPowerInverter := _arPowerString[0],
|
|
|
|
|
xInSafetyCheckMode := _xInSafetyCheckMode,
|
|
|
|
|
stHMIInterface:= GVL_SCADA.stHMIInterface[0],
|
|
|
|
|
xEmergencyStopOk:= _xEmergencyStopOk,
|
|
|
|
|
xReleaseErrors:= _xReleaseErrors AND _tonStartupDelay.Q AND _xEtherCatString1Ok,
|
|
|
|
|
xReleaseLimitErrors:= _xReleaseLimitsErrors AND _tonStartupDelay.Q,
|
|
|
|
|
xReleaseLimitErrors:= _xReleaseLimitsErrors AND _tonStartupDelay.Q AND _xEtherCatString1Ok,
|
|
|
|
|
xReleaseManualMode := _xReleaseManualMode,
|
|
|
|
|
xConfirmAlarms:= _xConfirmAlarms,
|
|
|
|
|
xAllToManualMode := _xAllComponentsToManualMode,
|
|
|
|
|
@@ -310,11 +325,11 @@ _afbStrings[1](
|
|
|
|
|
xEnable := _xEnableString,
|
|
|
|
|
xStartBalancing := _xStartBalancing,
|
|
|
|
|
sInverterIP := GVL_CONFIG.sInverterIpString2,
|
|
|
|
|
rPowerInverter := _rPowerInverter,
|
|
|
|
|
rPowerInverter := _arPowerString[1],
|
|
|
|
|
xInSafetyCheckMode := _xInSafetyCheckMode,
|
|
|
|
|
stHMIInterface:= GVL_SCADA.stHMIInterface[1],
|
|
|
|
|
xEmergencyStopOk:= _xEmergencyStopOk,
|
|
|
|
|
xReleaseErrors:= _xReleaseErrors AND _tonStartupDelay.Q AND _xEtherCatString2Ok AND FALSE,
|
|
|
|
|
xReleaseErrors:= _xReleaseErrors AND _tonStartupDelay.Q AND _xEtherCatString2Ok,
|
|
|
|
|
xReleaseLimitErrors:= _xReleaseLimitsErrors AND _tonStartupDelay.Q AND _xEtherCatString2Ok,
|
|
|
|
|
xReleaseManualMode := _xReleaseManualMode,
|
|
|
|
|
xConfirmAlarms:= _xConfirmAlarms,
|
|
|
|
|
@@ -325,12 +340,85 @@ IF _afbStrings[1].xError THEN
|
|
|
|
|
_xErrorActive := TRUE;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// ===============================
|
|
|
|
|
// Get global string status information
|
|
|
|
|
// ===============================
|
|
|
|
|
_xStringsReady := TRUE;
|
|
|
|
|
_xStringsErrorActive := FALSE;
|
|
|
|
|
_xStringsInSchutdownDischargeMode := FALSE;
|
|
|
|
|
_xStringsShutdownDischargeAllowed := TRUE;
|
|
|
|
|
_xStringsAllInAutomaticMode := TRUE;
|
|
|
|
|
_xStringsOff := TRUE;
|
|
|
|
|
_rMaxCurrentInverterDCVoltage := 0.0;
|
|
|
|
|
_rMinCurrentInverterDCVoltage := 10_000;
|
|
|
|
|
_rHighestSegmentVoltage := 0.0;
|
|
|
|
|
_rSmallestSegmentVoltage := 1_000.0;
|
|
|
|
|
|
|
|
|
|
FOR _ui := 0 TO (GVL_CONFIG.uiNumberOfStrings-1) DO
|
|
|
|
|
// Check ready state
|
|
|
|
|
IF (NOT _afbStrings[_ui].xReady) THEN
|
|
|
|
|
_xStringsReady := FALSE;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check error state
|
|
|
|
|
IF _afbStrings[_ui].xError THEN
|
|
|
|
|
_xStringsErrorActive := TRUE;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for shutdown discharge mode
|
|
|
|
|
IF _afbStrings[_ui].xInShutdownDischargeMode THEN
|
|
|
|
|
_xStringsInSchutdownDischargeMode := TRUE;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for shutdown discharge allowed
|
|
|
|
|
IF (NOT _afbStrings[_ui].xShutdownDischargeAllowed) THEN
|
|
|
|
|
_xStringsShutdownDischargeAllowed := FALSE;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for all in automatic mode
|
|
|
|
|
IF (NOT _afbStrings[_ui].xAllModulesInAutoMode) THEN
|
|
|
|
|
_xStringsAllInAutomaticMode := FALSE;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for all strings off
|
|
|
|
|
IF (NOT _afbStrings[_ui].xOff) THEN
|
|
|
|
|
_xStringsOff := FALSE;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for max dc voltage
|
|
|
|
|
IF _rMaxCurrentInverterDCVoltage < _afbStrings[_ui].stInverterData.rActDCVoltage THEN
|
|
|
|
|
_rMaxCurrentInverterDCVoltage := _afbStrings[_ui].stInverterData.rActDCVoltage;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for min DC voltage
|
|
|
|
|
IF _rMinCurrentInverterDCVoltage > _afbStrings[_ui].stInverterData.rActDCVoltage THEN
|
|
|
|
|
_rMinCurrentInverterDCVoltage := _afbStrings[_ui].stInverterData.rActDCVoltage;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Calculate highest segment voltage
|
|
|
|
|
IF _rSmallestSegmentVoltage > _afbStrings[_ui].rSmallestSegmentVoltage THEN
|
|
|
|
|
_rSmallestSegmentVoltage := _afbStrings[_ui].rSmallestSegmentVoltage;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Calculate lowest segment voltage
|
|
|
|
|
IF _rHighestSegmentVoltage < _afbStrings[_ui].rHighestSegmentVoltage THEN
|
|
|
|
|
_rHighestSegmentVoltage := _afbStrings[_ui].rHighestSegmentVoltage;
|
|
|
|
|
END_IF
|
|
|
|
|
END_FOR
|
|
|
|
|
|
|
|
|
|
// ===============================
|
|
|
|
|
// Calculate sum power for string balancing
|
|
|
|
|
// ===============================
|
|
|
|
|
_rStringsSumVoltage := _afbStrings[0].rCurrentVoltage + _afbStrings[1].rCurrentVoltage;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ===============================
|
|
|
|
|
// Hardware reset button part 2
|
|
|
|
|
// ===============================
|
|
|
|
|
_xShowErrorOnButton := _xErrorActive;
|
|
|
|
|
|
|
|
|
|
// HMI Feedback
|
|
|
|
|
(*
|
|
|
|
|
GVL_SCADA.stHMIInterface[0].rVoltage := _afbStrings[0].rCurrentVoltage;
|
|
|
|
|
IF _afbStrings[0].eStatus = E_COMPONENT_STATUS.ON THEN
|
|
|
|
|
IF _iState = 30 AND _rPowerInverter > 0 THEN
|
|
|
|
|
@@ -343,6 +431,7 @@ IF _afbStrings[0].eStatus = E_COMPONENT_STATUS.ON THEN
|
|
|
|
|
ELSE
|
|
|
|
|
GVL_SCADA.stHMIInterface[0].eStatus :=_afbStrings[0].eStatus;
|
|
|
|
|
END_IF
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
// ===============================
|
|
|
|
|
// Read modbus request count
|
|
|
|
|
@@ -381,25 +470,25 @@ _fbModbusRead(
|
|
|
|
|
// Copy data to modbus registers
|
|
|
|
|
// ===============================
|
|
|
|
|
// Modbus current inverter values
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diCurrentActivePower := REAL_TO_DINT(_afbStrings[_uiDebugCurrentString].stInverterData.rActACPower);
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diCurrentReactivePower := REAL_TO_DINT(_afbStrings[_uiDebugCurrentString].stInverterData.rActReactivePower);
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase1 := REAL_TO_DINT(_afbStrings[_uiDebugCurrentString].stInverterData.rActtACPhaseACurrent);
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase2 := REAL_TO_DINT(_afbStrings[_uiDebugCurrentString].stInverterData.rActtACPhaseBCurrent);
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase3 := REAL_TO_DINT(_afbStrings[_uiDebugCurrentString].stInverterData.rActtACPhaseCCurrent);
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diCurrentActivePower := 0;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diCurrentReactivePower := 0;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase1 := 0;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase2 := 0;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase3 := 0;
|
|
|
|
|
FOR _ui := 0 TO (GVL_CONFIG.uiNumberOfStrings-1) DO
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diCurrentActivePower := GVL_MODBUS.stModbusEMSComm.stModbusReg11.diCurrentActivePower + REAL_TO_DINT(_afbStrings[_ui].stInverterData.rActACPower);
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diCurrentReactivePower := GVL_MODBUS.stModbusEMSComm.stModbusReg11.diCurrentReactivePower + REAL_TO_DINT(_afbStrings[_ui].stInverterData.rActReactivePower);
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase1 := GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase1 + REAL_TO_DINT(_afbStrings[_ui].stInverterData.rActtACPhaseACurrent);
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase2 := GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase2 + REAL_TO_DINT(_afbStrings[_ui].stInverterData.rActtACPhaseBCurrent);
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase3 := GVL_MODBUS.stModbusEMSComm.stModbusReg11.diTotalACCurrentPhase3 + REAL_TO_DINT(_afbStrings[_ui].stInverterData.rActtACPhaseCCurrent);
|
|
|
|
|
END_FOR
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set Modbus mirror values
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.diSetpointActivePowerMirror := GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.rSetpointCosPhiMirror := GVL_MODBUS.stModbusEMSComm.stModbusReg12.rSetpointCosPhi;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ===============================
|
|
|
|
|
// Calculate highest and lowest
|
|
|
|
|
// segment voltage
|
|
|
|
|
// ===============================
|
|
|
|
|
_rSmallestSegmentVoltage := _afbStrings[_uiDebugCurrentString].rSmallestSegmentVoltage;
|
|
|
|
|
_rHighestSegmentVoltage := _afbStrings[_uiDebugCurrentString].rHighestSegmentVoltage;
|
|
|
|
|
|
|
|
|
|
// ===============================
|
|
|
|
|
// State machine
|
|
|
|
|
// ===============================
|
|
|
|
|
@@ -464,6 +553,16 @@ CASE _eBMSControlMode OF
|
|
|
|
|
_eBMSControlMode := GVL_SCADA.eRequestedControlMode;
|
|
|
|
|
END_IF
|
|
|
|
|
SM_BALANCING();
|
|
|
|
|
|
|
|
|
|
E_BMS_CONTROL_MODE.CYCLING:
|
|
|
|
|
_xAllComponentsToManualMode := FALSE;
|
|
|
|
|
_xInSafetyCheckMode := FALSE;
|
|
|
|
|
_xReleaseManualMode := FALSE;
|
|
|
|
|
_rAutoPowerRequest := DINT_TO_REAL(GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower);
|
|
|
|
|
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
|
|
|
|
|
_eBMSControlMode := GVL_SCADA.eRequestedControlMode;
|
|
|
|
|
END_IF
|
|
|
|
|
SM_AUTO();
|
|
|
|
|
END_CASE
|
|
|
|
|
|
|
|
|
|
GVL_SCADA.xCanChangeControlMode := _xCanChangeMode;
|
|
|
|
|
@@ -514,13 +613,13 @@ END_IF]]></ST>
|
|
|
|
|
10: // Wait for string to be ready
|
|
|
|
|
_fbStringReadyTimeout(IN := TRUE, PT := GVL_CONFIG.timStringReadyTimeout);
|
|
|
|
|
|
|
|
|
|
IF _afbStrings[_uiDebugCurrentString].xReady AND (NOT _afbStrings[_uiDebugCurrentString].xError) THEN
|
|
|
|
|
IF _xStringsReady AND (NOT _xStringsErrorActive) THEN
|
|
|
|
|
_fbStringReadyTimeout(IN := FALSE);
|
|
|
|
|
_rPowerInverter := 0.0;
|
|
|
|
|
_iState := 30;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
IF _afbStrings[_uiDebugCurrentString].xError OR _fbStringReadyTimeout.Q THEN
|
|
|
|
|
IF _xStringsErrorActive OR _fbStringReadyTimeout.Q THEN
|
|
|
|
|
_fbStringReadyTimeout(IN := FALSE);
|
|
|
|
|
_xEnableString := FALSE;
|
|
|
|
|
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
|
|
|
|
|
@@ -528,6 +627,7 @@ END_IF]]></ST>
|
|
|
|
|
_iState := 45;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IF (ABS(_rAutoPowerRequest) < DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) THEN
|
|
|
|
|
_fbStringReadyTimeout(IN := FALSE);
|
|
|
|
|
_xEnableString := FALSE;
|
|
|
|
|
@@ -574,51 +674,65 @@ END_IF]]></ST>
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Shutdown triggered by battery fully charged
|
|
|
|
|
IF GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus = E_CHARGE_STATUS.CHARGING AND ((_afbStrings[_uiDebugCurrentString].stInverterData.rActDCVoltage >= GVL_CONFIG.rStringFullyChargedVoltage) OR _rHighestSegmentVoltage >= GVL_CONFIG.rMaximumUnitVoltage) THEN
|
|
|
|
|
_tonBeginShutdown(In := FALSE);
|
|
|
|
|
IF GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus = E_CHARGE_STATUS.CHARGING AND ((_rMaxCurrentInverterDCVoltage >= GVL_CONFIG.rStringFullyChargedVoltage) OR _rHighestSegmentVoltage >= GVL_CONFIG.rMaximumUnitVoltage) THEN
|
|
|
|
|
|
|
|
|
|
// Send message
|
|
|
|
|
_fbBatteryFullMessage.Send(0);
|
|
|
|
|
IF (_eBMSControlMode = E_BMS_CONTROL_MODE.CYCLING) THEN
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower := GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower * -1;
|
|
|
|
|
// Change of charge discharge should be handled in next cycle by sasme state
|
|
|
|
|
// GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.DISCHARGING;
|
|
|
|
|
ELSE
|
|
|
|
|
_tonBeginShutdown(In := FALSE);
|
|
|
|
|
|
|
|
|
|
// Send message
|
|
|
|
|
_fbBatteryFullMessage.Send(0);
|
|
|
|
|
|
|
|
|
|
// Set inverter to zero power
|
|
|
|
|
_rPowerInverter := 0.0;
|
|
|
|
|
|
|
|
|
|
// Set local remote to zero power
|
|
|
|
|
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
|
|
|
|
|
|
|
|
|
|
// Start string shutdown
|
|
|
|
|
_xEnableString := FALSE;
|
|
|
|
|
|
|
|
|
|
// Change battery status
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.FULL;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
|
|
|
|
|
_iState := 35;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Set inverter to zero power
|
|
|
|
|
_rPowerInverter := 0.0;
|
|
|
|
|
|
|
|
|
|
// Set local remote to zero power
|
|
|
|
|
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
|
|
|
|
|
|
|
|
|
|
// Start string shutdown
|
|
|
|
|
_xEnableString := FALSE;
|
|
|
|
|
|
|
|
|
|
// Change battery status
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.FULL;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
|
|
|
|
|
_iState := 35;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Shutdown triggered by battery empty
|
|
|
|
|
IF GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus = E_CHARGE_STATUS.DISCHARGING AND ((_afbStrings[_uiDebugCurrentString].stInverterData.rActDCVoltage <= GVL_CONFIG.rStringEmptyVoltage) OR _rSmallestSegmentVoltage <= GVL_CONFIG.rMinimumUnitVoltage) THEN
|
|
|
|
|
_tonBeginShutdown(In := FALSE);
|
|
|
|
|
IF GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus = E_CHARGE_STATUS.DISCHARGING AND ((_rMinCurrentInverterDCVoltage <= GVL_CONFIG.rStringEmptyVoltage) OR _rSmallestSegmentVoltage <= GVL_CONFIG.rMinimumUnitVoltage) THEN
|
|
|
|
|
IF (_eBMSControlMode = E_BMS_CONTROL_MODE.CYCLING) THEN
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower := GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower * -1;
|
|
|
|
|
// Change of charge discharge should be handled in next cycle by sasme state
|
|
|
|
|
// GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.CHARGING;
|
|
|
|
|
ELSE
|
|
|
|
|
_tonBeginShutdown(In := FALSE);
|
|
|
|
|
|
|
|
|
|
// Send Message
|
|
|
|
|
_fbBatteryEmptyMessage.Send(0);
|
|
|
|
|
|
|
|
|
|
// Set local remote to zero power
|
|
|
|
|
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
|
|
|
|
|
|
|
|
|
|
// Set inverter to zero power
|
|
|
|
|
_rPowerInverter := 0.0;
|
|
|
|
|
|
|
|
|
|
// Start string shutdown
|
|
|
|
|
_xEnableString := FALSE;
|
|
|
|
|
|
|
|
|
|
// Change battery status
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.EMPTY;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
|
|
|
|
|
_iState := 35;
|
|
|
|
|
// Send Message
|
|
|
|
|
_fbBatteryEmptyMessage.Send(0);
|
|
|
|
|
|
|
|
|
|
// Set local remote to zero power
|
|
|
|
|
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
|
|
|
|
|
|
|
|
|
|
// Set inverter to zero power
|
|
|
|
|
_rPowerInverter := 0.0;
|
|
|
|
|
|
|
|
|
|
// Start string shutdown
|
|
|
|
|
_xEnableString := FALSE;
|
|
|
|
|
|
|
|
|
|
// Change battery status
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.EMPTY;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg10.uiActiveParallelMembers := 0;
|
|
|
|
|
_iState := 35;
|
|
|
|
|
END_IF
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for errors
|
|
|
|
|
IF _afbStrings[_uiDebugCurrentString].xError THEN
|
|
|
|
|
IF _xStringsErrorActive THEN
|
|
|
|
|
_xEnableString := FALSE;
|
|
|
|
|
_tonBeginShutdown(In := FALSE);
|
|
|
|
|
GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic := 0;
|
|
|
|
|
@@ -627,7 +741,7 @@ END_IF]]></ST>
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
35: // Wait for string to be in shutdown discharge mode
|
|
|
|
|
IF _afbStrings[_uiDebugCurrentString].xInShutdownDischargeMode THEN
|
|
|
|
|
IF _xStringsInSchutdownDischargeMode THEN
|
|
|
|
|
// Check if we are allowed to discharge during shutdown with inverter
|
|
|
|
|
IF GVL_CONFIG.xShutdownDischargeWithInverter THEN
|
|
|
|
|
_iState := 40;
|
|
|
|
|
@@ -641,12 +755,12 @@ END_IF]]></ST>
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for errors
|
|
|
|
|
IF _afbStrings[_uiDebugCurrentString].xError THEN
|
|
|
|
|
IF _xStringsErrorActive THEN
|
|
|
|
|
_iState := 1000;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
40: // Wait for inverter discharge done
|
|
|
|
|
IF _afbStrings[_uiDebugCurrentString].xShutdownDischargeAllowed THEN
|
|
|
|
|
IF _xStringsShutdownDischargeAllowed THEN
|
|
|
|
|
_rPowerInverter := GVL_CONFIG.rAbsShutdownDischargePower;
|
|
|
|
|
ELSE
|
|
|
|
|
_rPowerInverter := 0.0;
|
|
|
|
|
@@ -657,29 +771,30 @@ END_IF]]></ST>
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for errors
|
|
|
|
|
IF _afbStrings[_uiDebugCurrentString].xError THEN
|
|
|
|
|
IF _xStringsErrorActive THEN
|
|
|
|
|
_iState := 1000;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Restart if possible
|
|
|
|
|
IF (ABS(_rAutoPowerRequest) > DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) AND (NOT _afbStrings[_uiDebugCurrentString].xError) AND _afbStrings[_uiDebugCurrentString].xAllModulesInAutoMode THEN
|
|
|
|
|
IF (ABS(_rAutoPowerRequest) > DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) AND (NOT _xStringsErrorActive) AND _xStringsAllInAutomaticMode THEN
|
|
|
|
|
_iState := 5;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
45: // Wait for shutdown of string to be done
|
|
|
|
|
IF (NOT _afbStrings[_uiDebugCurrentString].xInShutdownDischargeMode) AND _afbStrings[_uiDebugCurrentString].xOff THEN
|
|
|
|
|
IF (NOT _xStringsInSchutdownDischargeMode) AND _xStringsOff THEN
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.OFF;
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eChargeStatus := E_CHARGE_STATUS.UNDEFINED;
|
|
|
|
|
_iState := 0;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Restart if possible
|
|
|
|
|
IF (ABS(_rAutoPowerRequest) > DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) AND (NOT _afbStrings[_uiDebugCurrentString].xError) AND _afbStrings[_uiDebugCurrentString].xAllModulesInAutoMode THEN
|
|
|
|
|
IF (ABS(_rAutoPowerRequest) > DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) AND (NOT _xStringsErrorActive) AND _xStringsAllInAutomaticMode THEN
|
|
|
|
|
_xCanChangeMode := FALSE;
|
|
|
|
|
_iState := 5;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for errors
|
|
|
|
|
IF _afbStrings[_uiDebugCurrentString].xError THEN
|
|
|
|
|
IF _xStringsErrorActive THEN
|
|
|
|
|
_iState := 1000;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
@@ -691,7 +806,7 @@ END_IF]]></ST>
|
|
|
|
|
_iState := 1010;
|
|
|
|
|
|
|
|
|
|
1010: // Wait for reset from error state
|
|
|
|
|
IF (_rAutoPowerRequest = 0.0) AND (NOT _afbStrings[_uiDebugCurrentString].xError) AND _xConfirmAlarms THEN
|
|
|
|
|
IF (_rAutoPowerRequest = 0.0) AND (NOT _xStringsErrorActive) AND _xConfirmAlarms THEN
|
|
|
|
|
// Reset modbus error register
|
|
|
|
|
GVL_MODBUS.stModbusEMSComm.stModbusReg11.lwErrorBitmap := 0;
|
|
|
|
|
|
|
|
|
|
@@ -703,7 +818,28 @@ END_IF]]></ST>
|
|
|
|
|
|
|
|
|
|
_xCanChangeMode := TRUE;
|
|
|
|
|
END_IF
|
|
|
|
|
END_CASE]]></ST>
|
|
|
|
|
END_CASE
|
|
|
|
|
|
|
|
|
|
// Calculate string power balancing
|
|
|
|
|
IF _rStringsSumVoltage <> 0 THEN
|
|
|
|
|
FOR _ui := 0 TO (GVL_CONFIG.uiNumberOfStrings-1) DO
|
|
|
|
|
// Discharging
|
|
|
|
|
IF _rPowerInverter > 0 THEN
|
|
|
|
|
_arPowerString[_ui] := _rPowerInverter * (_afbStrings[_ui].rCurrentVoltage / _rStringsSumVoltage);
|
|
|
|
|
// Charging
|
|
|
|
|
ELSIF _rPowerInverter < 0 THEN
|
|
|
|
|
_arPowerString[_ui] := _rPowerInverter * (1.0 - (_afbStrings[_ui].rCurrentVoltage / _rStringsSumVoltage));
|
|
|
|
|
// Nothing
|
|
|
|
|
ELSE
|
|
|
|
|
_arPowerString[_ui] := 0.0;
|
|
|
|
|
END_IF
|
|
|
|
|
END_FOR
|
|
|
|
|
ELSE
|
|
|
|
|
FOR _ui := 0 TO (GVL_CONFIG.uiNumberOfStrings-1) DO
|
|
|
|
|
_arPowerString[_ui] := 0.0;
|
|
|
|
|
END_FOR
|
|
|
|
|
END_IF
|
|
|
|
|
]]></ST>
|
|
|
|
|
</Implementation>
|
|
|
|
|
</Action>
|
|
|
|
|
<Action Name="SM_BALANCING" Id="{f1f90032-de29-468d-899c-50bfb54e48e0}">
|
|
|
|
|
@@ -760,6 +896,11 @@ END_CASE]]></ST>
|
|
|
|
|
<ST><![CDATA[_xCanChangeMode := TRUE;]]></ST>
|
|
|
|
|
</Implementation>
|
|
|
|
|
</Action>
|
|
|
|
|
<Action Name="SM_PRECHARGE" Id="{b84aedc8-0039-40a2-8abe-a166eca7bebc}">
|
|
|
|
|
<Implementation>
|
|
|
|
|
<ST><![CDATA[]]></ST>
|
|
|
|
|
</Implementation>
|
|
|
|
|
</Action>
|
|
|
|
|
<Action Name="SM_SAFETY_CHECK" Id="{6d8e5993-cf32-4980-9ea3-c1fbfa4b8601}">
|
|
|
|
|
<Implementation>
|
|
|
|
|
<ST><![CDATA[// Start on start button pressed
|
|
|
|
|
@@ -796,6 +937,7 @@ CASE _iStateSafetyCheck OF
|
|
|
|
|
IF NOT _xStartSafetyCheck THEN
|
|
|
|
|
_xEnableString := FALSE;
|
|
|
|
|
_iStateSafetyCheck := 0;
|
|
|
|
|
_xCanChangeMode := TRUE;
|
|
|
|
|
END_IF
|
|
|
|
|
|
|
|
|
|
// Check for errors
|
|
|
|
|
|