Skip to content

Instantly share code, notes, and snippets.

@RozeDoyanawa
Last active February 22, 2019 12:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RozeDoyanawa/0939f08db3fea6dc496a785403476364 to your computer and use it in GitHub Desktop.
Save RozeDoyanawa/0939f08db3fea6dc496a785403476364 to your computer and use it in GitHub Desktop.
(* Status update timer setup *)
(* #wTmrStatusRefreshValue:= INT_TO_WORD(StatusRefreshInterval); *)
bEnableStatusUpdate:= NOT bStatusUpdateTimerFlag AND NOT bQueStatusUpdate AND NOT bQueInputUpdate AND NOT bQueStatusUpdate;
tmrStatusUpdate(EN:= EN, TON:= bEnableStatusUpdate, TimerValue:= INT_TO_WORD(StatusRefreshInterval), Out=>bStatusUpdateTimerFlag);
(* Retry timer setup *)
tmrRetry(EN:= EN, TON:= bTmrRetryEnable, TimerValue:= INT_TO_WORD(25), Out=> bTmrRetryFlag);
IF bStatusUpdateTimerFlag AND NOT Busy THEN (* If status update timer has triggered *)
bQueStatusUpdate:= TRUE; (* Schedule Status Word Update *)
END_IF;
IF bTmrRetryFlag THEN (* If retry timer has triggered *)
bTmrRetryEnable:= FALSE; (* Disable retry timer *)
(*bQueSetSpeed:= TRUE;*) (* Schedule setting of speed | Disabled*)
bQueSetControlWord:= TRUE; (* Schedule setting of control word *)
END_IF;
(* Main State Machine *)
CASE iState OF
(* Idle State *)
0: IF bQueStatusUpdate THEN
iState:= 1; (* Send Status Word Request *)
ELSIF bQueInputUpdate THEN
iState:= 3; (* Send Input Request *)
ELSIF wSpeed <> Speed OR bQueSetSpeed THEN
bQueSetSpeed:= FALSE; (* Clear Explicit Speed Update Request *)
iState:= 5; (* Send Speed Update *)
ELSIF bStarted <> Start OR bReversing <> Reversing OR bQueSetControlWord THEN (* If Start or reversing state is different from last transmission or if ControlWord transmission has explicitly been requested *)
bQueSetControlWord:= FALSE; (* Clear Explicit update request flag *)
iState:= 6; (* Send ControlWord Update *)
IF Start THEN (* Make sure to send speed an extra time when start was requested *)
wSpeed:= 0; (* Clear buffered speed to force re-send *)
END_IF;
END_IF;
(* Send Status Word Request *)
1: IF NOT bBusInUse AND NOT Busy AND NOT bModbus_Executing_P1 THEN
bBusInUse:= TRUE; (* Set Bus in use so no other block tries to claim it *)
Done:= FALSE; (* Clear previously set done flag *)
Busy:= TRUE; (* Set internal busy so we know we claimed the bus *)
w50Modbus_CommandData_P1[0]:= INT_TO_WORD(SlaveID); (* Load Slave ID *)
w50Modbus_CommandData_P1[1]:= 16#0003; (* Function code, 0x3=Read Holding Register *)
w50Modbus_CommandData_P1[2]:= 16#0004; (* Number of bytes to send NOT words. Excluding addr, size and function*)
w50Modbus_CommandData_P1[3]:= 16#C417; (* Holding register address 0xC417 is 50199 is Register(50200) is Status Control Word (SCW)*)
w50Modbus_CommandData_P1[4]:= INT_TO_WORD(1); (* Number of words to read *)
iState:= 2; (* Wait Status Word (SCW) Response *)
bModbus_Executing_P1:= TRUE; (* Initiate transfer *)
END_IF;
(* Wait Status Word Response *)
2:IF Busy AND NOT bModbus_Executing_P1 THEN
bQueStatusUpdate:= FALSE;
IF InputReading THEN (* If we are interested in input port states *)
iState:= 3; (* Send Input Request *)
ELSE
iState:= 0; (* Idle State *)
END_IF;
IF NOT bModbus_Error_P1 THEN (* Only if no bus error *)
IF w50Modbus_RecievedData_P1[2] = 0 THEN (* Only if response function is 0 *)
IF SHR (w50Modbus_RecievedData_P1[4] AND 16#00F0, 8) = 2 THEN (* If we received requested number of bytes *)
wReceived:= SHL(w50Modbus_RecievedData_P1[4] AND 16#00FF, 8) OR SHR(w50Modbus_RecievedData_P1[5] AND 16#FF00, 8);
DeviceStatus:= wReceived; (* Output received ControlWord *)
(* Mask out status bits *)
UnitReady:= (SHR(wReceived, 0) AND 16#1) = 1;
ControlReady:= (SHR(wReceived, 1) AND 16#1) = 1;
CoastingEnabled:= (SHR(wReceived, 2) AND 16#1) = 1;
Error_Trip:= (SHR(wReceived, 3) AND 16#1) = 1;
Error_NoTrip:= (SHR(wReceived, 4) AND 16#1) = 1;
TripLocked:= (SHR(wReceived, 6) AND 16#1) = 1;
Warning:= (SHR(wReceived, 7) AND 16#1) = 1;
SpeedOK:= (SHR(wReceived, 8) AND 16#1) = 1;
BusInControl:= (SHR(wReceived, 9) AND 16#1) = 1;
FrequencyLimitOK:= (SHR(wReceived, 10) AND 16#1) = 1;
Running:= (SHR(wReceived, 11) AND 16#1) = 1;
ResistorBreakFault:= (SHR(wReceived, 12) AND 16#1) = 1;
VoltageFault:=(SHR(wReceived, 13) AND 16#1) = 1;
TorqueFault:= (SHR(wReceived, 14) AND 16#1) = 1;
ThermalWarning:= (SHR(wReceived, 15) AND 16#1) = 1;
IF Running <> Start THEN (* If Local Start State differs from Frequency converter *)
bTmrRetryEnable:= TRUE; (* Retry setting state *)
END_IF;
END_IF;
END_IF;
Busy:= FALSE; (* Release Busy Flag *)
Done:= TRUE; (* Tell we are done *)
bBusInUse:= FALSE; (* Release Bus *)
END_IF;
END_IF;
(* Send Input Request *)
3: IF NOT bBusInUse AND NOT Busy AND NOT bModbus_Executing_P1 THEN
bBusInUse:= TRUE; (* Set Bus in use so no other block tries to claim it *)
Done:= FALSE; (* Clear previously set done flag *)
Busy:= TRUE; (* Set internal busy so we know we claimed the bus *)
w50Modbus_CommandData_P1[0]:= INT_TO_WORD(SlaveID); (* Load Slave ID *)
w50Modbus_CommandData_P1[1]:= 16#0003; (* Function code, 0x3=Read Holding Register *)
w50Modbus_CommandData_P1[2]:= 16#0004; (* Number of bytes to send NOT words. Excluding addr, size and function*)
w50Modbus_CommandData_P1[3]:= 16#40D7; (* Holding register address 0x40D7 is 16599 is Register(16600) is Config Param (16-60)*)
w50Modbus_CommandData_P1[4]:= INT_TO_WORD(1); (* Number of words to read *)
iState:= 4; (* Wait Input Request Response *)
bModbus_Executing_P1:= TRUE; (* Initiate transfer *)
END_IF;
(* Wait Input Request Response *)
4:IF Busy AND NOT bModbus_Executing_P1 THEN
bQueInputUpdate:= FALSE;
iState:= 0; (* Idle State *)
IF NOT bModbus_Error_P1 THEN (* Only if no bus error *)
IF w50Modbus_RecievedData_P1[2] = 0 THEN (* Only if response function is 0 *)
IF SHR (w50Modbus_RecievedData_P1[4] AND 16#00F0, 8) = 2 THEN (* If we received requested number of bytes *)
wReceived:= SHL(w50Modbus_RecievedData_P1[4] AND 16#00FF, 8) OR SHR(w50Modbus_RecievedData_P1[5] AND 16#FF00, 8);
(* Mask out input states *)
Input18:= (wReceived AND 16#F000) > 0;
Input19:= (wReceived AND 16#0F00) > 0;
Input27:= (wReceived AND 16#00F0) > 0;
Input33:= (wReceived AND 16#000F) > 0;
END_IF;
END_IF;
Busy:= FALSE; (* Release Busy Flag *)
Done:= TRUE; (* Tell we are done *)
bBusInUse:= FALSE; (* Release Bus *)
END_IF;
END_IF;
(* Send Speed Update *)
5: IF NOT bBusInUse AND NOT Busy AND NOT bModbus_Executing_P1 THEN
bBusInUse:= TRUE;(* Set Bus in use so no other block tries to claim it *)
Done:= FALSE; (* Clear previously set done flag *)
Busy:= TRUE; (* Set internal busy so we know we claimed the bus *)
wSpeed:= Speed;
w50Modbus_CommandData_P1[0]:= INT_TO_WORD(SlaveID); (* Load Slave ID *)
w50Modbus_CommandData_P1[1]:= 16#0010; (* Function code, 0x10=Write Holding Register *)
w50Modbus_CommandData_P1[2]:= 16#0007; (* Number of bytes to send NOT words. Excluding addr, size and function*)
w50Modbus_CommandData_P1[3]:= 16#C359; (* Holding register address 0xC359 is 50009 is Register(50010) is Bus Reference Value*)
w50Modbus_CommandData_P1[4]:= 16#0001; (* Number of words to write *)
w50Modbus_CommandData_P1[5]:= 16#0200 OR SHR(wSpeed,8); (* Byte Count + speed high-byte*)
w50Modbus_CommandData_P1[6]:= SHL(wSpeed AND 16#FF, 8); (* Speed low-byte *)
iState:= 100; (* State to Wait transfer complete / error*)
bModbus_Executing_P1:= TRUE; (* Initiate transfer *)
END_IF;
(* Send ControlWord Update *)
6: IF NOT bBusInUse AND NOT Busy AND NOT bModbus_Executing_P1 THEN (* Wait for bus to be free *)
bBusInUse:= TRUE;(* Set Bus in use so no other block tries to claim it *)
Done:= FALSE; (* Clear previously set done flag *)
Busy:= TRUE; (* Set internal busy so we know we claimed the bus *)
wTemp:= 0; (* Use a temporary variable to store the CTW *)
IF Start THEN (* If Start requested *)
wTemp:= wTemp OR SHR(16#1, 6); (* Set bit 6 of CTW *)
END_IF;
IF Reversing THEN (* If Reversing requested *)
wTemp:= wTemp OR SHR(16#1, 15); (* Set bit 15 of CTW *)
END_IF;
bReversing:= Reversing; (* Store written reversing state *)
bStarted:= Start; (* Store written start state *)
w50Modbus_CommandData_P1[0]:= INT_TO_WORD(SlaveID); (* Load Slave ID *)
w50Modbus_CommandData_P1[1]:= 16#0010; (* Function code, 3=Read Holding Register *)
w50Modbus_CommandData_P1[2]:= 16#0007; (* Number of bytes to send NOT words. Excluding addr, size and function*)
w50Modbus_CommandData_P1[3]:= 16#C34F; (* Holding register address 0xC34F is 49999 is Register(50000) is Control Word (CTW)*)
w50Modbus_CommandData_P1[4]:= 16#1; (* Number of words to write *)
w50Modbus_CommandData_P1[5]:= 16#0200 OR SHR(wTemp,8); (* Byte Count + CTW high-byte*)
w50Modbus_CommandData_P1[6]:= SHL(wTemp AND 16#FF, 8); (* CTW low-byte *)
iState:= 100; (* State to Wait bus Ready *)
bModbus_Executing_P1:= TRUE; (* Initiate transfer *)
END_IF;
(* Wait Transfer complete / error *)
100: IF Busy AND NOT bModbus_Executing_P1 THEN
iState:= 0; (* State to Idle State *)
Busy:= FALSE; (* Release Busy Flag *)
Done:= TRUE; (* Tell we are done *)
bBusInUse:= FALSE; (* Release Bus *)
END_IF;
END_CASE;
(* Bus error checking *)
IF Busy AND NOT bModbus_Executing_P1 AND bModbus_Error_P1 AND NOT ErrorClear AND NOT Error THEN (* If We own the bus and Executing stopped and there is a bus error *)
Error:= TRUE; (* Flag error *)
Busy:= FALSE; (* Clear Busy *)
bBusInUse:= FALSE; (* Release Bus *)
ELSIF Error AND ErrorClear THEN (* If there is an error and clearing it is requested *)
iState:= 0; (* Idle State *)
Error:= FALSE; (* Clear error flag *)
END_IF;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment