Further Samples

The following samples show different types of application of the TwinCAT XML Data Servers. The PLC-project, which contains the samples, can be downloaded here.

Sample 5 shows an initialization once at program startup, Sample 6 shows cyclic and event-driven printing procedures. Both samples again use the structure ST_MYSTRUCT, which in turn includes ST_INNTERSTRUCT. Both Structures are shown in the following:

Structures

TYPE ST_MYSTRUCT:
STRUCT
   fReal       : REAL;
   bBool       : ARRAY [0..2] OF BOOL;
   stInner     : ST_INNTERSTRUCT;
END_STRUCT
END_TYPE
TYPE ST_INNTERSTRUCT:
STRUCT
  nInteger     : INT;
  sString      : STRING;
END_STRUCT
END_TYPE

Sample 5: Initialization once at program startup

Sample 5 shows the initialization of value1 once at program startup. Therefore FB_XmlSrvRead is used.

(* Sample5 reads and initializes value1 when the PLC is started FUNCTIONBLOCK: FB_XmlSrvRead *)
PROGRAM Sample5
VAR
   value1        : ST_MyStruct;
   fbXmlSrvRead  : FB_XmlSrvRead;
   bExecute      : BOOL;
   sFilePath     : T_MaxString := 'C:\Test.xml'; (* CE: '\Hard Disk\Test.xml' *)
   sXPath        : T_MaxString := '/dataentry/MAIN.value1';
   nState        : INT := 0;
END_VAR
CASE nState OF
0: (* initialize *)
   fbXmlSrvRead(
   pSymAddr  := ADR(value1),
   cbSymSize := SIZEOF(value1), 
   sFilePath := sFilePath,
   sXPath    := sXPath,
   bExecute  := bExecute
   );
   fbXmlSrvRead(bExecute:= TRUE); 
   nState:= 1; 

1: (* wait for read operation *)
   fbXmlSrvRead(bExecute:= FALSE);
   IF NOT fbXmlSrvRead.bBusy AND NOT fbXmlSrvRead.bError THEN
     nState:= 2; 
   ELSIF fbXmlSrvRead.bError THEN
     nState:= 100;
   END_IF

2: (* operations *)
   ;

100:(* errorState *)
   ;

END_CASE

Sample 6: Cyclic and event-driven printing

The following sample creates a new XML file every 20 seconds and writes the above-mentioned structure to it. The filename is made up of the current windows-date, -time and the string sFileName. Furthermore, the printing procedure can be started by pressing a button (or setting the respective variable bButton). If the printing procedure is triggered twice a second, the latest file will be overwritten.

(* Sample6: Every 20s value1 will be written into a new XML-File named after the current date and 
   time. Furthermore you can activate the printing procedure by pressing a button (or setting the 
   corresponding variable *)
PROGRAM Sample6
VAR
   value1            : ST_MyStruct;
   fbXmlSrvWrite     : FB_XmlSrvWrite;
   
   sFileFolder       : T_MaxString :='C:\'; (* CE: '\Hard Disk\' *)
   sFileName         : T_MaxString:= '_test.xml';
   sFilePathWrite    : T_MaxString
   (*sFilePathWrite = sFileFolder + time + sFileName*)
   
   sXPathWrite       : T_MaxString :='/dataentry/MAIN.value1';
   ntGetTime         : NT_GetTime;
   stMyTimestruct    : TIMESTRUCT;
   iState            : INT := 1;
   bTwentySec        : BOOL:= FALSE;
   bButton           : BOOL:= FALSE;
   bTwentySecOver    : BOOL;
   triggerWrite      : R_TRIG;
   triggerButton     : R_TRIG;
END_VAR
triggerButton(CLK:= bButton);

CASE iState OF
0: (* idle state *)
   ;

1: (* initialize *)
   fbXmlSrvWrite(nMode:=XMLSRV_ADDMISSING, pSymAddr:= ADR(value1),
     cbSymSize:= SIZEOF(value1));
   ntGetTime(START:= TRUE, TIMESTR=>stMyTimestruct);  (* get Windows time *)IF NOT ntGetTime.BUSY AND NOT ntGetTime.ERR THEN
     iState:= 2;
   ELSIF ntGetTime.ERR THEN
     iState:= 100;
   END_IF
   
2: (* working state *)
   (* change some values - replace with production-process *)
   value1.stInner.nInteger:= value1.stInner.nInteger + 1;
   IF value1.stInner.nInteger = 32767 THEN
     value1.stInner.nInteger:= 0;
   END_IF(* get Windows time *)
   ntGetTime(START:= FALSE);
   IF NOT ntGetTime.BUSY AND NOT ntGetTime.ERR THEN
     ntGetTime(START:= TRUE, TIMESTR=>stMyTimestruct);
   ELSIF ntGetTime.ERR THEN
     iState:= 100;
   END_IF(* check if 20s have passed*)IF stMyTimestruct.wSecond = 0  OR stMyTimestruct.wSecond = 20  OR stMyTimeStruct.wSecond = 40  THEN
     bTwentySecOver:= TRUE;
   ELSE
     bTwentySecOver:= FALSE;
   END_IF(* if 20s have passed => trigger writing-process *)
   triggerWrite(CLK:=bTwentySecOver);
   IF (triggerWrite.Q OR triggerButton.Q) AND NOT fbXmlSrvWrite.bBusy
                      AND NOT fbXmlSrvWrite.bError THEN (* create filename *)
     sFilePathWrite:= CONCAT(sFileFolder, SYSTEMTIME_TO_STRING(stMyTimestruct)); (* set folder + time *)
     sFilePathWrite:= DELETE(STR:= sFilePathWrite, LEN:= 4 , 
                 POS:= LEN(STR:=sFilePathWrite)-3); (* delete milliseconds *)
     sFilePathWrite:= REPLACE(STR1:= sFilePathWrite , STR2:= '.' , L:= 1, 
                  P:= LEN(STR:=sFilePathWrite)-2); (* replace colon with point *)
     sFilePathWrite:= REPLACE(STR1:= sFilePathWrite , STR2:= '.' , L:= 1, 
                  P:= LEN(STR:=sFilePathWrite)-5); (* replace colon with point *)
     sFilePathWrite:= CONCAT(sFilePathWrite, sFileName);  (* add filename (default: test) *)(* write *)
     fbXmlSrvWrite(sFilePath:=sFilePathWrite, sXPath:=sXPathWrite, bExecute:= TRUE);
   ELSIF fbXmlSrvWrite.bError THEN
     iState:= 100;
   END_IF(* reset fbXmlSrvWrite *)IF fbXmlSrvWrite.bBusy AND NOT ntGetTime.ERR THEN
     fbXmlSrvWrite(bExecute:= FALSE);
   ELSIF ntGetTime.ERR THEN
     iState:= 100;
   END_IF
   
100: (* error state*) 
   ;

END_CASE

Requirements

Entwicklungsumgebung

Zielplattform

Einzubindende SPS Bibliotheken

TwinCAT v2.10.0

PC or CX (x86, ARM)

TcXmlDataSrv.Lib