rMaxBattPower) THEN _rPowerInternal := rMaxBattPower; END_IF IF (rPower < -rMaxBattPower) THEN _rPowerInternal := -rMaxBattPower; END_IF CASE _iState OF 0: // Pre-init phase (no battery limits set) _fbTONSetBatteryLimits(IN := TRUE); IF _fbTONSetBatteryLimits.Q THEN _fbTONSetBatteryLimits(IN := FALSE); _iState := 10; END_IF 10: // Read scaling factors _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 2, nMBAddr:= BATTERY_LIMIT_SF, cbLength:= SIZEOF(_arBattScalingFactors), pDestAddr:= ADR(_arBattScalingFactors), bExecute:= TRUE, tTimeout:= T#30S, bBusy=> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN IF (NOT _fbReadRegister.bError) THEN _iState := 20; ELSE // Goto error state _iState := 0; END_IF _fbReadRegister(bExecute := FALSE); END_IF 20: // Set min voltage _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= DIS_MIN_V, cbLength:= SIZEOF(uiMinDisVoltage), pSrcAddr:= ADR(uiMinDisVoltage), 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 := 30; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 30: // Set max voltage _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= CHA_MAX_V, cbLength:= SIZEOF(uiMaxChaVoltage), pSrcAddr:= ADR(uiMaxChaVoltage), 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 := 40; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 40: // Set charge current _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= CHA_MAX_A, cbLength:= SIZEOF(uiMaxChaCurrent), pSrcAddr:= ADR(uiMaxChaCurrent), 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; ELSE // Goto error state _xErrorSetBatteryLimits := TRUE; _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 50: // Set discharge current _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= DIS_MAX_A, cbLength:= SIZEOF(uiMaxDisCurrent), pSrcAddr:= ADR(uiMaxDisCurrent), 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; ELSE // Goto error state _xErrorSetBatteryLimits := TRUE; _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 60: // Enable battery limits _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= EN_LIMIT, cbLength:= SIZEOF(_uiEnableLimit), pSrcAddr:= ADR(_uiEnableLimit), 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 // Battery limits set _xBatteryLimitsSet := TRUE; _xStartupBusy := FALSE; _iState := 70; ELSE // Goto error state //_xErrorSetBatteryLimits := TRUE; _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 70: // Try to set battery limits _rPowerInternal := 0; _iWSetPct := 0; _iState := 80; 80: // Battery limits are set, write zero power _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_SET_PCT, cbLength:= SIZEOF(_iWSetPct), pSrcAddr:= ADR(_iWSetPct), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> ); IF NOT _fbWriteRegister.bBusy THEN IF (NOT _fbWriteRegister.bError) THEN _iState := 90; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 90: // Read max power scaling _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_MAX_SF, 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 := 100; // Check for valid value IF (_iWMaxSF < -10) OR (_iWMaxSF > 10) OR (_iWMaxSF = 16#8000) THEN ADSLOGSTR(msgCtrlMask := ADSLOG_MSGTYPE_HINT, msgFmtStr := 'FBInverter into error state from: %s', strArg := TO_STRING(_iState)); // Goto error state _iState := 1000; END_IF ELSE xError := TRUE; // Goto error state _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 100: // Read max power _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_MAX, cbLength:= SIZEOF(_uiWMax), pDestAddr:= ADR(_uiWMax), 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 := 110; // Calculate WMax // Reading a register with scaling factor = value * 10^SF _rWMax := LREAL_TO_REAL(_uiWMax * EXPT(10,_iWMaxSF)); ELSE xError := TRUE; // Goto error state _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 110: // Idle state, wait for enable IF _tonPollingTimer.Q THEN _tonPollingTimer(IN := FALSE, PT := _timPollingDelay); _iState := 120; END_IF // If enable and INTLK Ok IF xEnable THEN // _iState := 130; _iState := 130; _rPowerInternal := 0.0; _iWSetPct := 0; _uiPCSSetOperation := 11; _tonPollingTimer(IN := FALSE, PT := _timPollingDelay); ELSE _tonPollingTimer(IN := TRUE, PT := _timPollingDelay); _rPowerInternal := 0.0; _iWSetPct := 0; END_IF 120: // Write current power demand _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_SET_PCT, cbLength:= SIZEOF(_iWSetPct), pSrcAddr:= ADR(_iWSetPct), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> ); IF NOT _fbWriteRegister.bBusy THEN IF (NOT _fbWriteRegister.bError) THEN _iState := 121; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 121: // Read current dc values _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 6, 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 := 122; stCurrentValues.rActDCCurrent := LREAL_TO_REAL(WORD_TO_INT(_awCurrentDCValues[0]) * EXPT(10,WORD_TO_INT(_awCurrentDCValues[1]))); stCurrentValues.rActDCVoltage := LREAL_TO_REAL(WORD_TO_UINT(_awCurrentDCValues[2]) * EXPT(10,WORD_TO_INT(_awCurrentDCValues[3]))); stCurrentValues.rActDCPower := LREAL_TO_REAL(WORD_TO_INT(_awCurrentDCValues[4]) * EXPT(10,WORD_TO_INT(_awCurrentDCValues[5]))); ELSE xError := TRUE; // Goto error state _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 122: // Read current ac values _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 22, nMBAddr:= AC_VALUES_START_REGISTER, cbLength:= SIZEOF(_awCurrentACValues), pDestAddr:= ADR(_awCurrentACValues), 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 := 123; stCurrentValues.rActACCurrent := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[0]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[4]))); stCurrentValues.rActtACPhaseACurrent := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[1]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[4]))); stCurrentValues.rActtACPhaseBCurrent := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[2]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[4]))); stCurrentValues.rActtACPhaseCCurrent := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[3]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[4]))); stCurrentValues.rActACPower := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[12]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[13]))); stCurrentValues.rActACFreq := LREAL_TO_REAL(WORD_TO_UINT(_awCurrentACValues[14]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[15]))); stCurrentValues.rActApparentPower := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[16]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[17]))); stCurrentValues.rActReactivePower := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[18]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[19]))); stCurrentValues.rActPowerFactor := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[20]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[21]))); ELSE // Read error register _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 123: // Read current status _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 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 (NOT _fbReadRegister.bError) THEN // IF (NOT xEnable) THEN // _iState := 110; // ELSE // _iState := 140; // END_IF _iState := 124; ELSE _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 124: // Reset if in error state and not enabled // Inverter in error state IF (_uiInverterState = 7) THEN // Inverter not enabled, so try a reset IF (NOT xEnable) THEN _uiPCSSetOperation := 1; _iState := 125; ELSE // Else go to error state _iState := 1000; END_IF ELSE // No error and not enabled IF (NOT xEnable) THEN // Goto polling state _iState := 110; ELSE // No error and enabled, goto enabled polling state _iState := 140; END_IF END_IF 125: // Send off/reset command _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 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 := 110; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 130: // Go to started _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 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 := 133; ELSE _uiPCSSetOperation := 1; // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 131: // Wait for inverter to be online and in state Grid Connected(11) _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 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 Grid Connected(11) then continue IF NOT _fbReadRegister.bError AND _uiInverterState = 8 THEN _uiInverterState := 11; _iState := 133; END_IF // If the inverter is not ready wait some time before polling again IF NOT _fbReadRegister.bError AND _uiInverterState <> 8 THEN _iState := 132; END_IF _fbReadRegister(bExecute := FALSE); END_IF // If not enable, go back to idle IF (NOT xEnable) THEN _fbReadRegister(bExecute := FALSE); _iState := 110; END_IF 132: // Delay polling inverter ready _tonPollingTimer(IN := TRUE, PT := _timPollingDelay); IF _tonPollingTimer.Q THEN _tonPollingTimer(IN := FALSE); _iState := 131; END_IF // If not enable, go back to idle IF (NOT xEnable) THEN _tonPollingTimer(IN := FALSE); _iState := 110; END_IF 133: // Standby mode to grid connect _fbReadRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 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 Grid Connected(11) then continue IF NOT _fbReadRegister.bError AND _uiInverterState = 4 THEN //_uiPCSSetOperation := 11; xActive := TRUE; _iState := 140; END_IF // If the inverter is not ready wait some time before polling again IF NOT _fbReadRegister.bError AND _uiInverterState <> 4 THEN _iState := 134; END_IF _fbReadRegister(bExecute := FALSE); END_IF // If not enable, go back to idle // IF (NOT xEnable) THEN // _fbReadRegister(bExecute := FALSE); // _iState := 110; // END_IF 134: // Polling timer delay _tonPollingTimer(IN := TRUE, PT := _timPollingDelay); IF _tonPollingTimer.Q THEN _tonPollingTimer(IN := FALSE); _iState := 133; END_IF // If not enable, go back to idle IF (NOT xEnable) THEN _tonPollingTimer(IN := FALSE); _iState := 110; END_IF 140: // Enabled _tonPollingTimer(IN := TRUE); IF _tonPollingTimer.Q THEN _tonPollingTimer(IN := FALSE, PT := _timPollingDelay); // Calculate power to write to register _iWSetPct := LREAL_TO_INT((_rPowerInternal*100)/(_rWMax * EXPT(10,-2))); _iState := 120; END_IF // If enable and INTLK Ok IF (NOT xEnable) THEN _rPowerInternal := 0.0; _iWSetPct := 0; _uiPCSSetOperation := 1; _tonPollingTimer(IN := FALSE, PT := _timPollingDelay); _iState := 150; END_IF 150: // Send shutdown power command _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= W_SET_PCT, cbLength:= SIZEOF(_iWSetPct), pSrcAddr:= ADR(_iWSetPct), bExecute:= TRUE, tTimeout:= T#5S, bBusy=> , bError=> , nErrId=> ); IF NOT _fbWriteRegister.bBusy THEN IF (NOT _fbWriteRegister.bError) THEN _iState := 151; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 151: // Goto off state _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 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 xActive := FALSE; _iState := 110; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 1000: // Error state xActive := FALSE; xError := TRUE; _iState := 1001; 1001: // Error state, wait for reset IF xReset AND (NOT xEnable) THEN _uiPCSSetOperation := 1; xError := FALSE; _iState := 1002; END_IF 1002: // Try to clear all error by going into off state _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#01, // 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 xActive := FALSE; _iState := 110; ELSE // Goto error state _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF END_CASE // Calculate power to write to register // (could not find where the scaling for wset can be read but its -2!) // => 10% = 1000 // Writing a register with scaling factor = value / (10^SF) //_iWSetPct := LREAL_TO_INT((_rPowerInternal*100)/(_rWMax * EXPT(10,-2)));]]> , bError=> , nErrId=> , cbRead=> ); // Check if reading mudbus register is done IF NOT _fbReadRegister.bBusy THEN IF (NOT _fbReadRegister.bError) THEN _iState := 20; ELSE // Goto error state //_xErrorSetBatteryLimits := TRUE; _iState := 1000; END_IF _fbReadRegister(bExecute := FALSE); END_IF 20: // Set min voltage _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= DIS_MIN_V, cbLength:= SIZEOF(uiMinDisVoltage), pSrcAddr:= ADR(uiMinDisVoltage), 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 := 30; ELSE // Goto error state //_xErrorSetBatteryLimits := TRUE; _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 30: // Set max voltage _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= CHA_MAX_V, cbLength:= SIZEOF(uiMaxChaVoltage), pSrcAddr:= ADR(uiMaxChaVoltage), 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 := 40; ELSE // Goto error state //_xErrorSetBatteryLimits := TRUE; _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 40: // Set charge current _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= CHA_MAX_A, cbLength:= SIZEOF(uiMaxChaCurrent), pSrcAddr:= ADR(uiMaxChaCurrent), 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; ELSE // Goto error state _xErrorSetBatteryLimits := TRUE; _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 50: // Set discharge current _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= DIS_MAX_A, cbLength:= SIZEOF(uiMaxDisCurrent), pSrcAddr:= ADR(uiMaxDisCurrent), 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; ELSE // Goto error state _xErrorSetBatteryLimits := TRUE; _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 60: // Enable battery limits _fbWriteRegister( sIPAddr:= sInverterIPAddr, nTCPPort:= 502, nUnitID:= 16#FF, // 16#FF for Modbus TCP nQuantity:= 1, nMBAddr:= EN_LIMIT, cbLength:= SIZEOF(_uiEnableLimit), pSrcAddr:= ADR(_uiEnableLimit), 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 // Battery limits set _xBatteryLimitsSet := TRUE; _xStartupBusy := FALSE; _iState := 0; ELSE // Goto error state //_xErrorSetBatteryLimits := TRUE; _iState := 1000; END_IF _fbWriteRegister(bExecute := FALSE); END_IF 1000: // Error state _iStateStartup := 0; _xErrorSetBatteryLimits := TRUE; _xBatteryLimitsSet := FALSE; _xStartupBusy := FALSE; END_CASE]]>