String in Array of String schreiben

carepicha

Level-1
Beiträge
49
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Liebes SPS Forum,

Ich möchte Zustände Loggen und Strings in einem Array ablegen.


DiagArrayLog^:= StringTest;

Bei diesen Aufruf kommt immer ein PageFault.

Ist dies zulässig?
Hat jemand eine Idee warum dieser Fehler auftritt?

Besten Dank für Eure Unterstützung.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Dass geht nicht.

Ich poste mal den gesamten Code um mein Problem genauer zu beschreiben;
Ich ein Struct gemacht habe (Diag) und den Pointer übergebe ich. Deshalb braucht es meiner Meinung nach das ^ zwingend.
Ich möchte das Struct in ein separates Array kopieren damit ich verschiedene Zustände festhalten kann.
Genau bei dieser Zuweisung gibt es den Page Fault.

Aufgrund dessen habe ich versucht lediglich ein Wert des Types STRING in ein Array zu schreiben.
=> Auch hier passiert der gleiche Fehler
=> Dies deutet darauf hin, dass es mit der Zuweisung eine Strings in ein Array ein Problem gibt.

Für weitere Hinweise bin ich dankbar.

(*Log the machine status*)

(*diag*)
DiagArrayTemp := ADR (Diag);

count :=SIZEOF(Diag)-1; (*the array runs from 0..n*)



FOR i:= 0 TO count BY 1 DO
DiagArrayLog^:= DiagArrayTemp^;
DiagArrayLog^:= StringTest;
nicount:=i;

END_FOR;
 
Du hattest eben doch recht, ich hatte das DiagArrayLog fälschlicherweise mit Pointer definiert :-(

Jetzt habe ich eine weitere Frage;

Wenn ich den (SizeOf) mache, dann gibt es einen Count von 1701;
Das macht auch insofern Sinn den,
21 Anzahl Strings im Struct
81 = Bit = Datengrösse eines Strings (Ist auch so in den Schulungsunterlagen definiert.
=1701

Warum ist der Count 1701,
Mich interessiert ja nicht die Grösse des Datenbereiches, sondern Anzahl Strings

Hat jemand eine Idee?
Was muss ich anschliessend Unternehmen dass die entsprechenden Strings auch im Logger Array auf Platz 0-21 stehen und nicht zwischen 0 und 1701 verteilt sind?

Vielen Dank für Eure Unterstützung
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du hattest eben doch recht, ich hatte das DiagArrayLog fälschlicherweise mit Pointer definiert :-(

Jetzt habe ich eine weitere Frage;

Wenn ich den (SizeOf) mache, dann gibt es einen Count von 1701;
Das macht auch insofern Sinn den,
21 Anzahl Strings im Struct
81 = Bit = Datengrösse eines Strings (Ist auch so in den Schulungsunterlagen definiert.
=1701

Warum ist der Count 1701,
Mich interessiert ja nicht die Grösse des Datenbereiches, sondern Anzahl Strings

Hat jemand eine Idee?
Was muss ich anschliessend Unternehmen dass die entsprechenden Strings auch im Logger Array auf Platz 0-21 stehen und nicht zwischen 0 und 1701 verteilt sind?

Vielen Dank für Eure Unterstützung


Item1:string(50); (*50 Bytes werden im Speicher fuer den String "reserviert", damit hat jeder Arraitem gleiche Groesse*)

(*Anzahl Strings*)
Anzahl:=0;
while _i < ArrayItem_Max+1 do
if ArraItem[x].String <> '' then
Anzahl:=Anzahl+1;
end_if;
_i:=_i+1;
end_while;


Irek
 
Einfache Methode


ArrayNeu[x].ItemNeu1:=ArrayAlt[y].ItemAlt1; (*ArrayNeu[1...n] of Struct*)


Irek

Genau so möchte ich das machen, aber momentan habe ich noch ein Problem mit dem Syntax;

Mein Struct heisst ST_Diag

Bedeutet dass ich mache 2 Instanzen vom Struct?
Diag:ST_DIAG;
DiagLogger:ST_DIAG;

und dann

DiagLogger:=Diag;

kommt der Fehler
<Index> ist nur für Arrayvariablen zulässig

Oder was ist Eure Meinung wie mehrere Strings geloggt werden sollen?

Danke für Eure Hilfe
 
Zuletzt bearbeitet:
Item1:string(50); (*50 Bytes werden im Speicher fuer den String "reserviert", damit hat jeder Arraitem gleiche Groesse*)


(*Anzahl Strings*)
Anzahl:=0;
while _i < ArrayItem_Max+1 do
if ArraItem[x].String <> '' then
Anzahl:=Anzahl+1;
end_if;
_i:=_i+1;
end_while;




Irek



Danke für den Vorschlag,

Könntest du mir erklären warum es dann so gut sein soll?
Ist dann zu erwarten dass anschliessend die geloggten Daten im Array auf 1-21 stehen?

Danke für deine Bemühungen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Im Quellarray sind die Informationen zufällig verteilt. Also prüfe ich jeden Eintrag auf den Inhalt.
Das wird in den erste While-Schleife erledigt. Wird etwas gefunden kopieren wir das in den Ziel-Array. Damit es auch funktioniert muss ich den Arrayindex inkrementieren, also der erste Eintrag in den ArrayNeu[1].etwas, der nächste in den ArrayNeu[2].etwas.
Am Ende sind alle relevanten Einträge erfasst und können weiter verarbeitet werden.
Deklaration String:STRING(40); reserviert im Speicher 40 byte, sonst werden 80 daraus.
Wenn ich also ein Array aus STRUCT Elementen habe, bin ich in der Lage über die Adresse
ArraySTRUCT[X].Eintrag den gewünschten Element zu bearbeiten.


Neue_Wert:=ArraySTRUCT[X].Eintrag
oder
ArraySTRUCT[X].Eintrag:=Neue_Wert;


Irek
 
Im Quellarray sind die Informationen zufällig verteilt. Also prüfe ich jeden Eintrag auf den Inhalt.
Das wird in den erste While-Schleife erledigt. Wird etwas gefunden kopieren wir das in den Ziel-Array. Damit es auch funktioniert muss ich den Arrayindex inkrementieren, also der erste Eintrag in den ArrayNeu[1].etwas, der nächste in den ArrayNeu[2].etwas.
Am Ende sind alle relevanten Einträge erfasst und können weiter verarbeitet werden.
Deklaration String:STRING(40); reserviert im Speicher 40 byte, sonst werden 80 daraus.
Wenn ich also ein Array aus STRUCT Elementen habe, bin ich in der Lage über die Adresse
ArraySTRUCT[X].Eintrag den gewünschten Element zu bearbeiten.


Neue_Wert:=ArraySTRUCT[X].Eintrag
oder
ArraySTRUCT[X].Eintrag:=Neue_Wert;

Danke für deine Beschreibung.
Kann es sein dass der Befehl für das Speichern im ZielArray fehlt?
Sonst ist es soweit klar.

Noch eine Frage für die Zuweisung.

Warum
Neue_Wert:=ArrayStruct[x].Eintrag

Ich möchte ja den Wert jeweils indexiert zum Struct hinzufügen.
Erfolgt dies nicht mit
ArraySTRUCT[X]:=Neue_Wert;


Danke für Eure Hilfe
 
Danke für deine Beschreibung.
Kann es sein dass der Befehl für das Speichern im ZielArray fehlt?
Sonst ist es soweit klar.

Noch eine Frage für die Zuweisung.

Warum
Neue_Wert:=ArrayStruct[x].Eintrag

Ich möchte ja den Wert jeweils indexiert zum Struct hinzufügen.
Erfolgt dies nicht mit
ArraySTRUCT[X]:=Neue_Wert;


Danke für Eure Hilfe

Genau das, will man noch mehr, dann besteht die die Möglichkeit im Qellarray weitere Informationen zu definieren, die über den Index mitkopiert werden.
Das Speichern erfolgt hinter der IF Abfrage mit der Anweisung ArraySTRUCT[X]:=Neue_Wert;
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Anzahl:=0;
while _i < ArrayItem_Max+1 do
if ArraItem[x].String <> '' then (*hier wird nach einen String gesucht, wenn nichts da, wird der naechste Arrayfeld bearbeitet*)
NewArrayItem[Anzahl].String:=ArraItem[x].String(*und wenn was da, dann in neuen Array kopieren*)
Anzahl:=Anzahl+1;(*Index erhoehen, sonst wird alles ueberschrieben*)
end_if;
_i:=_i+1;
end_while;

Im neuen Array werden dann die gesuchten Werte uebernommen
PS.: Schreibweise durch englische Tastatur bedingt
 
Anzahl:=0;
while _i < ArrayItem_Max+1 do
if ArraItem[x].String <> '' then (*hier wird nach einen String gesucht, wenn nichts da, wird der naechste Arrayfeld bearbeitet*)
NewArrayItem[Anzahl].String:=ArraItem[x].String(*und wenn was da, dann in neuen Array kopieren*)
Anzahl:=Anzahl+1;(*Index erhoehen, sonst wird alles ueberschrieben*)
end_if;
_i:=_i+1;
end_while;

Im neuen Array werden dann die gesuchten Werte uebernommen
PS.: Schreibweise durch englische Tastatur bedingt


eine andere Version
PROGRAM MAIN
VAR
String_Array_Qelle:ARRAY[1..10] OF STRING(2):='1','','2','','3','','4','','5','';
String_Array_Ziel:ARRAY[1..10] OF STRING(2);
State_Machine:INT:=1;
Start_Kopieren:BOOL;
_X:INT:=1;
_Y:INT:=1;
END_VAR
(****************************************************)

CASE State_Machine OF
(*Start*)
1: IF Start_Kopieren THEN
State_Machine :=2;
END_IF;
(*weitersuchen oder Ende*)
2: IF _X < (10+1) THEN
State_Machine :=3;
ELSE
State_Machine :=5;
END_IF
(*Item mit oder ohne Inhalt*)
3: IF String_Array_Qelle[_X] <> '' THEN
State_Machine :=4;
ELSE
_X:=_X+1;
State_Machine :=2;
END_IF;
(*gefundenen Inhalt kopieren*)
4: String_Array_Ziel[_Y]:= String_Array_Qelle[_X] ;
_X:=_X+1;
_Y:=_Y+1;
State_Machine :=2;
END_CASE;


**************************************************************)
 
OK, die Schlaufe funktioniert nun soweit.
Nun erhalte ich nun aber eigenartige Sachen wenn mit der Übergabe des Pointers für das Struct.

Ich erstelle eine Instanz des Struct;
Code:
Diag:ST_DIAG;

und übergebe den Pointer;
Code:
ArrayDiagTemp := ADR (Diag);

Wenn ich im Struct die String Daten prüfe sind alle schön vorhanden.

Das Problem scheint nun schon bei der Übergabe des Pointers zu entstehen. Es stimmt lediglich der erste Eintrag.
Weiss jemand warum das so ist?
Danke für Eure Inputs

Array.JPG
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi,

das wird nur bedingt funktionieren. Eine CPU (µC) kennt keine geschriebenen Zahlen
oder Buchstaben.
Dies wir im Byte als ASCI-Wert dargestellt, will heißen ein Buchstabe=1Byte (8bit).
„1“=16#31
„9“=16#39
„A“=16#41
„Z“=16#5A
„a“=16#61
„z“=16#7A

weil:

Nibble=4bit
2 Nibble=8bit=1byte

und die Werte im Nibble dazu
0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
0101 = 5
0110 = 6
…...........
1001 = 9
1010 = A (10 Dez)
…........
1111 = F (15 Dez)
daraus folgt Byte 16#FF=1111 1111 (High Nibble Low Nibble)
16#11=0001 0001

Für den String im Speicher brauchen wir die Startadresse, seine Länge (Anzahl Bytes), dann
Byte für Byte alles auslesen, Umwandeln und zusammenfügen.
Der Operator ADR liefert nur die Adresse vom ersten Byte, versuch dann mit SIZEOF die
Gesamtlänge für den Arrayitem zu ermitteln.
Ist der String 5 Buchstaben Lang werden dementsprechend 5 Bytes benötigt.
Irek

direkt vom Beckhoff:

pt:pOINTER TO INT;
var_int1:INT := 5;
var_int2:INT;
pt := ADR(var_int1);(*das ist nur Die Speicheradresse*)
var_int2:= pt^; (* var_int2 ist nun 5 ) (In die der Wert 5 reingeschrieben wird*)
 
Ok Danke,
eigentlich wollte ich nur strings loggen......scheint nicht ohne weiteres möglich zu sein.

Wenn ich die Strings in ein CSV schreiben möchte, werde ich wohl auf die gleiche Problematik stossen, oder?

Sonstige Ideen wie dies am einfachsten realisiert werden kann?

Danke für eure Unterstützung
 
Ok Danke,
eigentlich wollte ich nur strings loggen......scheint nicht ohne weiteres möglich zu sein.

Wenn ich die Strings in ein CSV schreiben möchte, werde ich wohl auf die gleiche Problematik stossen, oder?

Sonstige Ideen wie dies am einfachsten realisiert werden kann?

Danke für eure Unterstützung

Hi,

1)Es geht auch anders, leider gegen Entgeld. Wenn ich Daten (Strings) logge und das ueber langen Zeitraum, dann bitet XML-Server
die Loesung.
Du kannst jede Information als String nach Daum und Uhrzeit sortiert im Log.xml File speichern.
Man nehme anschliessend FTP und XML Editor vom MS.
2) CSV ist eigentlich die primitive Version von XML, kann genauso im File gespeichert werden, und ueber XCell Import als EXcell-Tabelle ausgelesen werden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Leider ist mir noch nicht alles ganz klar.

Mit dem Pointer zeigen wir lediglich auf den Start des Speicherortes.
=> Mit
if ArraItem[x].String <> '' then (*hier wird nach einen String gesucht, wenn nichts da, wird der naechste Arrayfeld bearbeitet*)
kann der Start des Array bestimmt werden wo ein String vorhanden ist.
=> An diesem Speicherort sind die Charakter im ASCI-Format abgelegt und sind pro Charakter 1 Byte gross.
=> Um den kompletten String zu bestimmen muss die länge diese Strings bestimmt werden und die Char dementsprechend entschlüsselt werden.



Was ich jetzt nicht verstehe ist warum der erste Eintrag korrekt angezeigt wird.

Logger.JPG

Was sind dann die restlichen Einträge? Ich hätte erwartet die restlichen Einträge aus dem Struct zu Filtern.
(Des Weitern sollten einige Einträge wie ein Teil einer IP-Adresse eigentlich gar nicht erscheinen)

Danke für Eure Hilfe
 
Hi,

wenn dein String als noLimit definiert wurde, dann liest die PLC max 80 Zeichen (Standartgroesse), oder
es gib den Zeichen "Stringende", was zu neuen Arrayeintrag fuehrt.
Was du da siehst, ist der Speicherabbild beginnend mit Startadresse Quellstring.

Irek
 
Ich möchte nochmals auf die Adressierung zurückkommen.

Ich habe ein Struct mit 21 Einträgen

z.B
Code:
TYPE ST_Diag :
STRUCT


	SFCCurrentStepRef			:STRING (40);
	SFCCurrentStepSystem                 :STRING (40);
        etc....

Code:
	Diag:ST_DIAG;

Nun mache ich den Zugriff auf dieses Struct mit einem Pointer

Code:
ArrayDiagTemp := ADR (Diag);

Code:
ArrayDiagTemp:  POINTER TO ARRAY [0.. n] OF STRING;	                                (*This is the diag array which hold all the temp machine status*)
														(*to access the diag infos more easly there is a struct defined which points to the same array*)
														(*use this array only in *)


Frage 1;
Wieviel Speicherplatz wird nun für das ArrayDiagTemp reserviert?
Könnte dies auch mit STRING (40) limitiert werden da die Daten im Struct nicht grösser sein können?
Was passiert nun wenn das Array keine explizite hat Zuweisung hat?
Es werden 80 Byte reserviert pro Array reserviert, oder?
Da mein Eintrag im Struct mit 40 Byte limitiert ist bleiben dann der Speicherplatz von 41-80 immer leer?

Frage 2;
Warum zeigt es nur bei der ersten Zeile im Array den Korrekten Text vom Struct an?
Ist jetzt nicht zu erwarten dass beim Array am Speicherplatz 81 sich der nächste String befindet?
Gemäss vorherigem Post sind die Daten im ASCII abgelegt. Warum ist nun aber 1 Eintrag korrekt und der Rest ist Müll?

Frage 3;
Warum befinde ich mich im Speicherabbild der SPS?
Ich hätte erwartet, dass ich mich lediglich im Speicher vom ArrayDiagTemp befinde.

Sorry dass ich hier nochmals nachhacken muss, aber es lässt mich nicht in Ruhe wenn ich die Funktionsweise nicht verstehe.
Danke für Eure Unterstützung?
 
Zurück
Oben