Fixed Modbus register access

This commit is contained in:
Matthias Heisig
2024-01-17 11:26:11 +01:00
parent 82826c258a
commit 57987cb19f
24 changed files with 1310 additions and 572 deletions

View File

@@ -10,11 +10,17 @@ VAR_INPUT
rMaxBattPower : REAL := 24_000; // 24kW
END_VAR
VAR_OUTPUT
// Output for SCS DC-Relais
xCloseDCRelais AT %Q*: BOOL;
rActDCCurrent : REAL;
rActDCVoltage : REAL;
xError : BOOL;
// Inverter active
xActive : BOOL;
// FB error
xError : BOOL;
// Current inverter values
stCurrentValues : ST_SUNSPEC_CURRENT_VALUES;
END_VAR
VAR
// Current state
@@ -41,6 +47,10 @@ VAR
// Unscaled limit for converter power
_iWMaxLimPct : INT;
// Reread set power limit
_iWMaxLimPctRead : INT;
_iWMaxLimPctReadScaled : REAL;
// Scaling factor for power limiting
_iWMaxLimPctSF : INT;
@@ -71,8 +81,11 @@ VAR
// Timer for polling of current values
_tonPollingTimer : TON;
// Current DC values (DCA, DCA_SF, DCV, DCV_SF) in word array for efficient modbus reading
_awCurrentDCValues : ARRAY[0..3] OF WORD;
// Current DC values (DCA, DCA_SF, DCV, DCV_SF, DCW, DCW_SF) in word array for efficient modbus reading
_awCurrentDCValues : ARRAY[0..5] OF WORD;
// Current AC values (W, W_SF, Hz, Hz_SF, VA, VA_SF, VAr, VAr_SF, PF, PF_SF) in word array for efficient modbus reading
_awCurrentACValues : ARRAY[0..9] OF WORD;
// Inverter error bits
_dwErrorBits : DWORD;
@@ -88,7 +101,7 @@ VAR CONSTANT
// Throttled power register
// Size 1, int16 (Range = -32767 .. 32767, Not implemented 0x8000)
W_MAX_LIM_PCT_REGISTER : WORD := 40187;
W_MAX_LIM_PCT_REGISTER : WORD := 40187;
// Throttled power register scaling factor
// Size 1, sunssf (int16) (Range = -10 .. 10, Not implemented 0x8000)
@@ -126,6 +139,10 @@ VAR CONSTANT
// Size 4
DC_VALUES_START_REGISTER : WORD := 40097;
// Start of register with the current ac values
// SIZE 10
AC_VALUES_START_REGISTER : WORD := 40084;
// Error bits register
// Size 2
EVT_1_REGISTER : WORD := 40110;
@@ -143,6 +160,7 @@ END_IF
// State machine
CASE _iState OF
0: // Off
// If enable and INTLK Ok
IF xEnable THEN
@@ -172,8 +190,34 @@ CASE _iState OF
IF NOT _fbReadRegister.bError AND _uiInverterState = 8 THEN
_iState := 20;
END_IF
// If the inverter is not ready wait some time before polling again
IF NOT _fbReadRegister.bError AND _uiInverterState <> 8 THEN
_iState := 15;
END_IF
_fbReadRegister(bExecute := FALSE);
END_IF
// If not enable, go back to idle
IF NOT xEnable THEN
_fbReadRegister(bExecute := FALSE);
_iState := 0;
END_IF
15: // Delay polling inverter ready
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
IF _tonPollingTimer.Q THEN
_tonPollingTimer(IN := FALSE);
_iState := 10;
END_IF
// If not enable, go back to idle
IF NOT xEnable THEN
_tonPollingTimer(IN := FALSE);
_iState := 0;
END_IF
20: // Read inverter max power scaling
_iErrorInState := _iState;
@@ -271,7 +315,7 @@ CASE _iState OF
_rWMax := LREAL_TO_REAL(_iWMax * EXPT(10,_iWMaxSF));
// Calculate power to write to register
_iWMaxLimPct := LREAL_TO_INT(rPower * EXPT(10,_iWMaxLimPctSF) / _rWMax);
_iWMaxLimPct := LREAL_TO_INT((rPower*100)/(_rWMax * EXPT(10,_iWMaxLimPctSF)));
ELSE
xError := TRUE;
// Goto error state
@@ -311,6 +355,32 @@ CASE _iState OF
_fbWriteRegister(bExecute := FALSE);
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(
@@ -369,7 +439,7 @@ CASE _iState OF
_fbWriteRegister(bExecute := FALSE);
END_IF
65: // Wait for error polling timer
65: // Wait for polling timer
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
IF _tonPollingTimer.Q THEN
_tonPollingTimer(IN := FALSE);
@@ -378,6 +448,8 @@ CASE _iState OF
_tonPollingTimer(IN := FALSE);
// If power has ben changed, goto set power limit mode
_iState := 40;
// Calculate power to write to register
_iWMaxLimPct := LREAL_TO_INT((rPower*100)/(_rWMax * EXPT(10,_iWMaxLimPctSF)));
END_IF
// check if inverter should shut down
@@ -428,7 +500,7 @@ CASE _iState OF
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nQuantity:= 4,
nQuantity:= 6,
nMBAddr:= DC_VALUES_START_REGISTER,
cbLength:= SIZEOF(_awCurrentDCValues),
pDestAddr:= ADR(_awCurrentDCValues),
@@ -443,9 +515,45 @@ CASE _iState OF
IF NOT _fbReadRegister.bBusy THEN
// If there was no error and the converter has no error continue
IF NOT _fbReadRegister.bError THEN
_iState := 85;
stCurrentValues.rActDCCurrent := LREAL_TO_REAL(WORD_TO_UINT(_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
// Read error register
_iState := 1000;
END_IF
_fbReadRegister(bExecute := FALSE);
END_IF
85: // Read current ac values
_iErrorInState := _iState;
_fbReadRegister(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nQuantity:= 10,
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
// Go back to polling state
_iState := 65;
rActDCCurrent := LREAL_TO_REAL(WORD_TO_UINT(_awCurrentDCValues[0]) * EXPT(10,WORD_TO_INT(_awCurrentDCValues[1])));
rActDCVoltage := LREAL_TO_REAL(WORD_TO_UINT(_awCurrentDCValues[2]) * EXPT(10,WORD_TO_INT(_awCurrentDCValues[3])));
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])));
stCurrentValues.rActReactivePower := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[6]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[7])));
stCurrentValues.rActPowerFactor := LREAL_TO_REAL(WORD_TO_INT(_awCurrentACValues[8]) * EXPT(10,WORD_TO_INT(_awCurrentACValues[9])));
ELSE
// Read error register
_iState := 1000;
@@ -474,8 +582,8 @@ CASE _iState OF
// And there is no error, then continue
IF NOT _fbWriteRegister.bError THEN
_iState := 210;
rActDCCurrent := 0.0;
rActDCVoltage := 0.0;
stCurrentValues.rActDCCurrent := 0.0;
stCurrentValues.rActDCVoltage := 0.0;
ELSE
// Goto error state
_iState := 1000;
@@ -572,7 +680,27 @@ CASE _iState OF
END_CASE]]></ST>
</Implementation>
<LineIds Name="FB_PowerSupplySunspec">
<LineId Id="774" Count="70" />
<LineId Id="774" Count="10" />
<LineId Id="1550" Count="0" />
<LineId Id="785" Count="28" />
<LineId Id="1701" Count="5" />
<LineId Id="814" Count="1" />
<LineId Id="1714" Count="0" />
<LineId Id="1719" Count="0" />
<LineId Id="1715" Count="0" />
<LineId Id="1718" Count="0" />
<LineId Id="1716" Count="1" />
<LineId Id="1707" Count="1" />
<LineId Id="1710" Count="2" />
<LineId Id="1709" Count="0" />
<LineId Id="1713" Count="0" />
<LineId Id="1720" Count="0" />
<LineId Id="1722" Count="1" />
<LineId Id="1726" Count="0" />
<LineId Id="1725" Count="0" />
<LineId Id="1721" Count="0" />
<LineId Id="1433" Count="0" />
<LineId Id="816" Count="28" />
<LineId Id="1171" Count="0" />
<LineId Id="845" Count="33" />
<LineId Id="1172" Count="0" />
@@ -580,9 +708,19 @@ END_CASE]]></ST>
<LineId Id="1173" Count="0" />
<LineId Id="913" Count="29" />
<LineId Id="1174" Count="0" />
<LineId Id="943" Count="28" />
<LineId Id="943" Count="4" />
<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="948" Count="23" />
<LineId Id="1175" Count="0" />
<LineId Id="972" Count="46" />
<LineId Id="972" Count="42" />
<LineId Id="1560" Count="1" />
<LineId Id="1015" Count="3" />
<LineId Id="1127" Count="0" />
<LineId Id="1019" Count="25" />
<LineId Id="1097" Count="1" />
@@ -594,8 +732,17 @@ END_CASE]]></ST>
<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="1739" Count="19" />
<LineId Id="1781" Count="0" />
<LineId Id="1759" Count="2" />
<LineId Id="1774" Count="0" />
<LineId Id="1776" Count="1" />
<LineId Id="1762" Count="4" />
<LineId Id="1738" Count="0" />
<LineId Id="1093" Count="1" />
<LineId Id="1102" Count="19" />
<LineId Id="1166" Count="1" />

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1" ProductVersion="3.1.4024.12">
<DUT Name="ST_SUNSPEC_CURRENT_VALUES" Id="{429ce2f6-f580-460c-8eb4-3ddb289effd4}">
<Declaration><![CDATA[TYPE ST_SUNSPEC_CURRENT_VALUES :
STRUCT
// Current DC current (A)
rActDCCurrent : REAL;
// Current DC voltage (V)
rActDCVoltage : REAL;
// Current DC power (W)
rActDCPower : REAL;
// Current AC power (W)
rActACPower : REAL;
// Current AC frequency (Hz)
rActACFreq : REAL;
// Current AC apparent power (VA)
rActApparentPower : REAL;
// Current AC reactive power (VAr)
rActReactivePower : REAL;
// Current AC power factor
rActPowerFactor : REAL;
END_STRUCT
END_TYPE
]]></Declaration>
</DUT>
</TcPlcObject>