Modbus RTU := eCockpit PFC100 (750-8100) + 750-652

I need to interview two Modbus RTU devices (drink + reading).
I ran into a problem that there is no example with a record and reading.
I use the library WagoApplCmodbus.
Now I have a decision with four FB. Can you do through one FB?
I can write the code below, if necessary.

No, unfortunately with RTU you will need to cycle through the four slaves in a state machine in one Function Block.

The way I have done it is with a case statement, and reconfigure the function block between messages. Something like this…

CASE state OF
    0: // Reconfigure Modbus master
         fBModbusMaster.id := 3;                  // Update the Modbus ID
         fBModbusMaster.xTrigger := TRUE;          // Re-enable the function block
         state := 1;

    1:  IF NOT fBModbusMaster.xTrigger THEN
            state := 2;
        END_IF
 
    2:  fBModbusMaster.id := 4;                  // Update the Modbus ID
            fBModbusMaster.xTrigger := TRUE;          // Re-enable the function block
            state := 3;

    3: IF NOT fBModbusMaster.xTrigger THEN
          state := 0;
       END_IF

END_CASE;

That’s about what I thought. Can we use one FB modbus or do we need each one for its own function (read/write) ?

Is this how it’s gonna work? Where do I change the utQuery parameters? If I understand correctly only this parameter is responsible for the address and function when polling.

PROGRAM prgMB_Master
VAR
	fbMasterSerial_MB	: WagoAppPlcModbus.FbMbMasterSerial;
	xConnect			: BOOL :=FALSE;
	xIsConnected		: BOOL;
	xError				: BOOL;
	oStatus				: WagoAppPlcModbus.WagoSysErrorBase.FbResult;
	utQuery				: typMbQuery := (bUnitId := 2, bFunctionCode := 16#10, uiReadAddress := 0, uiReadQuantity := 0, uiWriteAddress := 512, uiWriteQuantity := 7);
	xTrigger			: BOOL;
	utResponse			: typMbResponse;
	tTimeOut			: TIME := T#300MS;
	tQueryTime			: TIME := T#200MS;
	
	utQuery_1			: typMbQuery := (bUnitId := 2, bFunctionCode := 16#03, uiReadAddress := 525, uiReadQuantity := 8, uiWriteAddress := 0, uiWriteQuantity := 0);
	utQuery_2			: typMbQuery := (bUnitId := 3, bFunctionCode := 16#10, uiReadAddress := 0, uiReadQuantity := 0, uiWriteAddress := 512, uiWriteQuantity := 7);
	utQuery_3			: typMbQuery := (bUnitId := 3, bFunctionCode := 16#03, uiReadAddress := 525, uiReadQuantity := 8, uiWriteAddress := 0, uiWriteQuantity := 0);
END_VAR	
	

fbMasterSerial_MB(
	I_Port		:= IoConfig_Globals.COM1, 
	udiBaudrate	:= 19200 , 
	usiDataBits	:= 8, 
	eParity		:= eTTYParity.None, 
	eStopBits	:= eTTYStopBits.One , 
	eHandshake	:= eTTYHandshake.None , 
	ePhysical	:= eTTYPhysicalLayer.RS485_HalfDuplex, 
	//xIsConnected=> xIsConnected , 
	//xError		=> xError, 
	//oStatus		=> oStatus , 
	eFrameType	:= eMbFrameType.RTU , 
	tTimeOut	:= tTimeOut , 
	//utQuery		:= utQuery,
	//xTrigger	:= xTrigger ,
	//utResponse	:= utResponse );
	
CASE state OF
0:
	fbMasterSerial_MB(
	xConnect	:= FALSE , 
	utQuery		:= utQuery,
	xTrigger	:= xTrigger ,
	utResponse	:= utResponse );

fbMasterSerial_MB.xIsConnected;
fbMasterSerial_MB.xError;
fbMasterSerial_MB.oStatus;
state := 1;

1:
	fbMasterSerial_MB(
	xConnect	:= TRUE , 
	utQuery		:= utQuery,
	xTrigger	:= xTrigger ,
	utResponse	:= utResponse );

IF fbMasterSerial_MB.xIsConnected = TRUE THEN
	xTrigger := TRUE;
	state := 2;
END_IF

IF fbMasterSerial_MB.xError = TRUE THEN
	state := 0;
END_IF

2:
utQuery.awWriteData[0] := BOOL_TO_WORD( Modbus[1]);
utQuery.awWriteData[1] := BOOL_TO_WORD( Modbus[2]);

fbMasterSerial_MB(
	xConnect	:= TRUE , 
	utQuery		:= utQuery,
	xTrigger	:= xTrigger ,
	utResponse	:= utResponse );

IF fbMasterSerial_MB.oStatus.sDescription = 'OK' THEN
	state := 3;
END_IF

IF fbMasterSerial_MB.oStatus.sDescription = 'Error time out' THEN
	state := 0;
END_IF

3:
	fbMasterSerial_MB(
	xConnect	:= FALSE , 
	utQuery		:= utQuery,
	xTrigger	:= xTrigger ,
	utResponse	:= utResponse );

state := 4;

4:
fbMasterSerial_MB(
	xConnect	:= TRUE , 
	utQuery		:= utQuery_1,
	xTrigger	:= xTrigger ,
	utResponse	:= utResponse );

IF fbMasterSerial_MB.xIsConnected = TRUE THEN
	xTrigger := TRUE;
	state := 5;
END_IF

IF fbMasterSerial_MB.xError = TRUE THEN
	state := 0;
END_IF

5:
NEXT.....

I had the same issue. Digital Twins worked the best for me:

FUNCTION_BLOCK FbSpecialSlave EXTENDS FbDigitalTwinMbSlaveDevice
VAR_INPUT
	bUnitId					: BYTE := 1;
	tScanRate				: TIME := T#200MS;
END_VAR
VAR_OUTPUT
	xError					: BOOL;
	sInfo					: STRING;
	wValue1					: WORD;
	wValue2					: WORD;
	wValue3					: WORD;
END_VAR

VAR
	xTrigger				: BOOL;
	m_FbQuery_0				: WagoAppPLCModbus.FbQuery(THIS^);
	m_FbQuery_1				: WagoAppPLCModbus.FbQuery(THIS^);
	m_FbQuery_2				: WagoAppPLCModbus.FbQuery(THIS^);
	wState					: WORD;
	oDelay					: TON;
END_VAR


CASE wState OF
0:
	IF IMbMasterMultiQuery = 0 THEN
		RETURN;
	ELSIF NOT IMbMasterMultiQuery.xConnected THEN
		RETURN;
	ELSE
		wState := 10;
	END_IF
10:
	oDelay(
		IN		:= TRUE,
		PT		:= tScanRate );
	IF oDelay.Q THEN
		oDelay(
			IN	:= FALSE );
		m_FbQuery_0.bUnitId := bUnitId;
		m_FbQuery_0.bFunctionCode := 3;
		m_FbQuery_0.uiReadAddress := 0;
		m_FbQuery_0.uiReadQuantity := 1;
		protAttachMbQuery(m_FbQuery_0);
		
		m_FbQuery_1.bUnitId := bUnitId;
		m_FbQuery_1.bFunctionCode := 3;
		m_FbQuery_1.uiReadAddress := 1;
		m_FbQuery_1.uiReadQuantity := 1;
		protAttachMbQuery(m_FbQuery_1);
		
		m_FbQuery_2.bUnitId := bUnitId;
		m_FbQuery_2.bFunctionCode := 3;
		m_FbQuery_2.uiReadAddress := 2;
		m_FbQuery_2.uiReadQuantity := 1;
		protAttachMbQuery(m_FbQuery_2);
	END_IF
END_CASE

This FB has two methods
METH: onError

(*
	after each request with errors is method called
*)
METHOD onError : bool
VAR_INPUT
	IQuery		:	I_Query;
	utResponse	:	typMbResponse;
	oStatus		:	WagoSysErrorBase.FbResult;
END_VAR

xError := TRUE;
sInfo := oStatus.GetDescription();

METH onResponse:

METHOD onResponse : BOOL
VAR_INPUT
	IQuery		:	I_Query;
	utResponse	:	typMbResponse;
END_VAR

xError := FALSE;
sInfo := 'OK';

IF IQuery = m_FbQuery_0.IQuery THEN
	wValue1 := utResponse.awData[0];
ELSIF
	IQuery = m_FbQuery_1.IQuery THEN
	wValue2 := utResponse.awData[0];
ELSIF
	IQuery = m_FbQuery_2.IQuery THEN
	wValue3 := utResponse.awData[0];
END_IF

No use the FbMbMasterMultiQuerySerial as your Master. connect the IMbMasterMultiQuery from your master to the Slave Devices. I_Port ist the 750-652 Card.

I hope this helps.

Cheers

2 Likes