Added multi string handling and balancing
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TcPlcObject Version="1.1.0.1" ProductVersion="3.1.4024.12">
|
||||
<TcPlcObject Version="1.1.0.1" ProductVersion="3.1.4026.8">
|
||||
<DUT Name="E_BMS_CONTROL_MODE" Id="{ab000a04-c252-420d-ac1e-2bf611fa911a}">
|
||||
<Declaration><![CDATA[{attribute 'qualified_only'}
|
||||
{attribute 'strict'}
|
||||
@@ -10,7 +10,9 @@ TYPE E_BMS_CONTROL_MODE :
|
||||
SAFETY_CHECK := 3,
|
||||
CAPACITY_TEST := 4,
|
||||
MANUAL := 5,
|
||||
BALANCING := 6
|
||||
BALANCING := 6,
|
||||
CYCLING := 7,
|
||||
PRECHARGE := 8
|
||||
);
|
||||
END_TYPE
|
||||
]]></Declaration>
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
<TcPlcObject Version="1.1.0.1" ProductVersion="3.1.4026.8">
|
||||
<GVL Name="GVL_CONFIG" Id="{0773bf51-0237-454d-a970-cfd896054edb}">
|
||||
<Declaration><![CDATA[{attribute 'qualified_only'}
|
||||
VAR_GLOBAL CONSTANT
|
||||
// ===========================
|
||||
// Number of active strings
|
||||
// ===========================
|
||||
uiNumberOfStrings : UINT := 2;
|
||||
END_VAR
|
||||
VAR_GLOBAL PERSISTENT
|
||||
// ===========================
|
||||
// Unit hardware config
|
||||
@@ -242,8 +248,8 @@ VAR_GLOBAL PERSISTENT
|
||||
rPumpNegolytOnPower : REAL := 65.0;
|
||||
|
||||
// Pump discharge segment without inverter power (%)
|
||||
rPumpPosolytDisChrgPower : REAL := 35.0;
|
||||
rPumpNegolytDisChrgPower : REAL := 35.0;
|
||||
rPumpPosolytDisChrgPower : REAL := 45.0;
|
||||
rPumpNegolytDisChrgPower : REAL := 45.0;
|
||||
|
||||
// Unit voltage pumps shutoff threshold (Volt)
|
||||
rPumpshutoffThreshold : REAL := 15.0;
|
||||
@@ -252,7 +258,7 @@ VAR_GLOBAL PERSISTENT
|
||||
rMinimumUnitVoltage : REAL := 55.0;
|
||||
|
||||
// Maximum unit voltage for fully charged (Volt)
|
||||
rMaximumUnitVoltage : REAL := 79.0;
|
||||
rMaximumUnitVoltage : REAL := 79.5;
|
||||
|
||||
// Delta value to minimum unit voltage for shutdown discharge (Volt)
|
||||
rDeltaUnitVoltageShutdownDischarge : REAL := 5.0;
|
||||
@@ -270,11 +276,11 @@ VAR_GLOBAL PERSISTENT
|
||||
|
||||
// Maximum allowed charging power (Watt) per String
|
||||
// 24.000 W -> 2.000 W per Unit
|
||||
diMaxStringChargingPower : DINT := -24_000;
|
||||
diMaxStringChargingPower : DINT := -50_000;
|
||||
|
||||
// Maximum allowed discharging power (Watt) per String
|
||||
// 24.000 W -> 2.000 W per Unit
|
||||
diMaxStringDischargePower : DINT := 24_000;
|
||||
diMaxStringDischargePower : DINT := 50_000;
|
||||
|
||||
// Inverter ip address for string 1
|
||||
sInverterIpString1 : STRING := '192.168.42.10';
|
||||
|
||||
@@ -111,6 +111,9 @@
|
||||
<Compile Include="POUs\FB_Module.TcPOU">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="POUs\FB_PowerMeter.TcPOU">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="POUs\FB_Safety.TcPOU">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
@@ -212,8 +215,8 @@
|
||||
<ProjectExtensions>
|
||||
<PlcProjectOptions>
|
||||
<XmlArchive>
|
||||
<Data>
|
||||
<o xml:space="preserve" t="OptionKey">
|
||||
<Data>
|
||||
<o xml:space="preserve" t="OptionKey">
|
||||
<v n="Name">"<ProjectRoot>"</v>
|
||||
<d n="SubKeys" t="Hashtable" ckt="String" cvt="OptionKey">
|
||||
<v>{192FAD59-8248-4824-A8DE-9177C94C195A}</v>
|
||||
@@ -2595,16 +2598,16 @@
|
||||
</d>
|
||||
<d n="Values" t="Hashtable" />
|
||||
</o>
|
||||
</Data>
|
||||
<TypeList>
|
||||
<Type n="Boolean">System.Boolean</Type>
|
||||
<Type n="Hashtable">System.Collections.Hashtable</Type>
|
||||
<Type n="Int32">System.Int32</Type>
|
||||
<Type n="OptionKey">{54dd0eac-a6d8-46f2-8c27-2f43c7e49861}</Type>
|
||||
<Type n="String">System.String</Type>
|
||||
<Type n="UInt32">System.UInt32</Type>
|
||||
</TypeList>
|
||||
</XmlArchive>
|
||||
</Data>
|
||||
<TypeList>
|
||||
<Type n="Boolean">System.Boolean</Type>
|
||||
<Type n="Hashtable">System.Collections.Hashtable</Type>
|
||||
<Type n="Int32">System.Int32</Type>
|
||||
<Type n="OptionKey">{54dd0eac-a6d8-46f2-8c27-2f43c7e49861}</Type>
|
||||
<Type n="String">System.String</Type>
|
||||
<Type n="UInt32">System.UInt32</Type>
|
||||
</TypeList>
|
||||
</XmlArchive>
|
||||
</PlcProjectOptions>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
406
PLC/PLC.tmc
406
PLC/PLC.tmc
File diff suppressed because one or more lines are too long
51
PLC/POUs/FB_PowerMeter.TcPOU
Normal file
51
PLC/POUs/FB_PowerMeter.TcPOU
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TcPlcObject Version="1.1.0.1" ProductVersion="3.1.4026.8">
|
||||
<POU Name="FB_PowerMeter" Id="{9d4159f4-2d3f-4522-a770-c038a26d9d77}" SpecialFunc="None">
|
||||
<Declaration><![CDATA[FUNCTION_BLOCK FB_PowerMeter
|
||||
VAR_INPUT
|
||||
xResetEnergyCounter : BOOL;
|
||||
END_VAR
|
||||
VAR_OUTPUT
|
||||
END_VAR
|
||||
VAR
|
||||
_fbReadRegs : FB_MBReadInputRegs;
|
||||
_fbWriteRegs : FB_MBWriteRegs;
|
||||
|
||||
_fbREResetEnergyCounter : R_TRIG;
|
||||
_xResetEnergyCounter : BOOL;
|
||||
|
||||
_iState : INT := 0;
|
||||
END_VAR
|
||||
]]></Declaration>
|
||||
<Implementation>
|
||||
<ST><![CDATA[_fbREResetEnergyCounter(CLK := xResetEnergyCounter);
|
||||
|
||||
IF _fbREResetEnergyCounter.Q THEN
|
||||
_xResetEnergyCounter := TRUE;
|
||||
END_IF
|
||||
|
||||
CASE _iState OF
|
||||
0: // Idle
|
||||
IF _xResetEnergyCounter THEN
|
||||
_xResetEnergyCounter := FALSE;
|
||||
_iState := 10;
|
||||
END_IF
|
||||
|
||||
10: // Reset energy counters
|
||||
_fbWriteRegs(
|
||||
sIPAddr:= '192.168.42.80',
|
||||
nTCPPort:= 502,
|
||||
nUnitID:= 16#FF ,
|
||||
nQuantity:= ,
|
||||
nMBAddr:= 16#0600,
|
||||
cbLength:= ,
|
||||
pSrcAddr:= ,
|
||||
bExecute:= ,
|
||||
tTimeout:= ,
|
||||
bBusy=> ,
|
||||
bError=> ,
|
||||
nErrId=> );
|
||||
END_CASE]]></ST>
|
||||
</Implementation>
|
||||
</POU>
|
||||
</TcPlcObject>
|
||||
@@ -140,6 +140,9 @@ VAR
|
||||
// Isolatio alarm
|
||||
_fbIsolationAlarm : FB_TcAlarm;
|
||||
|
||||
// Safety interlock reset timeout
|
||||
_fbSafetyIntlkTimeoutAlarm : FB_TcAlarm;
|
||||
|
||||
// Shutdown discharge stopped messages
|
||||
_fbSDDCLevel : FB_TcMessage;
|
||||
_fbSDUnitThreshold : FB_TcMessage;
|
||||
@@ -598,6 +601,9 @@ CASE _iState OF
|
||||
xCloseDCCB := TRUE;
|
||||
xError := TRUE;
|
||||
xReady := FALSE;
|
||||
IF (NOT _fbSafetyIntlkTimeoutAlarm.bRaised) THEN
|
||||
_fbSafetyIntlkTimeoutAlarm.Raise(0);
|
||||
END_IF
|
||||
_iState := 1000;
|
||||
END_IF
|
||||
|
||||
@@ -688,6 +694,14 @@ CASE _iState OF
|
||||
_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;
|
||||
@@ -815,7 +829,7 @@ END_CASE
|
||||
// Copy inverter data to SCADA interface
|
||||
stHMIInterface.stInverterData := stInverterData;
|
||||
|
||||
IF _xAllModulesReady AND _xBalanceOk AND (_iState = 30) THEN
|
||||
IF _xAllModulesReady AND _xBalanceOk AND ((_iState = 30) OR (_iState = 29)) THEN
|
||||
xReady := TRUE;
|
||||
ELSE
|
||||
xReady := FALSE;
|
||||
@@ -824,7 +838,15 @@ END_IF
|
||||
// Reset inverter startup timeout alarm
|
||||
IF _fbInverterStartupTimeoutAlarm.bRaised AND xConfirmAlarms THEN
|
||||
_fbInverterStartupTimeoutAlarm.Clear(0, TRUE);
|
||||
END_IF]]></ST>
|
||||
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;]]></ST>
|
||||
</Implementation>
|
||||
<Method Name="FB_init" Id="{9e8494eb-1b40-4be9-91c8-810ecbdf7f0c}">
|
||||
<Declaration><![CDATA[METHOD FB_init : BOOL
|
||||
@@ -867,6 +889,10 @@ _fbSCSConnLost.CreateEx(stEventEntry := TC_EVENTS.General.CommError, bWithConfir
|
||||
_sTemp := CONCAT(_sName, ' SCS');
|
||||
_fbSCSConnLost.ipArguments.Clear().AddString(_sTemp);
|
||||
|
||||
// Safety interlock reset timeout alarm
|
||||
_fbSafetyIntlkTimeoutAlarm.CreateEx(stEventEntry := TC_EVENTS.BMSEvents.SafetyIntlkTimeout, bWithConfirmation := TRUE, 0);
|
||||
_fbSafetyIntlkTimeoutAlarm.ipArguments.Clear().AddString(_sName);
|
||||
|
||||
// Shutdown discharge messages
|
||||
_fbSDDCLevel.CreateEx(TC_EVENTS.BMSEvents.SDDCVoltage, 0);
|
||||
_fbSDDCLevel.ipArguments.Clear().AddString(_sName);
|
||||
@@ -906,7 +932,8 @@ _fbInverter.Name := _sName;
|
||||
|
||||
// Create alarm messages
|
||||
_fbModulesOutOfBalanceAlarm.ipArguments.Clear().AddString(_sName);
|
||||
_fbSafetyInterlocksNotOkAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
|
||||
_fbSafetyInterlocksNotOkAlarm.ipArguments.Clear().AddString(_sName);
|
||||
_fbSafetyIntlkTimeoutAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
|
||||
</Implementation>
|
||||
</Set>
|
||||
</Property>
|
||||
|
||||
@@ -237,11 +237,14 @@ END_VAR
|
||||
_fbNegolytPumpInlet.Name := CONCAT(_sName, ' - Negolyt segment inlet');
|
||||
stHMIInterface.stNS21.sName := 'Negolyt segment inlet';
|
||||
|
||||
_fbPressurePosolytSegmentInlet.Name := CONCAT(_sName, ' - Posolyt Segment Inlet');
|
||||
_fbPressurePosolytTankInlet.Name := CONCAT(_sName, ' - Posolyt Tank inlet');
|
||||
_fbPressurePosolytSegmentInlet.Name := CONCAT(_sName, ' - Pressure Posolyt Segment Inlet');
|
||||
_fbPressurePosolytTankInlet.Name := CONCAT(_sName, ' - Pressure Posolyt Tank inlet');
|
||||
|
||||
_fbPressureNegolytSegmentInlet.Name := CONCAT(_sName, ' - Negolyt Segment Inlet');
|
||||
_fbPressureNegolytTankInlet.Name := CONCAT(_sName, ' - Negolyt 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');
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -797,8 +797,8 @@ CASE _iState OF
|
||||
IF _tonPollingTimer.Q THEN
|
||||
_tonPollingTimer(IN := FALSE);
|
||||
_iState := 70;
|
||||
ELSIF ABS(rPower - _rOldPower) > 0.1 THEN
|
||||
_tonPollingTimer(IN := FALSE);
|
||||
ELSIF (ABS(rPower - _rOldPower) > 0.1) THEN
|
||||
//_tonPollingTimer(IN := FALSE);
|
||||
// If power has ben changed, goto set power limit mode
|
||||
_iState := 40;
|
||||
// Calculate power to write to register
|
||||
|
||||
Reference in New Issue
Block a user