EMS communication and Voltage optimizations

- Added data for EMS communication
- Added highest segment voltage for charging check
- Added lowest segment voltage for discharging check
This commit is contained in:
Matthias Heisig
2024-05-07 17:10:29 +02:00
parent 327f324be8
commit 0ffff9be2a
11 changed files with 660 additions and 383 deletions

View File

@@ -55,51 +55,56 @@ STRUCT
uiCurrentDOD : UINT;
// Addr: 11.019
// Request from energielenker
// Wanted to start on a even register number
//uiDummy : UINT;
// Addr: 11.020
// Unit: Wh
udiChargedEnergy : UDINT;
// Addr: 11.021
// Addr: 11.022
// Unit: Wh
udiAvailableEnergy : UDINT;
// Addr: 11.023
// Addr: 11.024
// Unit: %
uiCurrentSOH : UINT := 100;
// Addr: 11.024
// Addr: 11.025
// Unit: A
diTotalACCurrentPhase1 : DINT;
// Addr: 11.026
// Addr: 11.027
// Unit: A
diTotalACCurrentPhase2 : DINT;
// Addr: 11.028
// Addr: 11.029
// Unit: A
diTotalACCurrentPhase3 : DINT;
// Addr: 11.030
// Addr: 11.031
// Unit: W
diSetpointActivePowerMirror : DINT;
// Addr: 11.032
// Addr: 11.033
rSetpointCosPhiMirror : REAL; // 32 bit
// Addr: 11.034
// Addr: 11.035
// Unit: W
diCurrentActivePower : DINT;
// Addr: 11.036
// Addr: 11.037
// Unit: var
diCurrentReactivePower : DINT;
// Addr: 11.038
// Addr: 11.039
udiLifeMessage : UDINT;
// Addr: 11.040
// Addr: 11.041
lwWarningBitmap : LWORD;
// Addr: 11.044
// Addr: 11.045
lwErrorBitmap : LWORD;
END_STRUCT
END_TYPE

View File

@@ -11,6 +11,7 @@ STRUCT
rSetpointCosPhi : REAL;
// Addr: 12.004
// Can be removed if cosphi can be written in pos and neg range
eReactivePowerType : E_REACTIVE_POWER_TYPE;
END_STRUCT
END_TYPE

View File

@@ -251,6 +251,9 @@ VAR_GLOBAL PERSISTENT
// Minimum unit voltage required for inverter startup (Volt)
rMinimumUnitVoltage : REAL := 55.0;
// Maximum unit voltage for fully charged (Volt)
rMaximumUnitVoltage : REAL := 79.0;
// Delta value to minimum unit voltage for shutdown discharge (Volt)
rDeltaUnitVoltageShutdownDischarge : REAL := 5.0;

View File

@@ -127,6 +127,10 @@
<DefaultResolution>BaseLib, * (cmblu)</DefaultResolution>
<Namespace>BaseLib</Namespace>
</PlaceholderReference>
<PlaceholderReference Include="Tc2_ModbusRTU">
<DefaultResolution>Tc2_ModbusRTU, * (Beckhoff Automation GmbH)</DefaultResolution>
<Namespace>Tc2_ModbusRTU</Namespace>
</PlaceholderReference>
<PlaceholderReference Include="Tc2_ModbusSrv">
<DefaultResolution>Tc2_ModbusSrv, * (Beckhoff Automation GmbH)</DefaultResolution>
<Namespace>Tc2_ModbusSrv</Namespace>

File diff suppressed because one or more lines are too long

View File

@@ -70,6 +70,9 @@ VAR_OUTPUT
// Smallest segment voltage
rSmallestSegmentVoltage : REAL;
// Highest segment voltage
rHighestSegmentVoltage : REAL;
// Balancing done
xBalancingDone : BOOL;
END_VAR
@@ -377,7 +380,7 @@ END_IF
// for balancing
// ===============================
rSmallestSegmentVoltage := MIN(_fbUnit1.rCurrentVoltage, _fbUnit2.rCurrentVoltage, _fbUnit3.rCurrentVoltage, _fbUnit4.rCurrentVoltage);
rHighestSegmentVoltage := MAX(_fbUnit1.rCurrentVoltage, _fbUnit2.rCurrentVoltage, _fbUnit3.rCurrentVoltage, _fbUnit4.rCurrentVoltage);
// ===============================
// Module status sum

View File

@@ -85,6 +85,12 @@ VAR_OUTPUT
// Inverter status data
stInverterData : ST_SUNSPEC_CURRENT_VALUES;
// Smallest segment voltage
rSmallestSegmentVoltage : REAL;
// Highest segment voltage
rHighestSegmentVoltage : REAL;
// Balancing done
xBalancingDone : BOOL;
END_VAR
@@ -158,9 +164,6 @@ VAR
_xReleaseLimitErrorsInternal : BOOL;
// Smallest segment voltage
_rSmallestSegmentVoltage : REAL;
// Balancing done
_xBalancingDone : BOOL;
@@ -239,7 +242,7 @@ _fbModule1(
xReleaseLimitErrors:= xReleaseLimitErrors AND _xReleaseLimitErrorsInternal,
xReleaseManualMode := xReleaseManualMode,
xConfirmAlarms:= xConfirmAlarms,
rBalancingTargetVoltage := _rSmallestSegmentVoltage);
rBalancingTargetVoltage := rSmallestSegmentVoltage);
IF _fbModule1.xWarning THEN
xWarning := TRUE;
@@ -270,7 +273,7 @@ _fbModule2(
xReleaseLimitErrors:= xReleaseLimitErrors AND _xReleaseLimitErrorsInternal,
xReleaseManualMode := xReleaseManualMode,
xConfirmAlarms:= xConfirmAlarms,
rBalancingTargetVoltage := _rSmallestSegmentVoltage);
rBalancingTargetVoltage := rSmallestSegmentVoltage);
IF _fbModule2.xWarning THEN
xWarning := TRUE;
@@ -300,7 +303,7 @@ _fbModule3(
xReleaseLimitErrors:= xReleaseLimitErrors AND _xReleaseLimitErrorsInternal,
xReleaseManualMode := xReleaseManualMode,
xConfirmAlarms:= xConfirmAlarms,
rBalancingTargetVoltage := _rSmallestSegmentVoltage);
rBalancingTargetVoltage := rSmallestSegmentVoltage);
IF _fbModule3.xWarning THEN
xWarning := TRUE;
@@ -428,7 +431,8 @@ _tonSafetyOkTimeout();
// Get smalles segment voltage
// of all units
// ===============================
_rSmallestSegmentVoltage := MIN(_fbModule1.rSmallestSegmentVoltage, _fbModule2.rSmallestSegmentVoltage, _fbModule3.rSmallestSegmentVoltage);
rSmallestSegmentVoltage := MIN(_fbModule1.rSmallestSegmentVoltage, _fbModule2.rSmallestSegmentVoltage, _fbModule3.rSmallestSegmentVoltage);
rHighestSegmentVoltage := MAX(_fbModule1.rSmallestSegmentVoltage, _fbModule2.rSmallestSegmentVoltage, _fbModule3.rSmallestSegmentVoltage);
// Call inverter
@@ -635,6 +639,13 @@ CASE _iState OF
_iState := 40;
END_IF
// Restart on Enable or StartBalancing
IF xEnable OR xStartBalancing THEN
_rPowerInverterInternal := 0.0;
_xEnableInverter := FALSE;
_iState := 40;
END_IF
40: // Wait for inverter to shut down
IF NOT _fbInverter.xActive THEN
_iState := 41;
@@ -768,68 +779,7 @@ _fbSafetyInterlocksNotOkAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
</Set>
</Property>
<LineIds Name="FB_String">
<LineId Id="3089" Count="50" />
<LineId Id="3540" Count="0" />
<LineId Id="3784" Count="0" />
<LineId Id="3140" Count="28" />
<LineId Id="3541" Count="0" />
<LineId Id="3785" Count="0" />
<LineId Id="3169" Count="7" />
<LineId Id="3532" Count="0" />
<LineId Id="3177" Count="18" />
<LineId Id="3542" Count="0" />
<LineId Id="3786" Count="0" />
<LineId Id="3196" Count="7" />
<LineId Id="3533" Count="0" />
<LineId Id="3204" Count="35" />
<LineId Id="3552" Count="0" />
<LineId Id="3545" Count="2" />
<LineId Id="3544" Count="0" />
<LineId Id="3548" Count="0" />
<LineId Id="3240" Count="104" />
<LineId Id="3536" Count="0" />
<LineId Id="3584" Count="0" />
<LineId Id="3348" Count="1" />
<LineId Id="3534" Count="1" />
<LineId Id="3537" Count="0" />
<LineId Id="3562" Count="0" />
<LineId Id="3538" Count="0" />
<LineId Id="3543" Count="0" />
<LineId Id="3539" Count="0" />
<LineId Id="3573" Count="2" />
<LineId Id="3606" Count="0" />
<LineId Id="3787" Count="0" />
<LineId Id="3607" Count="0" />
<LineId Id="3788" Count="0" />
<LineId Id="3605" Count="0" />
<LineId Id="3576" Count="3" />
<LineId Id="3585" Count="0" />
<LineId Id="3580" Count="1" />
<LineId Id="3586" Count="1" />
<LineId Id="3590" Count="0" />
<LineId Id="3588" Count="1" />
<LineId Id="3582" Count="1" />
<LineId Id="3593" Count="11" />
<LineId Id="3592" Count="0" />
<LineId Id="3591" Count="0" />
<LineId Id="3350" Count="18" />
<LineId Id="3791" Count="0" />
<LineId Id="3369" Count="23" />
<LineId Id="3792" Count="0" />
<LineId Id="3794" Count="3" />
<LineId Id="3793" Count="0" />
<LineId Id="3393" Count="11" />
<LineId Id="3798" Count="0" />
<LineId Id="3405" Count="33" />
<LineId Id="3608" Count="0" />
<LineId Id="3439" Count="12" />
<LineId Id="3790" Count="0" />
<LineId Id="3452" Count="42" />
<LineId Id="3553" Count="0" />
<LineId Id="3569" Count="0" />
<LineId Id="3554" Count="1" />
<LineId Id="3564" Count="4" />
<LineId Id="3495" Count="36" />
<LineId Id="4873" Count="525" />
<LineId Id="527" Count="0" />
</LineIds>
<LineIds Name="FB_String.FB_init">

View File

@@ -95,6 +95,12 @@ VAR
_fbBatteryFullMessage : FB_TcMessage;
_fbBatteryEmptyMessage : FB_TcMessage;
// Smallest segment voltage
_rSmallestSegmentVoltage : REAL;
// Highest segment voltage
_rHighestSegmentVoltage : REAL;
// Safety
_fbSafety : FB_Safety;
@@ -104,6 +110,12 @@ VAR
_xDebug : BOOL;
_uiDebugCurrentString : UINT := 1;
_ModbusDebugTest : ST_MODBUS_REG_11;
_fbModbusRead : FB_MBReadRegs;
_iLength : WORD := 49;
bDebugTest : BOOL;
END_VAR
]]></Declaration>
<Implementation>
@@ -273,6 +285,40 @@ _fbADSReader(
ERR=> ,
ERRID=> );
_fbModbusRead(
sIPAddr:= '127.0.0.1',
nTCPPort:= 502,
nUnitID:= 16#FF,
nQuantity:= 48,
nMBAddr:= 11000,
cbLength:= SIZEOF(_ModbusDebugTest),
pDestAddr:= ADR(_ModbusDebugTest),
bExecute:= bDebugTest,
tTimeout:= T#5S,
bBusy=> ,
bError=> ,
nErrId=> ,
cbRead=> );
// ===============================
// 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);
// 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
@@ -435,7 +481,7 @@ 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) THEN
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);
// Send message
@@ -457,7 +503,7 @@ END_IF]]></ST>
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) THEN
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);
// Send Message
@@ -741,7 +787,26 @@ END_CASE]]></ST>
<LineId Id="2490" Count="10" />
<LineId Id="2484" Count="0" />
<LineId Id="2113" Count="19" />
<LineId Id="2144" Count="23" />
<LineId Id="2144" Count="15" />
<LineId Id="3088" Count="0" />
<LineId Id="3094" Count="12" />
<LineId Id="3089" Count="0" />
<LineId Id="3124" Count="0" />
<LineId Id="3123" Count="0" />
<LineId Id="3125" Count="2" />
<LineId Id="2160" Count="0" />
<LineId Id="3081" Count="1" />
<LineId Id="3085" Count="0" />
<LineId Id="3084" Count="0" />
<LineId Id="3083" Count="0" />
<LineId Id="3086" Count="0" />
<LineId Id="3115" Count="2" />
<LineId Id="3119" Count="0" />
<LineId Id="3121" Count="0" />
<LineId Id="3120" Count="0" />
<LineId Id="3118" Count="0" />
<LineId Id="3122" Count="0" />
<LineId Id="2161" Count="6" />
<LineId Id="2601" Count="0" />
<LineId Id="2168" Count="0" />
<LineId Id="2944" Count="1" />

View File

@@ -8,17 +8,17 @@ VAR_INPUT
rPower : REAL;
rReactivePower : REAL := 0.0;
xReset : BOOL;
rMaxBattPower : REAL := 24_000; // 24kW
rMaxBattPower : REAL := 40_000; // 24kW
END_VAR
VAR_OUTPUT
// Output for SCS DC-Relais
//xCloseDCRelais AT %Q*: BOOL;
VAR_OUTPUT
// Inverter active
xActive : BOOL;
// FB error
xError : BOOL;
// Heartbeat ok signal
xHeartbeatOk : BOOL := TRUE;
// Current inverter values
stCurrentValues : ST_SUNSPEC_CURRENT_VALUES;
@@ -103,9 +103,22 @@ VAR
// Inverter reset errors command
_uiResetInverter : UINT := 1;
// PLC -> Inverter heartbeat
_uiPLCToInverterCounter : UINT;
// Inverter -> PLC heartbeat
_uiInverterToPLCCounter : UINT;
_uiInverterToPLCCounterOld : UINT;
// Flag to check if inverter has incremented the heartbeat counter
_xInverterHBCounterIncremented : BOOL := TRUE;
// Inverter alarm
_fbErrorInverterAlarm : Fb_TcAlarm;
// Heartbeat timeout
_tonHeartbeatTimeout : TON;
_sName : STRING;
END_VAR
@@ -181,6 +194,12 @@ VAR CONSTANT
// Error bits register
// Size 2
EVT_1_REGISTER : WORD := 40110;
// PLC -> Inverter Heartbeat register
CONTROLLER_HB : WORD := 40229;
// Inverter -> PLC heartbeat register
PCS_HB : WORD := 40228;
END_VAR
]]></Declaration>
<Implementation>
@@ -200,7 +219,6 @@ CASE _iState OF
// If enable and INTLK Ok
IF xEnable THEN
_iState := 10;
//xCloseDCRelais := TRUE;
_tonPollingTimer(IN := FALSE, PT := _timPollingDelay);
ELSE
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
@@ -211,6 +229,7 @@ CASE _iState OF
_iState := 1;
END_IF
1: // Read inverter status
_fbReadRegister(
sIPAddr:= sInverterIPAddr,
@@ -237,6 +256,7 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
2: // IF inverter is not in STANDYB(8) STATE, send command to shutdown inverter
IF (_uiInverterState = 8) OR (_uiInverterState = 1) THEN
_iState := 3;
@@ -245,6 +265,7 @@ CASE _iState OF
_iState := 200;
END_IF
3: // Read current DC values
_iErrorInState := _iState;
_fbReadRegister(
@@ -277,6 +298,7 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
4: // Read current ac values
_iErrorInState := _iState;
_fbReadRegister(
@@ -299,7 +321,7 @@ CASE _iState OF
// If there was no error and the converter has no error continue
IF NOT _fbReadRegister.bError THEN
// Go back to polling state
_iState := 0;
_iState := 5;
stCurrentValues.rActACPower := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[0]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[1])));
stCurrentValues.rActACFreq := LREAL_TO_REAL(WORD_TO_UINT(_awCurrentACValues[2]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[3])));
stCurrentValues.rActApparentPower := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[4]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[5])));
@@ -313,6 +335,75 @@ CASE _iState OF
END_IF
5: // Send heartbeat signal
_uiPLCToInverterCounter := _uiPLCToInverterCounter + 1;
_iErrorInState := _iState;
_fbWriteRegister(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nQuantity:= 1,
nMBAddr:= CONTROLLER_HB,
cbLength:= SIZEOF(_uiPLCToInverterCounter),
pSrcAddr:= ADR(_uiPLCToInverterCounter),
bExecute:= TRUE,
tTimeout:= T#5S,
bBusy=> ,
bError=> ,
nErrId=> );
// If writing modbus register is done
IF NOT _fbWriteRegister.bBusy THEN
// And there is no error, then continue
IF NOT _fbWriteRegister.bError THEN
_iState := 6;
ELSE
xError := TRUE;
// Goto error state
_iState := 1000;
END_IF
_fbWriteRegister(bExecute := FALSE);
END_IF
6: // Check heartbeat signal
_fbReadRegister(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nQuantity:= 1,
nMBAddr:= PCS_HB,
cbLength:= SIZEOF(_uiInverterToPLCCounter),
pDestAddr:= ADR(_uiInverterToPLCCounter),
bExecute:= TRUE,
tTimeout:= T#5S,
bBusy=> ,
bError=> ,
nErrId=> ,
cbRead=> );
IF NOT _fbReadRegister.bBusy THEN
IF (NOT _fbReadRegister.bError) THEN
// Check if counter has been incremented by the inverter
IF (_uiInverterToPLCCounter - _uiInverterToPLCCounterOld) > 0 THEN
_xInverterHBCounterIncremented := TRUE;
// Safe old value
_uiInverterToPLCCounterOld := _uiInverterToPLCCounter;
ELSE
_xInverterHBCounterIncremented := FALSE;
END_IF
_iState := 0;
ELSE
xError := TRUE;
// Goto error state
_iState := 1000;
END_IF
_fbReadRegister(bExecute := FALSE);
END_IF
10: // Wait for inverter to be online and in state STANDBY(8)
_fbReadRegister(
@@ -351,6 +442,7 @@ CASE _iState OF
_iState := 0;
END_IF
15: // Delay polling inverter ready
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
IF _tonPollingTimer.Q THEN
@@ -400,6 +492,7 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
25: // Read inverter Max power limit scaling
_iErrorInState := _iState;
_fbReadRegister(
@@ -435,6 +528,7 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
26: // Read inverter scaling factor for reactive power
_iErrorInState := _iState;
_fbReadRegister(
@@ -506,6 +600,7 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
40: // Set power limit
_iErrorInState := _iState;
_fbWriteRegister(
@@ -569,6 +664,7 @@ CASE _iState OF
_fbWriteRegister(bExecute := FALSE);
END_IF
42: // Enable reactive power percent limiting
_iErrorInState := _iState;
_fbWriteRegister(
@@ -599,32 +695,6 @@ CASE _iState OF
END_IF
// 45: // Read set power
// _fbReadRegister(
// sIPAddr:= sInverterIPAddr,
// nTCPPort:= 502,
// nUnitID:= 16#FF, // 16#FF for Modbus TCP
// nQuantity:= 1,
// nMBAddr:= W_MAX_LIM_PCT_REGISTER,
// cbLength:= SIZEOF(_iWMaxLimPctRead),
// pDestAddr:= ADR(_iWMaxLimPctRead),
// bExecute:= TRUE,
// tTimeout:= T#5S,
// bBusy=> ,
// bError=> ,
// nErrId=> ,
// cbRead=> );
// // Check if reading mudbus register is done
// IF NOT _fbReadRegister.bBusy THEN
// IF NOT _fbReadRegister.bError THEN
// _iWMaxLimPctReadScaled := LREAL_TO_INT(_rWMax * _iWMaxLimPctRead * EXPT(10,_iWMaxLimPctSF)*0.01);
// _iState := 50;
// END_IF
// _fbReadRegister(bExecute := FALSE);
// END_IF
50: // Enable Power limiting (THROTTLED)
_iErrorInState := _iState;
_fbWriteRegister(
@@ -655,6 +725,7 @@ CASE _iState OF
_fbWriteRegister(bExecute := FALSE);
END_IF
51: // Go to started
_iErrorInState := _iState;
_fbWriteRegister(
@@ -713,6 +784,7 @@ CASE _iState OF
_fbWriteRegister(bExecute := FALSE);
END_IF
65: // Wait for polling timer
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
IF _tonPollingTimer.Q THEN
@@ -733,6 +805,7 @@ CASE _iState OF
_iState := 200;
END_IF
70: // Enabled, check for error
_iErrorInState := _iState;
_fbReadRegister(
@@ -769,6 +842,7 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
80: // Read current DC values
_iErrorInState := _iState;
_fbReadRegister(
@@ -801,6 +875,7 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
85: // Read current ac values
_iErrorInState := _iState;
_fbReadRegister(
@@ -836,6 +911,7 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
90: // Read current inverter status
_fbReadRegister(
sIPAddr:= sInverterIPAddr,
@@ -855,7 +931,7 @@ CASE _iState OF
// Check if reading mudbus register is done
IF NOT _fbReadRegister.bBusy THEN
IF NOT _fbReadRegister.bError THEN
_iState := 65;
_iState := 91;
stCurrentValues.uiStatus := _uiInverterState;
ELSE
// Read error register
@@ -864,6 +940,77 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
91: // Send heartbeat signal
_uiPLCToInverterCounter := _uiPLCToInverterCounter + 1;
_iErrorInState := _iState;
_fbWriteRegister(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nQuantity:= 1,
nMBAddr:= CONTROLLER_HB,
cbLength:= SIZEOF(_uiPLCToInverterCounter),
pSrcAddr:= ADR(_uiPLCToInverterCounter),
bExecute:= TRUE,
tTimeout:= T#5S,
bBusy=> ,
bError=> ,
nErrId=> );
// If writing modbus register is done
IF NOT _fbWriteRegister.bBusy THEN
// And there is no error, then continue
IF NOT _fbWriteRegister.bError THEN
_iState := 92;
ELSE
xError := TRUE;
// Goto error state
_iState := 1000;
END_IF
_fbWriteRegister(bExecute := FALSE);
END_IF
92: // Check heartbeat signal
_fbReadRegister(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nQuantity:= 1,
nMBAddr:= PCS_HB,
cbLength:= SIZEOF(_uiInverterToPLCCounter),
pDestAddr:= ADR(_uiInverterToPLCCounter),
bExecute:= TRUE,
tTimeout:= T#5S,
bBusy=> ,
bError=> ,
nErrId=> ,
cbRead=> );
IF NOT _fbReadRegister.bBusy THEN
IF (NOT _fbReadRegister.bError) THEN
// Check if counter has been incremented by the inverter
IF (_uiInverterToPLCCounter - _uiInverterToPLCCounterOld) > 0 THEN
_xInverterHBCounterIncremented := TRUE;
// Safe old value
_uiInverterToPLCCounterOld := _uiInverterToPLCCounter;
ELSE
_xInverterHBCounterIncremented := FALSE;
END_IF
_iState := 65;
ELSE
xError := TRUE;
// Goto error state
_iState := 1000;
END_IF
_fbReadRegister(bExecute := FALSE);
END_IF
200: // Shutdown sequence
_iErrorInState := _iState;
_fbWriteRegister(
@@ -892,6 +1039,7 @@ CASE _iState OF
_fbWriteRegister(bExecute := FALSE);
END_IF
210: // Wait for poll timer to
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
IF _tonPollingTimer.Q THEN
@@ -899,6 +1047,7 @@ CASE _iState OF
_iState := 220;
END_IF
220: // Poll and wait for standby state
_iErrorInState := _iState;
_fbReadRegister(
@@ -927,6 +1076,7 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
990: // Read error register
_iErrorInState := _iState;
_fbReadRegister(
@@ -953,11 +1103,13 @@ CASE _iState OF
_fbReadRegister(bExecute := FALSE);
END_IF
1000: // Error state, wait for reset
IF xReset AND (NOT xEnable) THEN
_iState := 1010;
END_IF
1010: // Try to clear all latched events
_fbWriteRegister(
sIPAddr:= sInverterIPAddr,
@@ -980,6 +1132,27 @@ CASE _iState OF
END_IF
END_CASE
// ===============================
// Heartbeat check
// ===============================
_tonHeartbeatTimeout(IN := (NOT _xInverterHBCounterIncremented), PT := T#5S);
// Reset heartbeat ok signal
IF xReset AND (NOT _tonHeartbeatTimeout.Q) THEN
xHeartbeatOk := TRUE;
END_IF
// Check for heartbeat
IF _tonHeartbeatTimeout.Q THEN
xHeartbeatOk := FALSE;
END_IF
// ===============================
// Inverter alarm handling
// ===============================
IF xError AND (NOT _fbErrorInverterAlarm.bRaised) THEN
_fbErrorInverterAlarm.Raise(0);
END_IF
@@ -1012,14 +1185,16 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
<LineIds Name="FB_PowerSupplySunspec">
<LineId Id="774" Count="10" />
<LineId Id="1550" Count="0" />
<LineId Id="785" Count="4" />
<LineId Id="785" Count="3" />
<LineId Id="2615" Count="0" />
<LineId Id="790" Count="0" />
<LineId Id="2614" Count="0" />
<LineId Id="2613" Count="0" />
<LineId Id="2616" Count="1" />
<LineId Id="2906" Count="0" />
<LineId Id="2618" Count="3" />
<LineId Id="2618" Count="2" />
<LineId Id="3661" Count="0" />
<LineId Id="2621" Count="0" />
<LineId Id="2623" Count="15" />
<LineId Id="2622" Count="0" />
<LineId Id="2639" Count="0" />
@@ -1029,15 +1204,33 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
<LineId Id="2642" Count="0" />
<LineId Id="2721" Count="0" />
<LineId Id="2640" Count="0" />
<LineId Id="2645" Count="1" />
<LineId Id="2645" Count="0" />
<LineId Id="3660" Count="0" />
<LineId Id="2646" Count="0" />
<LineId Id="2648" Count="1" />
<LineId Id="2651" Count="0" />
<LineId Id="2722" Count="0" />
<LineId Id="2652" Count="0" />
<LineId Id="2650" Count="0" />
<LineId Id="2653" Count="0" />
<LineId Id="2656" Count="64" />
<LineId Id="2654" Count="1" />
<LineId Id="3659" Count="0" />
<LineId Id="2656" Count="31" />
<LineId Id="3658" Count="0" />
<LineId Id="2688" Count="32" />
<LineId Id="2654" Count="0" />
<LineId Id="3422" Count="2" />
<LineId Id="3438" Count="0" />
<LineId Id="3440" Count="19" />
<LineId Id="3464" Count="5" />
<LineId Id="3439" Count="0" />
<LineId Id="3425" Count="0" />
<LineId Id="3474" Count="0" />
<LineId Id="3426" Count="0" />
<LineId Id="3475" Count="12" />
<LineId Id="2655" Count="0" />
<LineId Id="3488" Count="0" />
<LineId Id="3607" Count="19" />
<LineId Id="3489" Count="0" />
<LineId Id="2647" Count="0" />
<LineId Id="791" Count="22" />
<LineId Id="1701" Count="5" />
@@ -1047,7 +1240,9 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
<LineId Id="1715" Count="0" />
<LineId Id="1718" Count="0" />
<LineId Id="1716" Count="1" />
<LineId Id="1707" Count="1" />
<LineId Id="1707" Count="0" />
<LineId Id="3657" Count="0" />
<LineId Id="1708" Count="0" />
<LineId Id="1710" Count="2" />
<LineId Id="1709" Count="0" />
<LineId Id="1713" Count="0" />
@@ -1059,10 +1254,14 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
<LineId Id="1433" Count="0" />
<LineId Id="816" Count="28" />
<LineId Id="1171" Count="0" />
<LineId Id="845" Count="33" />
<LineId Id="845" Count="5" />
<LineId Id="3656" Count="0" />
<LineId Id="851" Count="27" />
<LineId Id="1172" Count="0" />
<LineId Id="879" Count="4" />
<LineId Id="1981" Count="1" />
<LineId Id="1981" Count="0" />
<LineId Id="3655" Count="0" />
<LineId Id="1982" Count="0" />
<LineId Id="1991" Count="0" />
<LineId Id="1993" Count="12" />
<LineId Id="1992" Count="0" />
@@ -1072,7 +1271,9 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
<LineId Id="1983" Count="0" />
<LineId Id="884" Count="28" />
<LineId Id="1173" Count="0" />
<LineId Id="913" Count="28" />
<LineId Id="913" Count="5" />
<LineId Id="3654" Count="0" />
<LineId Id="919" Count="22" />
<LineId Id="2024" Count="1" />
<LineId Id="942" Count="0" />
<LineId Id="1174" Count="0" />
@@ -1081,45 +1282,50 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
<LineId Id="1934" Count="18" />
<LineId Id="1955" Count="5" />
<LineId Id="1933" Count="0" />
<LineId Id="2030" Count="1" />
<LineId Id="2030" Count="0" />
<LineId Id="3653" Count="0" />
<LineId Id="2031" Count="0" />
<LineId Id="2033" Count="25" />
<LineId Id="2032" Count="0" />
<LineId Id="1932" Count="0" />
<LineId Id="1520" Count="0" />
<LineId Id="1522" Count="17" />
<LineId Id="1541" Count="0" />
<LineId Id="1548" Count="0" />
<LineId Id="1542" Count="2" />
<LineId Id="1521" Count="0" />
<LineId Id="1493" Count="0" />
<LineId Id="3639" Count="0" />
<LineId Id="948" Count="23" />
<LineId Id="1175" Count="0" />
<LineId Id="972" Count="4" />
<LineId Id="2907" Count="1" />
<LineId Id="2907" Count="0" />
<LineId Id="3640" Count="0" />
<LineId Id="2908" Count="0" />
<LineId Id="2969" Count="18" />
<LineId Id="3031" Count="0" />
<LineId Id="2988" Count="5" />
<LineId Id="2909" Count="0" />
<LineId Id="2996" Count="0" />
<LineId Id="977" Count="37" />
<LineId Id="977" Count="28" />
<LineId Id="3641" Count="0" />
<LineId Id="1006" Count="8" />
<LineId Id="1560" Count="1" />
<LineId Id="1015" Count="3" />
<LineId Id="1127" Count="0" />
<LineId Id="1019" Count="25" />
<LineId Id="1019" Count="3" />
<LineId Id="3642" Count="0" />
<LineId Id="1023" Count="21" />
<LineId Id="1097" Count="1" />
<LineId Id="1100" Count="1" />
<LineId Id="1099" Count="0" />
<LineId Id="1045" Count="0" />
<LineId Id="1176" Count="0" />
<LineId Id="2723" Count="0" />
<LineId Id="1046" Count="6" />
<LineId Id="1046" Count="5" />
<LineId Id="3643" Count="0" />
<LineId Id="1052" Count="0" />
<LineId Id="1063" Count="20" />
<LineId Id="1090" Count="0" />
<LineId Id="1092" Count="0" />
<LineId Id="1775" Count="0" />
<LineId Id="1084" Count="4" />
<LineId Id="1062" Count="0" />
<LineId Id="1736" Count="1" />
<LineId Id="1736" Count="0" />
<LineId Id="3644" Count="0" />
<LineId Id="1737" Count="0" />
<LineId Id="1739" Count="19" />
<LineId Id="1781" Count="0" />
<LineId Id="1759" Count="2" />
@@ -1127,7 +1333,9 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
<LineId Id="1776" Count="1" />
<LineId Id="1762" Count="4" />
<LineId Id="1738" Count="0" />
<LineId Id="3213" Count="1" />
<LineId Id="3213" Count="0" />
<LineId Id="3645" Count="0" />
<LineId Id="3214" Count="0" />
<LineId Id="3216" Count="15" />
<LineId Id="3215" Count="0" />
<LineId Id="3232" Count="0" />
@@ -1137,24 +1345,46 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
<LineId Id="3235" Count="0" />
<LineId Id="3239" Count="0" />
<LineId Id="3233" Count="0" />
<LineId Id="1093" Count="1" />
<LineId Id="3529" Count="0" />
<LineId Id="3646" Count="0" />
<LineId Id="3531" Count="47" />
<LineId Id="3590" Count="0" />
<LineId Id="3593" Count="9" />
<LineId Id="3591" Count="0" />
<LineId Id="3603" Count="0" />
<LineId Id="3605" Count="1" />
<LineId Id="3604" Count="0" />
<LineId Id="3592" Count="0" />
<LineId Id="3588" Count="1" />
<LineId Id="3530" Count="0" />
<LineId Id="1093" Count="0" />
<LineId Id="3647" Count="0" />
<LineId Id="1094" Count="0" />
<LineId Id="1102" Count="24" />
<LineId Id="1054" Count="0" />
<LineId Id="1295" Count="4" />
<LineId Id="1295" Count="0" />
<LineId Id="3648" Count="0" />
<LineId Id="1296" Count="3" />
<LineId Id="1128" Count="0" />
<LineId Id="1300" Count="1" />
<LineId Id="3649" Count="0" />
<LineId Id="1129" Count="0" />
<LineId Id="1132" Count="20" />
<LineId Id="1163" Count="0" />
<LineId Id="1294" Count="0" />
<LineId Id="1161" Count="1" />
<LineId Id="1130" Count="1" />
<LineId Id="3650" Count="0" />
<LineId Id="1055" Count="0" />
<LineId Id="1177" Count="20" />
<LineId Id="1199" Count="1" />
<LineId Id="1169" Count="0" />
<LineId Id="1265" Count="2" />
<LineId Id="1269" Count="3" />
<LineId Id="1265" Count="0" />
<LineId Id="3651" Count="0" />
<LineId Id="1266" Count="1" />
<LineId Id="1269" Count="2" />
<LineId Id="3652" Count="0" />
<LineId Id="1272" Count="0" />
<LineId Id="1274" Count="11" />
<LineId Id="1273" Count="0" />
<LineId Id="1289" Count="1" />
@@ -1162,6 +1392,18 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
<LineId Id="2235" Count="0" />
<LineId Id="1291" Count="1" />
<LineId Id="12" Count="0" />
<LineId Id="3629" Count="1" />
<LineId Id="3628" Count="0" />
<LineId Id="3631" Count="1" />
<LineId Id="3524" Count="0" />
<LineId Id="3633" Count="0" />
<LineId Id="3525" Count="3" />
<LineId Id="3516" Count="0" />
<LineId Id="3627" Count="0" />
<LineId Id="3521" Count="2" />
<LineId Id="3635" Count="1" />
<LineId Id="3634" Count="0" />
<LineId Id="3637" Count="1" />
<LineId Id="2418" Count="0" />
<LineId Id="2417" Count="0" />
<LineId Id="2419" Count="1" />