Changed Kaco communication statemachine
- Added small delay after each modbus/tcp read - Only write requested state when requested state has changed
This commit is contained in:
18
PLC/POUs/Sunspec/Kaco/E_KACO_PCU_REQUESTED_STATE.TcDUT
Normal file
18
PLC/POUs/Sunspec/Kaco/E_KACO_PCU_REQUESTED_STATE.TcDUT
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TcPlcObject Version="1.1.0.1" ProductVersion="3.1.4026.12">
|
||||
<DUT Name="E_KACO_PCU_REQUESTED_STATE" Id="{d26b8bd2-4451-4a56-a3ba-471d8a90e01d}">
|
||||
<Declaration><![CDATA[{attribute 'qualified_only'}
|
||||
{attribute 'strict'}
|
||||
{attribute 'to_string'}
|
||||
TYPE E_KACO_PCU_REQUESTED_STATE :
|
||||
(
|
||||
UNDEFINED := 0,
|
||||
OFF := 1,
|
||||
STANDBY := 8,
|
||||
GRID_PRE_CONNECTED := 10,
|
||||
GRID_CONNECTED := 11
|
||||
);
|
||||
END_TYPE
|
||||
]]></Declaration>
|
||||
</DUT>
|
||||
</TcPlcObject>
|
||||
@@ -49,7 +49,8 @@ VAR
|
||||
_rPowerInternal : REAL := 0;
|
||||
|
||||
// Enum for requested state
|
||||
_eRequestedState : (OFF := 1, STANDBY := 8, GRID_PRE_CONNECTED := 10, GRID_CONNECTED := 11) := OFF;
|
||||
_eRequestedState : E_KACO_PCU_REQUESTED_STATE := E_KACO_PCU_REQUESTED_STATE.OFF;
|
||||
_eLastRequestedState : E_KACO_PCU_REQUESTED_STATE := E_KACO_PCU_REQUESTED_STATE.UNDEFINED;
|
||||
|
||||
// Watchdog timeout in seconds
|
||||
_uiWatchdogTimeoutSeconds : UINT := 10;
|
||||
@@ -85,20 +86,13 @@ VAR
|
||||
_fbReadACValues : FB_MBReadRegs;
|
||||
|
||||
// Time for polling for current dc values and check for inverter error
|
||||
_timPollingDelay : TIME := T#500MS;
|
||||
|
||||
// Time for setting the current power
|
||||
_timSetPowerDelay : TIME := T#250MS;
|
||||
_timPollingDelay : TIME := T#200MS;
|
||||
|
||||
// Timer for polling of current values
|
||||
_tonPollingTimer : TON;
|
||||
_tTimeoutPolling : TIME := T#5S;
|
||||
|
||||
// Timer for setting the inverter power
|
||||
_tonSetPowerTimer : TON;
|
||||
|
||||
// Timer for watchdog
|
||||
_tonWatchdogResetTimer : TON := (PT := T#1S);
|
||||
// watchdog write timeout
|
||||
_tTimeoutWriteWatchdogRegister : TIME := T#5S;
|
||||
|
||||
// Inverter alarm
|
||||
@@ -199,10 +193,12 @@ VAR CONSTANT
|
||||
// 41120 is Voltage and 41121 is amp
|
||||
BATTERY_LIMIT_SF_START : WORD := 41120;
|
||||
BATTERY_SET_LIMITS_START : WORD := 41122;
|
||||
(*
|
||||
DIS_MIN_V : WORD := 41122;
|
||||
DIS_MAX_A : WORD := 41123;
|
||||
CHA_MAX_V : WORD := 41125;
|
||||
CHA_MAX_A : WORD := 41126;
|
||||
*)
|
||||
EN_LIMIT : WORD := 41129;
|
||||
|
||||
// Power registers (Model 64201)
|
||||
@@ -248,7 +244,6 @@ IF (rPower < -rMaxBattPower) THEN
|
||||
_rPowerInternal := -rMaxBattPower;
|
||||
END_IF
|
||||
|
||||
HandleHeartbeat();
|
||||
HandleCyclicData();
|
||||
|
||||
CASE _iState OF
|
||||
@@ -256,7 +251,7 @@ CASE _iState OF
|
||||
_fbTONSetBatteryLimits(IN := TRUE);
|
||||
IF _fbTONSetBatteryLimits.Q THEN
|
||||
_fbTONSetBatteryLimits(IN := FALSE);
|
||||
_eRequestedState := OFF;
|
||||
_eRequestedState := E_KACO_PCU_REQUESTED_STATE.OFF;
|
||||
_iStateStartup := 0;
|
||||
_iState := 10;
|
||||
END_IF
|
||||
@@ -348,7 +343,7 @@ CASE _iState OF
|
||||
40: // Idle state, wait for enable
|
||||
// If enable and INTLK Ok
|
||||
IF xEnable THEN
|
||||
_eRequestedState := GRID_CONNECTED;
|
||||
_eRequestedState := E_KACO_PCU_REQUESTED_STATE.GRID_CONNECTED;
|
||||
IF xReleasePower THEN
|
||||
// Calculate power to write to register
|
||||
// (could not find where the scaling for wset can be read but its -2!)
|
||||
@@ -360,14 +355,14 @@ CASE _iState OF
|
||||
_iWSetPct := 0;
|
||||
END_IF
|
||||
ELSE
|
||||
_eRequestedState := OFF;
|
||||
_eRequestedState := E_KACO_PCU_REQUESTED_STATE.OFF;
|
||||
_iWSetPct := 0;
|
||||
END_IF
|
||||
|
||||
// Comm error or Watchdog error occured
|
||||
IF _xErrorCyclicData OR (NOT xHeartbeatOk) THEN
|
||||
_iWSetPct := 0;
|
||||
_eRequestedState := OFF;
|
||||
_eRequestedState := E_KACO_PCU_REQUESTED_STATE.OFF;
|
||||
_iState := 1000;
|
||||
END_IF
|
||||
|
||||
@@ -384,7 +379,7 @@ CASE _iState OF
|
||||
|
||||
1001: // Error state, wait for reset
|
||||
IF xReset AND (NOT xEnable) AND (NOT _xErrorInverter) AND (NOT _xErrorCyclicData) AND xHeartbeatOk THEN
|
||||
_eRequestedState := OFF;
|
||||
_eRequestedState := E_KACO_PCU_REQUESTED_STATE.OFF;
|
||||
xError := FALSE;
|
||||
_xFaultInverter := FALSE;
|
||||
_xErrorCyclicDataLedge := FALSE;
|
||||
@@ -463,14 +458,16 @@ _fbCyclicDataAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
|
||||
_iErrorIDRACV := 0;
|
||||
END_IF
|
||||
|
||||
// Fetch cyclic data with polling timer
|
||||
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
|
||||
|
||||
CASE _iStateCyclicData OF
|
||||
0: // init state
|
||||
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
|
||||
IF _tonPollingTimer.Q THEN
|
||||
_tonPollingTimer(IN := FALSE);
|
||||
_iStateCyclicData := 10;
|
||||
IF _eRequestedState <> _eLastRequestedState THEN
|
||||
_iStateCyclicData := 10;
|
||||
ELSE
|
||||
_iStateCyclicData := 20;
|
||||
END_IF
|
||||
END_IF
|
||||
|
||||
10: // Write requested state
|
||||
@@ -488,15 +485,23 @@ CASE _iStateCyclicData OF
|
||||
|
||||
IF (NOT _fbWriteRequestedState.bBusy) THEN
|
||||
_fbWriteRequestedState(bExecute := FALSE);
|
||||
_iStateCyclicData := 20;
|
||||
_iStateCyclicData := 11;
|
||||
IF _fbWriteRequestedState.bError THEN
|
||||
_iCurrentErrorCountWRS := _iCurrentErrorCountWRS + 1;
|
||||
_iErrorCountWRS := _iErrorCountWRS + 1;
|
||||
_iErrorIDWRS := _fbWriteRequestedState.nErrId;
|
||||
ELSE
|
||||
_iCurrentErrorCountWRS := 0;
|
||||
_eLastRequestedState := _eRequestedState;
|
||||
END_IF
|
||||
END_IF
|
||||
|
||||
11: // wait for next state
|
||||
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
|
||||
IF _tonPollingTimer.Q THEN
|
||||
_tonPollingTimer(IN := FALSE);
|
||||
_iStateCyclicData := 20;
|
||||
END_IF
|
||||
|
||||
20: // Write current power command
|
||||
_fbWritePowerCommand(
|
||||
@@ -515,7 +520,7 @@ CASE _iStateCyclicData OF
|
||||
|
||||
IF (NOT _fbWritePowerCommand.bBusy) THEN
|
||||
_fbWritePowerCommand(bExecute := FALSE);
|
||||
_iStateCyclicData := 30;
|
||||
_iStateCyclicData := 21;
|
||||
IF _fbWritePowerCommand.bError THEN
|
||||
_iCurrentErrorCountWPC := _iCurrentErrorCountWPC + 1;
|
||||
_iErrorCountWPC := _iErrorCountWPC + 1;
|
||||
@@ -525,6 +530,13 @@ CASE _iStateCyclicData OF
|
||||
END_IF
|
||||
END_IF
|
||||
|
||||
21: // wait for next state
|
||||
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
|
||||
IF _tonPollingTimer.Q THEN
|
||||
_tonPollingTimer(IN := FALSE);
|
||||
_iStateCyclicData := 30;
|
||||
END_IF
|
||||
|
||||
30: // Read current state
|
||||
_fbReadCurrentState(
|
||||
sIPAddr:= sInverterIPAddr,
|
||||
@@ -543,7 +555,7 @@ CASE _iStateCyclicData OF
|
||||
|
||||
IF (NOT _fbReadCurrentState.bBusy) THEN
|
||||
_fbReadCurrentState(bExecute := FALSE);
|
||||
_iStateCyclicData := 40;
|
||||
_iStateCyclicData := 31;
|
||||
IF _fbReadCurrentState.bError THEN
|
||||
_iCurrentErrorCountRCS := _iCurrentErrorCountRCS + 1;
|
||||
_iErrorCountRCS := _iErrorCountRCS + 1;
|
||||
@@ -552,6 +564,13 @@ CASE _iStateCyclicData OF
|
||||
_iCurrentErrorCountRCS := 0;
|
||||
END_IF
|
||||
END_IF
|
||||
|
||||
31: // wait for next state
|
||||
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
|
||||
IF _tonPollingTimer.Q THEN
|
||||
_tonPollingTimer(IN := FALSE);
|
||||
_iStateCyclicData := 40;
|
||||
END_IF
|
||||
|
||||
40: // Read current pcu status
|
||||
_fbReadPCUState(
|
||||
@@ -571,7 +590,7 @@ CASE _iStateCyclicData OF
|
||||
|
||||
IF (NOT _fbReadPCUState.bBusy) THEN
|
||||
_fbReadPCUState(bExecute := FALSE);
|
||||
_iStateCyclicData := 50;
|
||||
_iStateCyclicData := 41;
|
||||
IF _fbReadPCUState.bError THEN
|
||||
_iCurrentErrorCountRPCUS := _iCurrentErrorCountRPCUS + 1;
|
||||
_iErrorCountRPCUS := _iErrorCountRPCUS + 1;
|
||||
@@ -584,6 +603,13 @@ CASE _iStateCyclicData OF
|
||||
END_IF
|
||||
END_IF
|
||||
|
||||
41: // wait for next state
|
||||
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
|
||||
IF _tonPollingTimer.Q THEN
|
||||
_tonPollingTimer(IN := FALSE);
|
||||
_iStateCyclicData := 50;
|
||||
END_IF
|
||||
|
||||
50: // Read current dc values
|
||||
_fbReadDCValues(
|
||||
sIPAddr:= sInverterIPAddr,
|
||||
@@ -603,7 +629,7 @@ CASE _iStateCyclicData OF
|
||||
// Check if reading modbus register is done
|
||||
IF (NOT _fbReadDCValues.bBusy) THEN
|
||||
_fbReadDCValues(bExecute := FALSE);
|
||||
_iStateCyclicData := 60;
|
||||
_iStateCyclicData := 51;
|
||||
// If there was no error and the converter has no error continue
|
||||
IF (NOT _fbReadDCValues.bError) THEN
|
||||
stCurrentValues.rActDCCurrent := LREAL_TO_REAL(WORD_TO_INT(_awCurrentDCValues[0]) * EXPT(10,WORD_TO_INT(_awCurrentDCValues[1])));
|
||||
@@ -620,6 +646,13 @@ CASE _iStateCyclicData OF
|
||||
END_IF
|
||||
END_IF
|
||||
|
||||
51: // wait for next state
|
||||
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
|
||||
IF _tonPollingTimer.Q THEN
|
||||
_tonPollingTimer(IN := FALSE);
|
||||
_iStateCyclicData := 60;
|
||||
END_IF
|
||||
|
||||
60: // Read current ac values
|
||||
_fbReadACValues(
|
||||
sIPAddr:= sInverterIPAddr,
|
||||
@@ -639,7 +672,7 @@ CASE _iStateCyclicData OF
|
||||
// Check if reading mudbus register is done
|
||||
IF (NOT _fbReadACValues.bBusy) THEN
|
||||
_fbReadACValues(bExecute := FALSE);
|
||||
_iStateCyclicData := 0;
|
||||
_iStateCyclicData := 61;
|
||||
// If there was no error and the converter has no error continue
|
||||
IF (NOT _fbReadACValues.bError) THEN
|
||||
stCurrentValues.rActACCurrent := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[0]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[4])));
|
||||
@@ -667,8 +700,49 @@ CASE _iStateCyclicData OF
|
||||
_iErrorIDRACV := _fbReadACValues.nErrId;
|
||||
END_IF
|
||||
END_IF
|
||||
|
||||
61: // wait for next state
|
||||
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
|
||||
IF _tonPollingTimer.Q THEN
|
||||
_tonPollingTimer(IN := FALSE);
|
||||
_iStateCyclicData := 70;
|
||||
END_IF
|
||||
|
||||
70:
|
||||
// Timeout should be less than timer interval
|
||||
_fbWriteHearbeatRegister(
|
||||
sIPAddr:= sInverterIPAddr,
|
||||
nTCPPort:= 502,
|
||||
nUnitID:= 16#01,
|
||||
nMBAddr:= WATCHDOG_REGISTER,
|
||||
nValue:= _uiWatchdogTimeoutSeconds,
|
||||
bExecute:= TRUE,
|
||||
tTimeout:= _tTimeoutWriteWatchdogRegister,
|
||||
bBusy=> ,
|
||||
bError=> ,
|
||||
nErrId=> );
|
||||
|
||||
// Because there is no heartbeat register to read,
|
||||
// we will use a successfull write as a valid heartbeat signal
|
||||
IF NOT _fbWriteHearbeatRegister.bBusy THEN
|
||||
_fbWriteHearbeatRegister(bExecute := FALSE);
|
||||
_iStateCyclicData := 0;
|
||||
IF _fbWriteHearbeatRegister.bError THEN
|
||||
_iCurrentErrorCountHB := _iCurrentErrorCountHB + 1;
|
||||
_iErrorCountHB := _iErrorCountHB + 1;
|
||||
_iErrorIDHB := _fbWriteHearbeatRegister.nErrId;
|
||||
IF _iCurrentErrorCountHB >= GVL_CONFIG.udiMaxConsecutiveInvError THEN
|
||||
xHeartbeatOk := FALSE;
|
||||
xError := TRUE;
|
||||
END_IF
|
||||
ELSE
|
||||
_iCurrentErrorCountHB := 0;
|
||||
xHeartbeatOk := TRUE;
|
||||
END_IF
|
||||
END_IF
|
||||
END_CASE
|
||||
|
||||
|
||||
// evaluate inverter state
|
||||
IF _eCurrentState = E_KACO_CURRENT_STATE.GRID_CONNECTED OR _eCurrentState = E_KACO_CURRENT_STATE.THROTTLED THEN
|
||||
xActive := TRUE;
|
||||
@@ -710,7 +784,7 @@ IF _xErrorCyclicData THEN
|
||||
_xErrorCyclicDataLedge := TRUE;
|
||||
END_IF
|
||||
|
||||
// handle alarm
|
||||
// handle cyclic data alarm
|
||||
IF _xErrorCyclicData AND NOT _fbCyclicDataAlarm.bRaised THEN
|
||||
_fbCyclicDataAlarm.Raise();
|
||||
END_IF
|
||||
@@ -721,42 +795,6 @@ END_IF
|
||||
|
||||
IF _fbCyclicDataAlarm.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xReset THEN
|
||||
_fbCyclicDataAlarm.Confirm(0);
|
||||
END_IF]]></ST>
|
||||
</Implementation>
|
||||
</Action>
|
||||
<Action Name="HandleHeartbeat" Id="{eeb5f65a-fd91-4c22-ab2e-3080c24e87fb}">
|
||||
<Implementation>
|
||||
<ST><![CDATA[// Self resetting watchdog timer
|
||||
_tonWatchdogResetTimer(IN := TRUE);
|
||||
|
||||
// Timeout should be less than timer interval
|
||||
_fbWriteHearbeatRegister(
|
||||
sIPAddr:= sInverterIPAddr,
|
||||
nTCPPort:= 502,
|
||||
nUnitID:= 16#01,
|
||||
nMBAddr:= WATCHDOG_REGISTER,
|
||||
nValue:= _uiWatchdogTimeoutSeconds,
|
||||
bExecute:= _tonWatchdogResetTimer.Q AND (NOT _fbWriteHearbeatRegister.bBusy),
|
||||
tTimeout:= _tTimeoutWriteWatchdogRegister,
|
||||
bBusy=> ,
|
||||
bError=> ,
|
||||
nErrId=> );
|
||||
|
||||
// Because there is no heartbeat register to read,
|
||||
// we will use a successfull write as a valid heartbeat signal
|
||||
IF NOT _fbWriteHearbeatRegister.bBusy THEN
|
||||
IF _fbWriteHearbeatRegister.bError THEN
|
||||
_iCurrentErrorCountHB := _iCurrentErrorCountHB + 1;
|
||||
_iErrorCountHB := _iErrorCountHB + 1;
|
||||
_iErrorIDHB := _fbWriteHearbeatRegister.nErrId;
|
||||
IF _iCurrentErrorCountHB >= GVL_CONFIG.udiMaxConsecutiveInvError THEN
|
||||
xHeartbeatOk := FALSE;
|
||||
xError := TRUE;
|
||||
END_IF
|
||||
ELSE
|
||||
_iCurrentErrorCountHB := 0;
|
||||
xHeartbeatOk := TRUE;
|
||||
END_IF
|
||||
END_IF
|
||||
|
||||
// set fault flag when error active
|
||||
@@ -764,7 +802,7 @@ IF NOT xHeartbeatOk THEN
|
||||
_xHeartBeatNOK := TRUE;
|
||||
END_IF
|
||||
|
||||
// handle alarm
|
||||
// handle heartbeat alarm
|
||||
IF NOT xHeartbeatOk AND NOT _fbHeartBeatAlarm.bRaised THEN
|
||||
_fbHeartBeatAlarm.Raise();
|
||||
END_IF
|
||||
@@ -775,11 +813,6 @@ END_IF
|
||||
|
||||
IF _fbHeartBeatAlarm.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xReset THEN
|
||||
_fbHeartBeatAlarm.Confirm(0);
|
||||
END_IF
|
||||
|
||||
// Reset timer
|
||||
IF _tonWatchdogResetTimer.Q THEN
|
||||
_tonWatchdogResetTimer(IN := FALSE);
|
||||
END_IF]]></ST>
|
||||
</Implementation>
|
||||
</Action>
|
||||
|
||||
Reference in New Issue
Block a user