rMaxBattPower) THEN rPower := rMaxBattPower; END_IF IF (rPower < -rMaxBattPower) THEN rPower := -rMaxBattPower; END_IF // State machine CASE _iState OF 0: // Off // If enable and INTLK Ok IF xEnable THEN _iState := 10; xCloseDCRelais := TRUE; END_IF 10: // Wait for inverter to be online and in state STANDBY(8) _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= STATUS_REGISTER, cbLength:= SIZEOF(_uiInverterState), pDestAddr:= ADR(_uiInverterState), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN // If there was no error and the state is STANDBY(8) then continue IF NOT _fbReadRegister.bError AND _uiInverterState = 8 THEN _iState := 20; END_IF _fbReadRegister(bExecute := FALSE); END_IF 20: // Read inverter max power scaling _iErrorInState := _iState; _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_MAX_SF_REGISTER, cbLength:= SIZEOF(_iWMaxSF), pDestAddr:= ADR(_iWMaxSF), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN // If there was no error then continue IF NOT _fbReadRegister.bError THEN _iState := 25; // Check for valid value IF (_iWMaxSF < -10) OR (_iWMaxSF > 10) OR (_iWMaxSF = 16#8000) THEN // Goto error state _iState := 1000; END_IF ELSE xError := TRUE; // Goto error state _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 25: // Read inverter Max power limit scaling _iErrorInState := _iState; _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_MAX_LIM_PCT_SF_REGISTER, cbLength:= SIZEOF(_iWMaxLimPctSF), pDestAddr:= ADR(_iWMaxLimPctSF), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN // If there was no error then continue IF NOT _fbReadRegister.bError THEN _iState := 30; // Check for valid value IF (_iWMaxLimPctSF < -10) OR (_iWMaxLimPctSF > 10) OR (_iWMaxLimPctSF = 16#8000) THEN // Goto error state _iState := 1000; END_IF ELSE xError := TRUE; // Goto error state _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 30: // Read inverter max power _iErrorInState := _iState; _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_MAX_REGISTER, cbLength:= SIZEOF(_iWMax), pDestAddr:= ADR(_iWMax), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN // If there was no error then continue IF NOT _fbReadRegister.bError THEN _iState := 40; // Reading a register with scaling factor = value * 10^SF _rWMax := _iWMax * EXPT(10,_iWMaxSF); // Calculate power to write to register _iWMaxLimPct := LREAL_TO_INT(rPower * EXPT(10,_iWMaxLimPctSF) / _rWMax); ELSE xError := TRUE; // Goto error state _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 40: // Set power limit _iErrorInState := _iState; _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_MAX_LIM_PCT_REGISTER, cbLength:= SIZEOF(_iWMaxLimPct), pSrcAddr:= ADR(_iWMaxLimPct), 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 := 50; _rOldPower := rPower; _uiMaxLimEn := 1; ELSE xError := TRUE; // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 50: // Enable Power limiting (THROTTLED) _iErrorInState := _iState; _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_MAX_LIM_EN_REGISTER, cbLength:= SIZEOF(_uiMaxLimEn), pSrcAddr:= ADR(_uiMaxLimEn), 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 := 60; _uiPCSSetOperation := 1; ELSE xError := TRUE; // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 60: // Switch to THROTTLED mode _iErrorInState := _iState; _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= PCS_SET_OPERATION_REGISTER, cbLength:= SIZEOF(_uiPCSSetOperation), pSrcAddr:= ADR(_uiPCSSetOperation), 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 := 65; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 65: // Wait for error polling timer _tonPollingTimer(IN := TRUE, PT := _timPollingDelay); IF _tonPollingTimer.Q THEN _tonPollingTimer(IN := FALSE); _iState := 70; ELSIF ABS(rPower - _rOldPower) > 0.1 THEN _tonPollingTimer(IN := FALSE); // If power has ben changed, goto set power limit mode _iState := 40; END_IF // check if inverter should shut down IF NOT xEnable THEN _uiPCSSetOperation := 3; // Goto shutdown sequence _iState := 200; END_IF 70: // Enabled, check for error _iErrorInState := _iState; _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= STATUS_REGISTER, cbLength:= SIZEOF(_uiInverterState), pDestAddr:= ADR(_uiInverterState), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN // If there was no error and the converter has no error continue IF NOT _fbReadRegister.bError AND (_uiInverterState <> 7) THEN _iState := 80; IF (_uiInverterState = 4) OR (_uiInverterState = 5) THEN xActive := TRUE; ELSE xActive := FALSE; END_IF ELSE xError := TRUE; // Read error register _iState := 990; END_IF _fbReadRegister(bExecute := FALSE); END_IF 80: // Read current DC values _iErrorInState := _iState; _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 4, nMBAddr:= DC_VALUES_START_REGISTER, cbLength:= SIZEOF(_awCurrentDCValues), pDestAddr:= ADR(_awCurrentDCValues), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN // If there was no error and the converter has no error continue IF NOT _fbReadRegister.bError THEN _iState := 65; rActDCCurrent := WORD_TO_UINT(_awCurrentDCValues[0]) * EXPT(10,WORD_TO_INT(_awCurrentDCValues[1])); rActDCVoltage := WORD_TO_UINT(_awCurrentDCValues[2]) * EXPT(10,WORD_TO_INT(_awCurrentDCValues[3])); ELSE // Read error register _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 200: // Shutdown sequence _iErrorInState := _iState; _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= PCS_SET_OPERATION_REGISTER, cbLength:= SIZEOF(_uiPCSSetOperation), pSrcAddr:= ADR(_uiPCSSetOperation), 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 := 210; rActDCCurrent := 0.0; rActDCVoltage := 0.0; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 210: // Wait for poll timer to _tonPollingTimer(IN := TRUE, PT := _timPollingDelay); IF _tonPollingTimer.Q THEN _tonPollingTimer(IN := FALSE); _iState := 220; END_IF 220: // Poll and wait for standby state _iErrorInState := _iState; _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= STATUS_REGISTER, cbLength:= SIZEOF(_uiInverterState), pDestAddr:= ADR(_uiInverterState), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN // If there was no error and the converter has no error continue IF NOT _fbReadRegister.bError THEN _iState := 0; xActive := FALSE; xCloseDCRelais := FALSE; END_IF _fbReadRegister(bExecute := FALSE); END_IF 990: // Read error register _iErrorInState := _iState; _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 2, nMBAddr:= EVT_1_REGISTER, cbLength:= SIZEOF(_dwErrorBits), pDestAddr:= ADR(_dwErrorBits), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN // If there was no error and the converter has no error continue IF NOT _fbReadRegister.bError THEN _iState := 1000; END_IF _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, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= PCS_ALARM_RESET_REGISTER, cbLength:= SIZEOF(_uiResetInverter), pSrcAddr:= ADR(_uiResetInverter), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> ); IF NOT _fbWriteRegister.bBusy THEN _iState := 0; _fbWriteRegister(bExecute := FALSE); END_IF END_CASE]]>