MODBUS-RTU
Function Blocks
FB_Component_ModbusRTUMaster
| FUNCTION_BLOCK FB_Component_ModbusRTUMaster EXTENDS FB_ComponentBase IMPLEMENTS I_ModbusProvider
|
Contains required function blocks and logic to implement a Modbus-RTU master. Single and multi-drop configurations are supported.
Note
- This component contains function blocks that require a TF6255 license
- At this time, only KL/EL6xxx terminals implementing 22 byte buffers are supported
Design Notes
- Modbus slaves should implement
I_ModbusConsumer
and at a minimum provide a unique identifier for the slave via SlaveID
.
- Modbus requests contain one or many operations. Operations are further divided into R/W operations. An R/W operation is defined by a start & end register(s), as well as a pointer to where the master should read/write the data for the above register(s).
- Modbus requests are categorized as Sync or Async. Sync operations are analagous to EtherCAT process data, with a notable exception that they are processed serially versus completed cyclically. Async operations are meant to only be executed once (example a momentary pushbutton signal), and always take precedence over sync operations.
- Care should be taken to understand the relationship between the task cycle time, the hardware buffering mechanisms, and the inherent limitation on data throughput that this creates. Note this is separate from baud rate. See Transfer Rates.
- Process data links to/from the serial hardware are provided by the component.
Examples
Setting up sync requests in init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 | CASE SequenceState OF
0:
//Housekeeping--event creation, etc.
IF SUPER^.Initialize() THEN
SequenceState := SequenceState + 10;
END_IF
10:
//Wait for Modbus master assigned
//**This is application-dependant. In this example the slave FB has a property for passing in an interface to FB_Component_ModbusRTUMaster**
IF ipModbusMaster <> 0 AND _SlaveID <> 0 THEN
SequenceState := SequenceState + 10;
END_IF
20:
//Setup normal sync data reads
SyncData.ipRequestor := THIS^; //Allows master to call back after request complete
SyncData.ReadOps[1].StartAddress := 1000;
SyncData.ReadOps[1].EndAddress := 1010;
SyncData.ReadOps[1].pAddress := ADR(MySlaveStatusData); //This could be a DUT, group of vars, etc.
IF ipModbusMaster.RegisterSyncRequest(Request := SyncData, RequestID => SyncData.RequestID) THEN
SequenceState := SequenceState + 10;
END_IF
30:
//Setup async requests
//** In this case AsyncRequests is an array of ST_ModbusRequest **
FOR i := 1 TO MAX_ASYNC_REQUESTS DO
AsyncRequests[i].ipRequestor := THIS^;
END_FOR
// Stop Request - Write Stop Command
AsyncRequests[E_AsyncRequest.eAsyncRequest_Stop].WriteOps[1].StartAddress := 1023;
AsyncRequests[E_AsyncRequest.eAsyncRequest_Stop].WriteOps[1].EndAddress := 1024;
AsyncRequests[E_AsyncRequest.eAsyncRequest_Stop].WriteOps[1].pAddress := ADR(StopCommandFlag);
// Move Request - Write Move Command
AsyncRequests[E_AsyncRequest.eAsyncRequest_Move].WriteOps[1].StartAddress := 1020;
AsyncRequests[E_AsyncRequest.eAsyncRequest_Move].WriteOps[1].EndAddress := 1021;
AsyncRequests[E_AsyncRequest.eAsyncRequest_Move].WriteOps[1].pAddress := ADR(MoveCommandFlag);
SequenceState := SequenceState + 10;
40:
Trace('Init complete');
Initialize := TRUE;
END_CASE
|
Register an async request
| IF ipModbusMaster
.RegisterAsyncRequest(Request := AsyncRequests[E_Bansbach_AsyncRequest.eBansbachAsyncRequest_Stop], RequestID => AsyncRequests[E_Bansbach_AsyncRequest.eBansbachAsyncRequest_Stop].RequestID) THEN
Trace('Stop commanded');
Stop := TRUE;
END_IF
|
Handle request complete callback
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | METHOD ModbusRequestComplete
VAR_INPUT
RequestID : ULINT;
END_VAR
VAR
i : UDINT;
END_VAR
~~~~~~~~~~
//If the completed request is an async request, reset the RequestID to signal completed
CurrentCommsCount := CurrentCommsCount + 1;
FOR i := 1 TO MAX_ASYNC_REQUESTS DO
IF AsyncRequests[i].RequestID = RequestID THEN
Trace('Async modbus request completed');
AsyncRequests[i].RequestID := 0;
EXIT;
END_IF
END_FOR
|
Interfaces
I_ModbusConsumer
Function blocks requiring R/W services from the master shall implement I_ModbusConsumer
. This interface provides mechanisms for corellating particular function block instances with the Modbus slaves they represent, as well as a callback mechanism for the master to notify slaves of status information.
Properties
Property |
Type |
Access |
Description |
SlaveID |
BYTE |
R |
Unique slave identifier on bus |
Methods
Method |
Return Type |
Description |
ModbusRequestComplete |
null |
Callback from I_ModbusProvider which signals that a particular request (sync/async) has been completed. Input parameter RequestID is given by the master to indicate which request completed. |
I_ModbusProvider
Function blocks implementing I_ModbusConsumer
register their R/W requests with the master via the methods provided by I_ModbusProvider
.
Methods
Method |
Return Type |
Description |
RegisterAsyncRequest |
BOOL |
Register a set of asynchronous R/W operations to be executed as soon as possible |
RegisterSyncRequest |
BOOL |
Register a set of synchronous R/W operations to be executed cyclically, in order of registration |
DUTs
ST_ModbusOperation
| TYPE ST_ModbusOperation :
STRUCT
StartAddress : UINT;
EndAddress : UINT;
pAddress : PVOID;
END_STRUCT
END_TYPE
|
ST_ModbusRequest
| TYPE ST_ModbusRequest :
STRUCT
ipRequestor : I_ModbusConsumer;
RequestID : ULINT;
ReadOps : ARRAY[1..Parameters_ModbusRTU.MAX_MODBUS_RW_OPS_PER_REQUEST] OF ST_ModbusOperation;
WriteOps : ARRAY[1..Parameters_ModbusRTU.MAX_MODBUS_RW_OPS_PER_REQUEST] OF ST_ModbusOperation;
END_STRUCT
END_TYPE
|
Globals/Parameters
Parameters_ModbusRTU
Parameter |
Type |
Default |
Description |
MAX_MODBUS_REQUESTS |
UDINT |
100 |
Maximum sync & async requests that can be registered with a master |
MAX_MODBUS_RW_OPS_PER_REQUEST |
UDINT |
100 |
Maximum operations per request |
MODBUS_TIMEOUT |
TIME |
T#100MS |
Modbus-RTU communications timeout period |