# Datei erzeugen und Variablen in Excel



## dennish23 (28 September 2008)

Hallo liebe Forumgemeinde

Ich habe ein Problem mit der Dateierstellung und Variablen abspeicherung bei einem MFD4 von Klöckner und Möller.

Das Panel läuft als Master System in meinem SPS-Kreis. Es bekommt von allen angeschlossenen SPS die nötigen Informationen die jetzt noch auf der MMC Karte in einer Datei abgespeichert werden sollen. Wenn möglich in einer vorgefertigten Excel Tabelle.

Jetzt die Fragen wie ich 

a.) die Datei anlege mit hilfe einer von mir vorgestellten einteilung (1.Spalte=Position, 2.Spalte=Datum, 3.Spalte=Uhrzeit, 4.Spalte= welche SPS, 5.Spalte=welchen Wert)

b.) die werte die von den SPS kommen auf das Panel dann in die jeweiligen Spalten eintragen lasse und abspeicher

Vielleicht kann mir jemand helfen oder hat vielleicht schon ein Programm Model für mich.

Vielen Dank im voraus für euer Hilfe.

MFG Dennis


----------



## zotos (28 September 2008)

Aus der SPS heraus eine Excel Tabel zu erstellen oder auch nur zu füllen ist eher umständlich.

Ich würde einfach eine csv Datei ertstellen die kann man leicht erstellen und auch leicht in Excel oder auch anderen Programmen einlesen.


----------



## dennish23 (28 September 2008)

Danke Zotos aber hättest du ein Bsp. wie ich eine CSV-Datei erstellen kann mit meinen Variablen? Zur zeit benutze ich nur BOOL-Variablen und die Date and Time Variable.


----------



## zotos (28 September 2008)

Ich schreib Dir jetzt nicht Dein Programm auch wenn die Aufgabe nicht so schwer ist.

Ich habe gerade mal nachgelesen das MFD4 bietet die SysLibFile.lib an.

Schau Dir das mal in der Online Hilfe unter SysFile an.

In folgendem PDF findest Du einen Verweis auf diese Lib: ftp://ftp.moeller.net/DOCUMENTATION/AWB_MANUALS/h1594d.pdf


----------



## dennish23 (28 September 2008)

Zotos ich habe ja ein prog was mir die Datei anlegt aber nicht die den Wert übernimmt. Ich lege es hier mal mit ab. Vielleicht hast ja ne Idee woran es liegt.

MFG Dennis


IF bOnce THEN
    hFile:= SysFileOpen(szFilePath, 'w');
    FOR iCounter2:= 1 TO 5 DO
        FOR iCounter1:= 1 TO 5 DO
            szCurrent:= CONCAT(INT_TO_STRING(iCounter2), INT_TO_STRING(iCounter1));
            dwWritten:= SysFileWrite(hFile, ADR(szCurrent), 2);
            IF iCounter1 <> 5 THEN
                dwWritten:= SysFileWrite(hFile, ADR(szSeperator), 1);
            ELSE
                dwWritten:= SysFileWrite(hFile, ADR(wNewLine), SIZEOF(wNewLine));
            END_IF
        END_FOR
    END_FOR
    SysFileClose(hFile);
    bOnce:= FALSE;
END_IF


----------



## zotos (28 September 2008)

dennish23 schrieb:


> Zotos ich habe ja ein prog was mir die Datei anlegt aber nicht die den Wert übernimmt. Ich lege es hier mal mit ab. Vielleicht hast ja ne Idee woran es liegt.
> 
> MFG Dennis
> 
> ...


So kommen wir der Sache schon mal näher.

Ich habe mir Deinen Code angeschaut.
Du benutzt bei dem SysFileWrite zweimal feste Werte für die Länge und einmal SIZEOF.

--> Beide Varianten sind bei Strings ungeeignet. Bitte beide gegen LEN() ersetzen.

Dann schreibst Du 5 Zeilen mit je 5 Spalten aber immer nur am Ende der Zeile schreibst Du den Wert (wenn ich wNewLine richtig gedeutet habe).

Also nach kleinen Änderungen sieht bei mir das Ergebnis so aus:

```
11;12;13;14;15test 
21;22;23;24;25test 
31;32;33;34;35test 
41;42;43;44;45test 
51;52;53;54;55test
```
Also da ist noch nichts von:


dennish23 schrieb:


> ...
> a.) die Datei anlege mit hilfe einer von mir vorgestellten einteilung (1.Spalte=Position, 2.Spalte=Datum, 3.Spalte=Uhrzeit, 4.Spalte= welche SPS, 5.Spalte=welchen Wert)
> ...


zusehen. Bei Uhrzeit und Datum könnte ich Dir noch auf die Sprünge helfen (aber heute nicht mehr). Die anderen Informationen solltest Du  beisteuern.


Nun zu dem von mir geänderten Code (ich habe recht wenig geändert):

```
VAR
    bOnce: BOOL;
    hFile: DWORD;
    szFilePath: STRING := 'C:\text.txt'; (* Ich nutze die CoDeSysRTE und habe daher ein Dateisystem ala Windows *)
    iCounter1: INT;
    iCounter2: INT;
    szCurrent: STRING;
    dwWritten: DWORD;
    szSeperator: STRING := ';';
    wNewLine: STRING:='test $R$N'; (*Symbolisiert den Wert. Das $R$N erzeugt einen Zeilenumbruch muss später via CONCAT rein*)
END_VAR
```


```
IF bOnce THEN
    hFile:= SysFileOpen(szFilePath, 'w');
    FOR iCounter2:= 1 TO 5 DO
        FOR iCounter1:= 1 TO 5 DO
            szCurrent:= CONCAT(INT_TO_STRING(iCounter2), INT_TO_STRING(iCounter1));
            dwWritten:= SysFileWrite(hFile, ADR(szCurrent), LEN(szCurrent));
            IF iCounter1 <> 5 THEN
                dwWritten:= SysFileWrite(hFile, ADR(szSeperator), LEN(szSeperator));
            ELSE
                dwWritten:= SysFileWrite(hFile, ADR(wNewLine), LEN(wNewLine));
            END_IF
        END_FOR
    END_FOR
    SysFileClose(hFile);
    bOnce:= FALSE;
END_IF
```


----------



## dennish23 (29 September 2008)

Danke dir erstmal Zotos. Ich habe versucht dein Program nachzuvollziehen aber irgendwie verläßt mich mein Wissen. Ich versuche dir mal meinen gedankengang zu erklären.

Deklaration

PROGRAM PLC_PRG
VAR
    eingang1: BOOL;
    hFile: DWORD := 0;
    szFilePath: STRING := 'disk_mmc\TestDat.csv ';
    WriteBuffer : ARRAY[0..1] OF BYTE:=0,1;
    DwWritten: DWORD;
END_VAR


Programm

eingang1;  (*Variablenbedingung für das schreiben/erstellen einer Datei*)

IF eingang1 THEN    (*Bedingungsabfrage*)
hFile:= SysFileOpen(szFilePath, 'w'); (*wenn Bedingung erfüllt soll er eine Datei erstellen*)
SysFileClose(hFile);    (*Datei soll geschlossen werden*)
END_IF


----------



## dennish23 (29 September 2008)

Danke dir erstmal Zotos. Ich habe versucht dein Program nachzuvollziehen aber irgendwie verläßt mich mein Wissen. Ich versuche dir mal meinen gedankengang zu erklären.

Deklaration

PROGRAM PLC_PRG
VAR
    eingang1: BOOL;
    hFile: DWORD := 0;
    szFilePath: STRING := 'disk_mmc\TestDat.csv ';
    WriteBuffer : ARRAY[0..1] OF BYTE:=0,1;
    DwWritten: DWORD;
END_VAR


Programm

eingang1;  (*Variablenbedingung für das schreiben/erstellen einer Datei*)

IF eingang1 THEN    (*Bedingungsabfrage*)
hFile:= SysFileOpen(szFilePath, 'w'); (*wenn Bedingung erfüllt soll er eine Datei erstellen*)
SysFileClose(hFile);    (*Datei soll geschlossen werden*)
END_IF

jetzt muss ich ja noch die Informationen haben die ich schreiben möchte in die Datei also muss ich ja den Befehl:

 dwWritten:= SysFileWrite(hFile, ADR(szSeperator), LEN(szSeperator));
einbinden. Und wo genau sagen ich ihm jetzt das er True schreiben soll für die Variable eingang1 in der 5.ten Spalte?

Sorry wenn ich mich wie ein Änfänger aufführe, aber das ist mir alles einfach zu hoch.

MFG Dennis


----------



## zotos (29 September 2008)

dennish23 schrieb:


> Zotos ich habe ja ein prog was mir die Datei anlegt aber nicht die den Wert übernimmt.
> ...



In meiner grenzenlosen Naivität dachte ich das Programm wäre von Dir und Du würdest Dich wundern warum es nicht geht.

Also fangen wir noch mal von vorne an.


dennish23 schrieb:


> ...
> a.) die Datei anlege mit hilfe einer von mir vorgestellten einteilung (1.Spalte=Position, 2.Spalte=Datum, 3.Spalte=Uhrzeit, 4.Spalte= welche SPS, 5.Spalte=welchen Wert)
> ...


Was für eine Position ist in Spalte 1 gemeint? Ist das Datum in Spalte 2 und 3 eins das von außen vorgegeben wird oder einfach das beim Schreiben in die Datei? Wo kommen die Informationen von Spalte 4 und 5 her?

Wann willst Du was in die Datei schreiben? immer nur eine Zeile oder immer eine weitere anfügen?

Jetzt lass Dich mal richtig aus und beschreibe was Du machen willst.


----------



## dennish23 (29 September 2008)

Also ich habe 3 SPS die ihre Informationen an das Panel senden per Global Variablen in denen es im Moment nur um BOOL Variablen geht.

Wenn ich jetzt festlege das die SPS1 die Info schickt das Eingang1 (Termometer angeschlossen) und Eingang2 (Temperatur überschritten) beide auf True stehen dann ist dies ein Fehler und die Datei soll jetzt beschrieben werden.

das heißt:

In der ersten Spalte soll jetzt das Datum erscheinen wann der Fehler aufgetreten ist. (z.Bsp: 01.01.2008)

In der zweiten Spalte soll jetzt die Uhrzeit erscheinen wann der Fehler aufgetreten ist. (z.Bsp: 17:30:25)

In der dritten Spalte soll jetzt der Ort erscheinen von wo der Fehler kommt (z.Bsp: Client 1)

In der vierten Spalte soll jetzt die Information drinne stehen was dort falsch ist (z.Bsp: Temperatur ist über 30 Grad)

Dies soll aber jetzt nicht ständig wiederholt eingetragen werden sondern das Programm soll jetzt nur einmal diesen Fehler in die Datei schreiben und dann auf eine Änderung warten (z. Bsp: bis Eingang2 wieder FALSE wird) dann soll die Datei wieder geöffnet werden und es soll angezeigt werden das:

In der ersten Spalte soll jetzt das Datum erscheinen wann der Fehler aufgetreten ist. (z.Bsp: 01.01.2008)

In der zweiten Spalte soll jetzt die Uhrzeit erscheinen wann der Fehler aufgetreten ist. (z.Bsp: 17:30:25)

In der dritten Spalte soll jetzt der Ort erscheinen von wo der Fehler kommt (z.Bsp: SPS1)

In der vierten Spalte soll jetzt die Information drinne stehen (z.Bsp: Temperatur ist wieder im normal Bereich)


Das Problem besteht bei mir im Moment noch. Alle anderen Sachen das die Informationen gesendet werden und so funktionieren alles.

Kannst du mir jetzt helfen oder benötigst du noch mehr Informationen (z.Bsp. Das Prog für das Panel)

MFg Dennis


----------



## dennish23 (29 September 2008)

So stelle ich mir die Tabelle vor und sollte auch jeden Monat in der Grundstruktur angelegt werden. Allerdings ohne Beispiele die jetzt ja noch drin stehen.

MFG Dennis


----------



## zotos (29 September 2008)

Machen wir mal kleine Schritte:


```
VAR
  CurTimeEx       : CurTimeEx; (*Instanz des FBs um die Systemzeit zu ermittel*)
  TimeDate        : SystemTimeDate; (*Aktuelles Zeit und Datum*)
  SystemTime      : SysTime64; (**)

  NewData         : BOOL; (*Neue Daten zum schreiben*)
  NewData_old     : BOOL; (*Hilfsvariable zur Flankenerkunng*)
  FileHandel      : DWORD; (*Handel*)
  FilePath        : STRING := 'C:\text.txt'; (* Ich nutze die CoDeSysRTE und habe daher ein Dateisystem ala Windows *)
  CurrentString   : STRING; (*Temp String zum aufbauen der zu schreibenden Zeile*)
  RetValWritten   : DWORD; (*Rückgabewert der Schreibfunktion*)


  ClientName      : STRING := 'Heizung'; (*Inhalt Spalte Nr.3*)
  FehlerMeldung   : STRING := 'Temperatur zu hoch'; (*Inhalt Spalte Nr.4*)
END_VAR
```


```
(* Systemzeit ermitteln *)
CurTimeEx(TimeDate:=TimeDate, SystemTime:=SystemTime);

(* Neue Daten ? *)
IF NewData AND NOT NewData_old THEN

 (* Öffne die Datei um Daten anzufügen *)
  FileHandel:= SysFileOpen(FilePath, 'a');


  (* --Zeile zusammenbauen-- *)

  (* Spalte 1: DATUM *)
  CurrentString:= CONCAT(UINT_TO_STRING(TimeDate.Day), '.');
  CurrentString:= CONCAT(CurrentString, UINT_TO_STRING(TimeDate.Month));
  CurrentString:= CONCAT(CurrentString, '.');
  CurrentString:= CONCAT(CurrentString, UINT_TO_STRING(TimeDate.Year));
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 2: UHRZEIT *)
  CurrentString:= CONCAT(CurrentString, UINT_TO_STRING(TimeDate.Hour));
  CurrentString:= CONCAT(CurrentString, ':');
  CurrentString:= CONCAT(CurrentString, UINT_TO_STRING(TimeDate.Minute));
  CurrentString:= CONCAT(CurrentString, ':');
  CurrentString:= CONCAT(CurrentString, UINT_TO_STRING(TimeDate.Second));
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 3: NAME *)
  CurrentString:= CONCAT(CurrentString, ClientName);
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 4: MELDUNG *)
  CurrentString:= CONCAT(CurrentString, FehlerMeldung);
  CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)

  (* Zeile in die Datei schreiben *)
  RetValWritten:= SysFileWrite(FileHandel, ADR(CurrentString), LEN(CurrentString));

  (* Datei schließen *)
  SysFileClose(FileHandel);
END_IF

(* Flankenauswertung *)
NewData_old := NewData;
```


----------



## zotos (29 September 2008)

Hier noch das Ergebnis des Tests.

```
29.9.2008;20:33:30;Heizung;Temperatur zu hoch
29.9.2008;20:33:40;Heizung;Temperatur zu hoch
29.9.2008;20:33:47;Heizung;Temperatur zu hoch
```

PS: Ergänzend zum Code noch: Die CONCAT Verkettung ist nicht notwendig, man kann das ganze mit mehreren SysFileWrite hinterein lösen. Ich bin mir gerade nur nicht sicher was mehr Systemzeit braucht und habe mich jetzt einfach mal für dieses Konstrukt entschieden.


----------



## dennish23 (29 September 2008)

CurTimeEx       : CurTimeEx; (*Instanz des FBs um die Systemzeit zu ermittel*)
  TimeDate        : SystemTimeDate; (*Aktuelles Zeit und Datum*)
  SystemTime      : SysTime64; (**)


Ich bekomme hier bei alles 3 Zeilen ne Fehlermeldung.
Hängt das damit zusammen das CodesSys bei Klöckner und Möller
die SysLibRtc benutzt?

Echtzeit:=SysRtcGetTime(dummy); 	

das könnte ich doch ebenfalls benutzen für die ermittlung der
Systemzeit?

Mfg Dennis


----------



## dennish23 (29 September 2008)

PROGRAM PLC_PRG
VAR
  Echtzeit: DT;                                     (*Systemzeit komplett (z:B. DT#2006-12-06-08:53:50) imFoormat DT*)
    dummy: BOOL:=TRUE;
    Echtzeit_String: STRING;
    Jahr: INT;
    Tag: INT;
    Monat: INT;
    Stunde: INT;
    Minute: INT;
    Sekunde: INT;


  NewData         : BOOL; (*Neue Daten zum schreiben*)
  NewData_old     : BOOL; (*Hilfsvariable zur Flankenerkunng*)
  FileHandel      : DWORD; (*Handel*)
  FilePath        : STRING := 'C:\text.txt'; (* Ich nutze die CoDeSysRTE und habe daher ein Dateisystem ala Windows *)
  CurrentString   : STRING; (*Temp String zum aufbauen der zu schreibenden Zeile*)
  RetValWritten   : DWORD; (*Rückgabewert der Schreibfunktion*)


  ClientName      : STRING := 'Heizung'; (*Inhalt Spalte Nr.3*)
  FehlerMeldung   : STRING := 'Temperatur zu hoch'; (*Inhalt Spalte Nr.4*)

END_VAR



(* Systemzeit ermitteln *)

Echtzeit:=SysRtcGetTime(dummy);                 (* Echtzeit lesen*)
Echtzeit_String:=DT_TO_STRING(Echtzeit);         (*Echtzeit umwandeln in String*)
Jahr:=STRING_TO_INT(MID(Echtzeit_String,4,4));
Monat:=STRING_TO_INT(MID(Echtzeit_String,2,9));
Tag:=STRING_TO_INT(MID(Echtzeit_String,2,12));
Stunde:=STRING_TO_INT(MID(Echtzeit_String,2,15));
Minute:=STRING_TO_INT(MID(Echtzeit_String,2,18));
Sekunde:=STRING_TO_INT(MID(Echtzeit_String,2,21));


(* Neue Daten ? *)
IF NewData AND NOT NewData_old THEN

 (* Öffne die Datei um Daten anzufügen *)
  FileHandel:= SysFileOpen(FilePath, 'a');


  (* --Zeile zusammenbauen-- *)

  (* Spalte 1: DATUM *)
  CurrentString:= CONCAT(INT_TO_STRING(Tag), '.');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Monat));
  CurrentString:= CONCAT(CurrentString, '.');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Jahr));
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 2: UHRZEIT *)
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Stunde));
  CurrentString:= CONCAT(CurrentString, ':');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Minute));
  CurrentString:= CONCAT(CurrentString, ':');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Sekunde));
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 3: NAME *)
  CurrentString:= CONCAT(CurrentString, ClientName);
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 4: MELDUNG *)
  CurrentString:= CONCAT(CurrentString, FehlerMeldung);
  CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)

  (* Zeile in die Datei schreiben *)
  RetValWritten:= SysFileWrite(FileHandel, ADR(CurrentString), LEN(CurrentString));

  (* Datei schließen *)
  SysFileClose(FileHandel);
END_IF

(* Flankenauswertung *)
NewData_old := NewData;



So habe ich das jetzt geschrieben zwecks Datum/Uhrzeit ermittlung.
Hoffe das das richtig ist.

MFG Dennis


----------



## zotos (29 September 2008)

dennish23 schrieb:


> ...
> Ich bekomme hier bei alles 3 Zeilen ne Fehlermeldung.
> Hängt das damit zusammen das CodesSys bei Klöckner und Möller
> die SysLibRtc benutzt?
> ...



Oh ja das könnte sein bzw. das ist so ;o)
Ich habe nicht nachgeschaut was dieses Target zur Verfügung stellt.
Dann muss man den Code anpassen. Muss das Datum unbeding TT.MM.JJJJ sein oder kann es auch JJJJ-MM-TT sein? (zweites wäre deutlich einfacher zu realisieren).

[edit]


dennish23 schrieb:


> ...
> So habe ich das jetzt geschrieben zwecks Datum/Uhrzeit ermittlung.
> Hoffe das das richtig ist.
> 
> MFG Dennis



Auf den ersten Blick sieht es gut aus.
[/edit]


----------



## dennish23 (30 September 2008)

Vielen dank für deine Hilfe Zotos.
Das Programm funktioniert einwandfrei, nachdem ich die änderung mit der Uhrzeit geschichte gemacht habe.

Nun habe ich noch zwei Fragen.

Wie kann ich in der Datei einen Header(Überschrift) anlegen der immer nur einmal geschrieben wird (z.Bsp: Datum in der ersten Zelle; Uhrzeit in der zweiten Zelle; Ort in der dritten Zelle; Beschreibung in der vierten Zelle)?

Und wie muss ich jetzt (wahrscheinlich mit Hilfe der IF Funktion) die Programm verändern damit er monatlich eine neue Datei anlegt mit einem neuen Namen (z.Bsp Fehlermeldedatei September 2008 oder Fehlermeldedatei Oktober 2008).

Wäre sehr dankbar wenn du zu den Problemen noch eine Lösung hättest.

MFG Dennis


----------



## zotos (30 September 2008)

Ich hätte mir zwar gewünscht das Du erst selbst eine Lösung postest aber hier mal mein Vorschlag:

Neue Variablen:

```
MonatString     : ARRAY[1..12] OF STRING(10) := 'Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember';
  Monat_alt: INT := 0;
```
Neue Code stellen sind zwischen  (* NEU *) und (* /NEU *) zur Orientierung dienen die zwei alten Codestellen:

```
(* Neue Daten ? *)
IF NewData AND NOT NewData_old THEN

  (* NEU *)
  IF Monat <> Monat_alt THEN
    FilePath := '\disk_mmc\Fehlermeldedatei_';
    FilePath := CONCAT(FilePath, MonatString[Monat]);
    FilePath := CONCAT(FilePath, '_');
    FilePath := CONCAT(FilePath, INT_TO_STRING(Jahr));
    FilePath := CONCAT(FilePath, '.csv');
    Monat_alt := Monat;
  END_IF
  (* /NEU *)


  (* Öffne die Datei um Daten anzufügen *)
  FileHandel:= SysFileOpen(FilePath, 'a');

  (* NEU *)
  (* Erkennen ob es eine neue Datei ist *)
  IF SysFileGetPos(FileHandel) = 0 THEN
    (* Belibige Gesamtüberschrift *)
    CurrentString:= 'Überschrift Firmennamen oder was auch immer.';
    CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
    RetValWritten:= SysFileWrite(FileHandel, ADR(CurrentString), LEN(CurrentString));

    (* Spaltenüberschrift *)
    CurrentString:= 'Datum;Uhrzeit;Ort;Beschreibung';
    CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
    RetValWritten:= SysFileWrite(FileHandel, ADR(CurrentString), LEN(CurrentString));
  END_IF
  (* /NEU *)
```


----------



## dennish23 (30 September 2008)

Danke Zotos. Ich habe es versucht mir selbst zu erarbeiten mit Hilfe eines Vordruckes. Nur leider bin ich nach 8 Stunden noch immer zu keinem Ergebnis gekommen. Hier mal mein Versuch.

Funktionsbaustein

RisingEdgeWriteData(clk:=xStrobeWriteData);
IF RisingEdgeWriteData.q THEN
    IF( xFileOpen = FALSE) THEN
        dwFileHandle := SysFileOpen(sFileName, 'a');
        xFileOpen := TRUE;
    END_IF;

    IF xHeader THEN
        SysFileWrite(dwFileHandle, ADR( sHeader), LEN(sHeader));
    END_IF

    SysFileWrite(dwFileHandle, ADR( sDataString), LEN(sDataString));
    udiWriteCounter :=udiWriteCounter+1;
    IF sFileNameOld<>sFileName THEN
        udiWriteCounter :=1;
    END_IF
    sFileNameOld:=sFileName;
END_IF;




IF( NOT xKeepFileOpen AND xFileOpen)THEN
    xError:= SysFileClose(dwFileHandle);
        IF xError THEN
            xFileOpen := FALSE;
                   xError:=FALSE;
        END_IF;
END_IF;


PLC_PRG

(*Data logging every 5s*)
Timer(IN:=TRUE , PT:=t#5s );
xStrobeWriteData:=Timer.q;
IF Timer.q THEN
    Timer(IN:=FALSE , PT:=t#5s );
    Timer(IN:=TRUE , PT:=t#5s );
END_IF


(*Take Header if the file is new*)
RisingEdgeWriteData(clk:=xStrobeWriteData);
IF RisingEdgeWriteData.q THEN
    (*Header*)
    sHeader:='Date;Time;Info1;Info2;Data1;Data2;$N';

    (*Date and Time for file name and data*)
    S40_GetRealTimeClock1(
    Month=>usiMonth ,
    Day=>usiDay ,
    Hour=>usiHour ,
    Minute=>usiMinute ,
    Second=>usiSecond );
    uiYear:=USINT_TO_UINT(S40_GetRealTimeClock1.Year)+2000;

    (*Data String*)
    sDataString1:='';
    sDataString1:= CONCAT(sDataString1,USINT_TO_STRING(usiDay));
    sDataString1:= CONCAT(sDataString1,'.');
    sDataString1:= CONCAT(sDataString1,USINT_TO_STRING(usiMonth));
    sDataString1:= CONCAT(sDataString1,'.');
    sDataString1:= CONCAT(sDataString1,UINT_TO_STRING(uiYear));
    sDataString1:= CONCAT(sDataString1,';');
    sDataString1:= CONCAT(sDataString1,USINT_TO_STRING(usiHour));
    sDataString1:= CONCAT(sDataString1,':');
    sDataString1:= CONCAT(sDataString1,USINT_TO_STRING(usiMinute));
    sDataString1:= CONCAT(sDataString1,':');
    sDataString1:= CONCAT(sDataString1,USINT_TO_STRING(usiSecond));
    sDataString1:= CONCAT(sDataString1,';');
    sDataString1:= CONCAT(sDataString1,Info1);
    sDataString1:= CONCAT(sDataString1,';');
    sDataString1:= CONCAT(sDataString1,Info2);
    sDataString1:= CONCAT(sDataString1,';');
    sDataString1:= CONCAT(sDataString1,INT_TO_STRING(iData1));
    sDataString1:= CONCAT(sDataString1,';');
    sDataString1:= CONCAT(sDataString1,INT_TO_STRING(iData2));
    sDataString1:= CONCAT(sDataString1,'$N');


    (*Filename for data logging. Every day a new file name*)
    sDataloggingFileName:= '\DISK_MMC\' ;
    (*sDataloggingFileName:= CONCAT(sDataloggingFileName, Directory);
    sDataloggingFileName:= CONCAT(sDataloggingFileName,'\');*)
    sDataloggingFileName:= CONCAT(sDataloggingFileName, 'TestDataloggingFile');
    sDataloggingFileName:= CONCAT(sDataloggingFileName,'_');
    sDataloggingFileName:= CONCAT(sDataloggingFileName,USINT_TO_STRING(usiDay));
    sDataloggingFileName:= CONCAT(sDataloggingFileName,'-');
    sDataloggingFileName:= CONCAT(sDataloggingFileName,USINT_TO_STRING(usiMonth));
    sDataloggingFileName:= CONCAT(sDataloggingFileName,'-');
    sDataloggingFileName:= CONCAT(sDataloggingFileName,UINT_TO_STRING(uiYear));
    sDataloggingFileName:= CONCAT(sDataloggingFileName,'.csv');

    (*Header or Data*)
    xHeader:=sDataloggingFileNameOld<>sDataloggingFileName;
    sDataloggingFileNameOld:=sDataloggingFileName;
END_IF



(*Open, write and close the data logging file*)
OpenWriteCloseFile_1(
    xStrobeWriteData:=xStrobeWriteData ,
    xHeader:=xHeader,
    sHeader:=sHeader,
    sDataString:=sDataString1,
    sFileName:=sDataloggingFileName,
    xFileOpen=>xFileOpen,
    udiWriteCounter=>udiWriteCounter );

Aber das kann nicht in ein PLC geschrieben werden und er macht keine zusätzliche Freizeile rein. Das Prog läuft ohne Fehler aber die Datei wird nicht befüllt bei mir.

Vielleicht findest du ein schreibfehler oder ähnliches.

MFG Dennis


----------



## zotos (1 Oktober 2008)

dennish23 schrieb:


> Danke Zotos. Ich habe es versucht mir selbst zu erarbeiten mit Hilfe eines Vordruckes. Nur leider bin ich nach 8 Stunden noch immer zu keinem Ergebnis gekommen.
> ...



Hast Du meinen Code aus Beitrag #18 schon implementiert?


----------



## dennish23 (1 Oktober 2008)

ja habe ich gemacht aber er erzeugt die Datei nicht so wie du und ich es vielleicht gedacht haben, obwohl ich das mit eingefügt habe. Aber ich will da mal noch etwas probieren dran, um auch etwas dafür zu tun. Damit du stolz sein kannst auf mich. smilie

Bin nebenbei noch mit einem Emailversand und einer Sprachen umschaltung beschäftigt die ich ebenfalls noch mit einbinden möchte.

Bei der Emailerstellung ist halt das Problem das er keine 2 Empfänger akzeptiert. Zumindest nicht in meiner Schreibweise. Die Email kommt immer nur bei dem ersten an. Obwohl ich es so schreibe

VAR
    bSend: BOOL;
    bResult: BOOL;
    stServerName: STRING(80):= '172.16.24.187';
    szFrom: STRING(80):= 'mustermann@mustermann.de';
    szTo: STRING(80):= 'chef@mustermann.de;techniker@mustermann.de';
    szSubject: STRING(80):= 'Dies ist eine Fehlermeldung';
    szBody: STRING(255):= 'Die Temperatur der Anlage ist überschritten';
END_VAR


IF bSend THEN
    bResult:= FALSE;
    bResult:= SendMail(
        stServerName:= stServerName,
        stFrom:= szFrom,
        stTo:= szTo,
        stSubject:= szSubject,
        stBody:= szBody);
    bSend:= FALSE;
END_IF

Normalerweise kannst du ja im Email Prog wenn du mehrere Emails hast sie alle mit einem ; hintereinander schreiben. Aber das Programm setzt nicht beide Emails ab.

Und bei der Sprachenumschaltung hab ich noch eine genau Idee wie ich das hinbekommen könnte. Ich da was gelesen das du ne xml datei erzeugen musst. Allerdings weis ich noch nicht wie ich dann jeweils die Button beschriften muss. Ob %s in dem Dialogfenster Text ausreicht oder nicht. Das probiere ich am Wochenende noch ein wenig rum. Weil es für mich immer noch darum geht ich brauch ja ein Querverweis auf die XML Datei. Mal schauen.


----------



## dennish23 (1 Oktober 2008)

Zoto jetzt läuft es. Kann es aber sein das er zuviel Zeit braucht. Denn wenn ich ihm das Signal gebe und ihm es ca. 5 sekunden später wieder nehme dann sollten ja 2 Einträge in der Datei sein aber es immer nur eine. Muss ich jetzt mit einem Merker arbeiten der das im nachhinein noch reinschreibt, das er wieder geschaltet hat?

MFG Dennis


----------



## zotos (4 Oktober 2008)

dennish23 schrieb:


> Zoto jetzt läuft es. Kann es aber sein das er zuviel Zeit braucht. Denn wenn ich ihm das Signal gebe und ihm es ca. 5 sekunden später wieder nehme dann sollten ja 2 Einträge in der Datei sein aber es immer nur eine. Muss ich jetzt mit einem Merker arbeiten der das im nachhinein noch reinschreibt, das er wieder geschaltet hat?
> 
> MFG Dennis


Ja das schreiben Dateien kann je nach Plattform richtig lange dauern. Ich hatte vor kurzem Messwerte auf einer WAGO 750-841 geschrieben die in einer kurzen abfolge kamen. Dann hat das Schreiben der Datei auch zu einer "Pause" des SPS-Zyklus geführt (ich hatte so ca. 3s).

Die Lösung hat sich dann aus zwei Bestandteilen zusammen gesetzt. 

1. Nicht direkt alles schreiben sondern einen FIFO Buffer dazwischen bauen.

2. Habe ich einen Ereignisgesteuerten Task verwendet der eine geringere Priorität hatte als der bei mir Zyklische (also nicht Freilaufende) SPS Zyklus.

Ein Ereignisgesteuerter Task wird über den Flankenwechsel 0->1 einer Boolvariable gesteuert. 

hier mal die Bilder zur Einstellung der Tasks.


----------



## dennish23 (6 Oktober 2008)

Hi Zotos

Ich habe das Programm soweit fertig. Allerdings habe ich noch ein Problem welches ich ja schon versucht habe zu klären in meinem Programm aber es funktioniert nicht richtig.

Ich möchte an erster Stelle feststellen ob der Client Online ist. Das ganze versuche ich mit der xConnectionOk_client_1 Variable. Sollte der Client offline sein soll er es mir in die Datei schreiben. Jetzt ist es mittlerweile so das er es mir schreibt, aber auch schreibt er mir das das Thermometer nicht angeschlossen ist. Obwohl das ja noch nicht bekannt ist, weil der Client ja offline ist. Darüber kann ja nur eine genaue Auskunft erteielt werden in der Datei wenn der Client online ist.

Vielleicht kannst du dort mal drüber schauen wo mein Fehler ist. Ich selbst habe da das ganze Wochenende dran verbracht.

Hier die Variablen Deklaration:


PROGRAM Dateierzeugung
VAR
  FileHandel      : DWORD; (*Handel*)
  FilePath        : STRING := 'disk_mmc\'; (* Ich nutze die CoDeSysRTE und habe daher ein Dateisystem ala Windows *)
  CurrentString   : STRING; (*Temp String zum aufbauen der zu schreibenden Zeile*)
  RetValWritten   : DWORD; (*Rückgabewert der Schreibfunktion*)

  Thermo_ort      : STRING := 'SPS 1'; (*Inhalt Spalte Nr.3*)
  Thermo_ok   : STRING := 'Temperatur im grünen Bereich'; (*Inhalt Spalte Nr.4*)
  Thermo_not   : STRING := 'Thermometer nicht angeschlossen'; (*Inhalt Spalte Nr.4*)
  Temp_ueber   : STRING := 'Temperatur überschritten'; (*Inhalt Spalte Nr.4*)
  Temp_unter   : STRING := 'Temperatur unterschritten'; (*Inhalt Spalte Nr.4*)
  Netzwerk_client_1_ok   : STRING := 'Client 1 online'; (*Inhalt Spalte Nr.4*)
  Netzwerk_client_1_not   : STRING := 'Client 1 offline'; (*Inhalt Spalte Nr.4*)

  MonatString     : ARRAY[1..12] OF STRING(10) := 'Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember';
  Monat_alt: INT := 0;

  Thermometer_angeschlossen: BOOL;
  Temperatur_ueberschritten: BOOL;
  Temperatur_unterschritten: BOOL;
  DatenString   : STRING; (*Temp String zum schreiben der Zeile*)
  DatenString_old   : STRING; (*Temp String zum schreiben der Zeile*)
  xConnectionOk_client_1_old: BOOL;
END_VAR



Hier das Programm:

(*Hilfsvariablen Deklaration*)
Thermometer_angeschlossen:=eingang_client_1[4]; (*Die eingang_client_1[] sind global Variablen*)
Temperatur_ueberschritten:=eingang_client_1[2];
Temperatur_unterschritten:=eingang_client_1[1];

DatenString:='test';  (*Hier wird ein DatenString festgelegt zum Schreiben der Datei*)

IF Monat <> Monat_alt THEN  (*Hier wird der Monat für den DateiNamen festgelegt*)
    FilePath := '\disk_mmc\Fehlermeldedatei_';
    FilePath := CONCAT(FilePath, MonatString[Monat]);
    FilePath := CONCAT(FilePath, '_');
    FilePath := CONCAT(FilePath, INT_TO_STRING(Jahr));
    FilePath := CONCAT(FilePath, '.csv');
    Monat_alt := Monat;
  END_IF

 (* Öffne die Datei um Daten anzufügen *)
  FileHandel:= SysFileOpen(FilePath, 'a');

(* Erkennen ob es eine neue Datei ist *)
  IF SysFileGetPos(FileHandel) = 0 THEN
    (* Belibige Gesamtüberschrift *)
    CurrentString:= 'Fehlermeldedatei';
    CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
    CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
    RetValWritten:= SysFileWrite(FileHandel, ADR(CurrentString), LEN(CurrentString));

    (* Spaltenüberschrift *)
    CurrentString:= 'Datum;Uhrzeit;Ort;Beschreibung';
    CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
    RetValWritten:= SysFileWrite(FileHandel, ADR(CurrentString), LEN(CurrentString));
  END_IF

  (* Datei schließen *)
  SysFileClose(FileHandel);


  (* --Zeile zusammenbauen-- *)

  (* Spalte 1: DATUM *)
  CurrentString:= CONCAT(INT_TO_STRING(Tag), '.');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Monat));
  CurrentString:= CONCAT(CurrentString, '.');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Jahr));
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 2: UHRZEIT *)
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Stunde));
  CurrentString:= CONCAT(CurrentString, ':');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Minute));
  CurrentString:= CONCAT(CurrentString, ':');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Sekunde));
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 3: NAME *)
  CurrentString:= CONCAT(CurrentString, Thermo_ort);
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 4: MELDUNG *)

    IF xConnectionOk_client_1 <> xConnectionOk_client_1_old THEN
     (* Öffne die Datei um Daten anzufügen *)
      FileHandel:= SysFileOpen(FilePath, 'a');
  (* --Zeile zusammenbauen-- *)

  (* Spalte 1: DATUM *)
  CurrentString:= CONCAT(INT_TO_STRING(Tag), '.');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Monat));
  CurrentString:= CONCAT(CurrentString, '.');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Jahr));
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 2: UHRZEIT *)
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Stunde));
  CurrentString:= CONCAT(CurrentString, ':');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Minute));
  CurrentString:= CONCAT(CurrentString, ':');
  CurrentString:= CONCAT(CurrentString, INT_TO_STRING(Sekunde));
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 3: NAME *)
  CurrentString:= CONCAT(CurrentString, Thermo_ort);
  CurrentString:= CONCAT(CurrentString, ';');

  (* Spalte 4: MELDUNG *)
        IF xConnectionOk_client_1 = TRUE THEN (*Hier soll überprüft werden ob Client 1 online ist und in die Datei geschrieben werden*)

         CurrentString:= CONCAT(CurrentString, Netzwerk_client_1_ok);
          CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
        END_IF

        IF xConnectionOk_client_1 = FALSE THEN (*Hier wird festgestellt das Client 1 offline ist und in die Datei geschrieben*)
         CurrentString:= CONCAT(CurrentString, Netzwerk_client_1_not);
          CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
        END_IF

    (* Zeile in die Datei schreiben *)
      RetValWritten:= SysFileWrite(FileHandel, ADR(CurrentString), LEN(CurrentString));
      (* Datei schließen *)
      SysFileClose(FileHandel);
    END_IF

    IF xConnectionOk_client_1 =  xConnectionOk_client_1_old THEN

    IF Temperatur_ueberschritten AND Thermometer_angeschlossen THEN
         CurrentString:= CONCAT(CurrentString, Temp_ueber);
          CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
          DatenString:= CONCAT(DatenString, Temp_ueber);
    END_IF

    IF Temperatur_unterschritten AND Thermometer_angeschlossen THEN
         CurrentString:= CONCAT(CurrentString, Temp_unter);
          CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
          DatenString:= CONCAT(DatenString, Temp_unter);
    END_IF

    IF Thermometer_angeschlossen AND NOT Temperatur_ueberschritten AND NOT Temperatur_unterschritten THEN
        CurrentString:= CONCAT(CurrentString, Thermo_ok);
          CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
          DatenString:= CONCAT(DatenString, Thermo_ok);
    END_IF

    IF Thermometer_angeschlossen = FALSE THEN
        CurrentString:= CONCAT(CurrentString, Thermo_not);
          CurrentString:= CONCAT(CurrentString, '$R$N'); (* Zeilenumbruch *)
          DatenString:= CONCAT(DatenString, Thermo_not);
    END_IF

(* Neue Daten ? *)

IF DatenString <> DatenString_old THEN

 (* Öffne die Datei um Daten anzufügen *)
  FileHandel:= SysFileOpen(FilePath, 'a');

  (* Zeile in die Datei schreiben *)
  RetValWritten:= SysFileWrite(FileHandel, ADR(CurrentString), LEN(CurrentString));

  (* Datei schließen *)
  SysFileClose(FileHandel);

END_IF
END_IF
(* Flankenauswertung *)
DatenString_old:=DatenString;
xConnectionOk_client_1_old:=xConnectionOk_client_1;


Auch läuft das FileHandle permanent. Ich habe das bisher so verstanden das es sich nur verändert wenn ein neuer Eintrag in der Datei erfolgt ist.

Also wie gesagt vielleicht findest den Fehler in meiner Schreibweise.

MFG Dennis


----------

