Using IO-Link Terminal 750-1657 with PFC200

Hello.

I am programming a 750-8212 with several classic I/O terminals using CODESYS 3.5, and so far this works fine.

Now I wanted to connect a flow meter via IO-Link to read out the totalizer. For this, I purchased a 750-1657.

I downloaded IO-Check, used it to identify the IO-Link master on the PLC, and configured it with the IODD file. There, I can immediately see the sensor’s process data.

In CODESYS, I can add the 1657 to the K-Bus (but only by selecting the byte length); however, it then remains completely non-functional and empty—no I/O image is present, and I see no payload data. I can load the IODD file into CODESYS via the device repository, but I don’t know how to get it into the device tree. No matter where I try, the IO-Link device does not appear when I select “Attach Device.”

Which crucial step am I missing here?

Attached are two CODESYS sample projects and an application note from WAGO’s Download Center under the Learning Materials link.

a2019002_en__CDS3_WagoAppIOLink.pdf (519.6 KB)

WagoAppIOLink_Example_02.project (843.7 KB)

WagoAppIOLink_Example_01.project (1014.9 KB)

Thank you for your reply, John!

I managed to solve the issue with the help of the example projects.

It took me the whole weekend but now I have the live data in form of a bytes array that I can split and build some REAL values from them so I have the data I need. I hoped this would be a bit more comfortable but it works.

Hello!

Could you maybe post your solution? I managed to run into the same problem, using 1657 card to read out flow meters :slight_smile:

Thx in advance,

Hello.
I am happy to post my code here.
Of course, as always, with the note that this is my first CODESYS project and that there is certainly a better way to do it. But it works.

I have split it into two files, one FB_Picomag for the flow meter. Naturally, this is a Picomag from Endress+Hauser.

FUNCTION_BLOCK FB_Picomag EXTENDS FbIOL_Base
VAR_IN_OUT
	xResetTotalizer: BOOL;
END_VAR
VAR_OUTPUT
	rConductivity: REAL;
	rFlow: REAL;
	rTotalizer: REAL;
	rTemperature: REAL;
	xIOLinkOK: BOOL;
END_VAR
VAR
	RTrigReset: R_TRIG;
	bytesConv: U_BytesToReal;
	bResetWritten: BYTE;
END_VAR
SUPER^();

IF THIS^.Prop_xInDataValid THEN
	// Conductivity
	bytesConv.abBytes[3] := aDeviceInData[0];
	bytesConv.abBytes[2] := aDeviceInData[1];
	bytesConv.abBytes[1] := aDeviceInData[2];
	bytesConv.abBytes[0] := aDeviceInData[3];
	rConductivity := bytesConv.rValue;

	// Flow
	bytesConv.abBytes[3] := aDeviceInData[8];
	bytesConv.abBytes[2] := aDeviceInData[9];
	bytesConv.abBytes[1] := aDeviceInData[10];
	bytesConv.abBytes[0] := aDeviceInData[11];
	// Scaling by 60, as we apparently receive the value as liters/s.
	rFlow := bytesConv.rValue * 60.0;

	// Totalizer
	bytesConv.abBytes[3] := aDeviceInData[4];
	bytesConv.abBytes[2] := aDeviceInData[5];
	bytesConv.abBytes[1] := aDeviceInData[6];
	bytesConv.abBytes[0] := aDeviceInData[7];
	rTotalizer := bytesConv.rValue;
	
	// Temperature
	rTemperature := (INT_TO_REAL(aDeviceInData[12]) * 256.0 + INT_TO_REAL(aDeviceInData[13])) / 10.0;

	xIOLinkOK := TRUE;
	
	RTrigReset(CLK := xResetTotalizer);
	IF RTrigReset.Q THEN
		THIS^.IOL_Call_WriteWord(wIOL_Index := 362, bIOL_Subindex := 0, wValue := 1, bLen => bResetWritten);
		xResetTotalizer := FALSE;
	END_IF

	
ELSE
	xIOLinkOK := FALSE;
	
END_IF

Running as a separate task is this main program PRG_IOLink:

PROGRAM PRG_IOLink
VAR
xExecuteMain: BOOL := TRUE;
xDoneConfig: BOOL;
xBusyConfig: BOOL;
xErrorConfig: BOOL;
oStatusConfig: FbResult;
aPort: ARRAY [1..4] OF typIOLinkPortConfigBasic;
aIOLPort: ARRAY[1..4] OF typIOL_Device;
aIOLDevice: ARRAY [1..4] OF typIOLinkDeviceInfo;
xEnableDiagnosis: BOOL := TRUE;
xResetDiag: BOOL;
aDiagBuffer: ARRAY[0..IOL_DIAG_BUFFER] OF typDiag;
aDiagTimeBuffer: ARRAY[0..IOL_DIAG_BUFFER] OF DATE_AND_TIME;

IOL_Config_1657: WagoAppIOLink.FbIOL_MasterConfiguration_1657;
currentDT: DATE_AND_TIME;
RTCResult: RTS_IEC_RESULT;
xDiagResult: BOOL;
n : INT;
emptyPipeDetected: BOOL;

// Picomag
PicomagAnPort1: FbIOL_PortData;
PicoMagObj: FB_Picomag;
bytesConv: U_BytesToReal;
pOutBuffer: ARRAY[0..2] OF BYTE;
pInBuffer: ARRAY[0..14] OF BYTE;


xTxTriggerPicomag: BOOL := FALSE;
xCommResetPicomag: BOOL:= FALSE;
xValidPicomag: BOOL;
xBusyPicomag : BOOL;
xErrorPicomag: BOOL;
udiRxBytesPicomag: UDINT;
bRefreshCounterPicomag: BYTE;
oStatusPicomag: FbResult;
xInit: BOOL := FALSE;

END_VAR

IF NOT xInit THEN
	xInit := TRUE;
	// At the start of the controller, we assume a full pipe. 
	// After all, "EMPTY PIPE" is an error that is reported to us or not.
	GVL_IO.Filterpumpe_LeitungVoll := TRUE;
END_IF

aPort[1].bRXSize := 15;
aPort[1].eIOL_PortMode := eIOL_PortMode.IOL_Sensor;
aPort[1].xFragmented := FALSE;

aPort[2].eIOL_PortMode := eIOL_PortMode.Deactivated;
aPort[3].eIOL_PortMode := eIOL_PortMode.Deactivated;
aPort[4].eIOL_PortMode := eIOL_PortMode.Deactivated;


currentDT := UDINT_TO_DT(SysTimeRtcGet(pResult := RTCResult));

IOL_Config_1657(
	xEnable := xExecuteMain,
	I_Port := IoConfig_Globals._750_1657_24,
	eModeStartUp := eMasterConfigModeStartUp.AutoConfig,
	aPort := aPort,
	xDone => xDoneConfig,
	xBusy => xBusyConfig,
	xError => xErrorConfig,
	oStatus => oStatusConfig,
	aIOL_Port => aIOLPort,
	aIOL_DeviceInfo => aIOLDevice,
	dtTime := currentDT,
);


xDiagResult := IOL_Config_1657.GetDiagnosisBuffer(
	xEnable := xEnableDiagnosis,
	xReset := xResetDiag,
	aDiagBuffer := aDiagBuffer,
	aDiagTimeBuffer := aDiagTimeBuffer);

emptyPipeDetected := FALSE;
FOR n := 0 TO IOL_DIAG_BUFFER DO
	IF NOT emptyPipeDetected AND aDiagBuffer[n].EventCode = 6158 THEN
		emptyPipeDetected := TRUE;
		IF aDiagBuffer[n].DiagQualifier.DiagMode = eDiagQualMode.MBX_DiagAppears THEN
			GVL_IO.Filterpumpe_LeitungVoll := FALSE;
		ELSE
			GVL_IO.Filterpumpe_LeitungVoll := TRUE;
		END_IF
		xResetDiag := TRUE;		
	END_IF
END_FOR


PicoMagObj(
	typIOL_Sensor := aIOLPort[1],
	typIOLinkDeviceInfo := aIOLDevice[1],
	oStatus => oStatusPicomag,
	xError => xErrorPicomag,
	xResetTotalizer := GVL_IO.Filterpumpe_ZaehlerReset_Ausgang,
	);
	

GVL_IO.Filterpumpe_Conductivity := PicoMagObj.rConductivity;
GVL_IO.Filterpumpe_Flow := PicoMagObj.rFlow;
GVL_IO.Filterpumpe_Totalizer := PicoMagObj.rTotalizer;
GVL_IO.Filterpumpe_Temperature := PicoMagObj.rTemperature;
GVL_IO.Filterpumpe_IOLinkOK := PicoMagObj.xIOLinkOK;

A special feature is that the “Empty Pipe” message does not come from the device itself but from the IO-Link diagnosis buffer. For example, the LED on the terminal also lights up red as soon as the Picomag reports an Empty Pipe.

Thank you very much, I plan to use the same Flowmeters, just 4 of them, this will help me a lot!