Weiterführende Beispiele

Die folgenden Beispiele zeigen verschiedene Anwendungsarten des TC3 XML Servers. Das SPS-Projekt, das die Beispiele enthält, können Sie hier herunterladen: TC3_XmlSrv_Samples.zip

Beispiel 5 zeigt eine einmalige Initialisierung bei Programmstart, Beispiel 6 zyklische und ereignisgesteuerte Schreibvorgänge. Beide Beispiele arbeiten mit der schon aus den Beispielen 1-4 bekannten Struktur ST_MYSTRUCT, die wiederum die Struktur ST_INNTERSTRUCT enthält. Die beiden Strukturen sind im Folgenden dargestellt:

Die Strukturen

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: Einmalige Initalisierung bei Programmstart

Sample 5 zeigt die einmalige Initialisierung von value1 bei Programmstart. Zum Einsatz kommt der Funktionsbaustein FB_XmlSrvRead.

(* 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: Zyklisches und ereignisgesteuertes Schreiben

Das folgende Beispiel erzeugt alle 20 Sekunden eine neue XML-Datei und beschreibt diese mit der bekannten Struktur. Der Dateiname wird immer aus dem aktuellen Windows-Datum, der -Uhrzeit und einem String generiert. Außerdem kann der Schreibprozess durch Drücken eines Schalters (bzw. Setzen der Schaltervariable bButton) gestartet werden. Sollte der Schreibprozess in einer Sekunde mehrfach ausgelöst werden, wird die aktuelle Datei überschrieben.

(* 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) *)


      (*change value 1*)
      value1.stInner.sString := sFilePathWrite;
      value1.stInner.nInteger := stMyTimestruct.wSecond;

      (* write *)
      fbXmlSrvWrite(sFilePath:=sFilePathWrite, sXPath:=sXPathWrite, bExecute:= TRUE);

   ELSIF fbXmlSrvWrite.bError THEN
      iState:= 100;
   END_IF

   (* reset fbXmlSrvWrite *)
   IF fbXmlSrvWrite.bBusy AND NOT tGetTime.ERR THEN
      fbXmlSrvWrite(bExecute:= FALSE);
   ELSIF ntGetTime.ERR THEN
      iState:= 100;
   END_IF
 
100: (* error state*) 
 ;

END_CASE

Voraussetzungen

Entwicklungsumgebung

Zielplattform

Einzubindende SPS Bibliotheken

TwinCAT v3.1 Build 4011

PC oder CX (x86, x64, ARM)

Tc2_XmlDataSrv