TIA Zeichenkette über Zeiger in DB speichern

PLU

Level-1
Beiträge
16
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich hoffe der Titel ist nicht zu unverständlich, mir ist leider nichts passendes eingefallen.

Ich bin Automatiker im 4. Lehrjahr und erlerne zurzeit die Grundlagen in AWL. Ich habe nun die Möglichkeit einen Notebookmanager zu entwerfen. Dieser soll bewerkstelligen das wir einen Überblick haben, wer zurzeit welchen Laptop hat. Zu diesem Zweck haben wir ein HMI Panel über welchen man den Namen und die Laptop Nr. eintragen kann, diese Daten werden dann in einem DB gespeichert.

Nun bin ich soweit das ich über des Eingabefeld eine Zeichenkette eintragen und sie in einem DB mit dem Datentyp String abspeichern kann. Jetzt will ich diese Eingabe in einen anderen DB Laden bei welchem der Offset über einen Pointer veränderbar ist. Ich habe mir das Programm so vorgestellt.


// Bedingung neuen Benutzer einlesen
A "Neuen Benutzer einlesen" => I0.0
FP "Flankenmerker (Neuen Benutzer einlesen)" =>M4.4
S "Hilfsmerker(Neuen Benutzer einlesen)" => M4.5
JCN Exit
R "Hilfsmerker(Neuen Benutzer einlesen)" => M4.5
// Schleifenzähler auf 0
L 0
T "Schleifenzähler_Benutzer einlesen" => MW 5
loop: NOP 0
// Pointer
L "Schleifenzähler_Benutzer einlesen" => MW 5
L 254
*I
SLD 3
LAR1
// Freien Platz suchen
OPN "Benutzernamen" => DB2
L DBW [ AR1 , P#0.0 ]
L ' '
==I
JC Einlesen
//Schleifenzähler + 1
L "Schleifenzähler_Benutzer einlesen" => MW5
L 1
+I
T "Schleifenzähler_Benutzer einlesen" => MW5
// Maximale Anzahl an freien plätzen erreicht
L 20
L "Schleifenzähler_Benutzer einlesen" => MW 5
==I
= "Keine freien plätze mehr" => M4.6
JC Exit
// von vorne beginnen
JU loop

Einlesen : NOP 0
// Pointer Benutzer einlesen
L "Schleifenzähler_Benutzer einlesen" => MW5
L 254
*I
SLD 3
LAR1
// Benutzername Speichern
L "HMI Eingabe"."Benutzernamen eingabe" => DB3
OPN "Benutzernamen"
L DBW [ AR1 , P#0.0 ] => DB2


Allerdings kommt nun beim Laden des DB3 folgende Fehlermeldung: Der Operand String ist für diese Anweisung nicht zulässig.

Leider versuche ich nun schon seit langem einen anderen Weg zu finden um diesen Fehler zu beheben aber mir ist bis jetzt noch nichts gelungen. Gibt es vielleicht irgendeine Möglichkeit über den Datentyp Char ?

Ich hoffe das klar ist was ich meine.
 
Du hast uns leider nicht verraten in welcher SPS du programmiert. S7-300/400 oder 1200/1500.
Bei letzteren wäre es mit einem Array_of_String sehr einfach. Auch in 300/400 sofern man SCL einsetzt.

In 300/400-AWL ist es ein wenig komplizierter.
Allerdings kommt nun beim Laden des DB3 folgende Fehlermeldung: Der Operand String ist für diese Anweisung nicht zulässig.
Der L(Lade)-Befehl lädt Werte in die AKKUs der CPU. Diese sind aber 32-Bit groß und somit auf Datentypen wie DWORD,DINT oder REAL begrenzt. Ein String-Wert kann so nicht geladen werden.

Zum Kopieren von längeren Datenbereichen verwendet man die Funkion SFC20 BLKMOV und kommt damit in Berührung mit dem ANY-Pointer.
Lies dazu bitte einmal erst das hervorragende FAQ von Volker.
http://www.sps-forum.de/faq/12923-zeiger-fuer-datentypen.html


Bevor es komplizierter wird.
Du könntest auch das variable "Pointer"-basierende programmieren auslassen und einfach einen SFC20-Aufruf für jeden Ziel-String programmieren und diesen via Index selektieren.

Wenn es immer noch variabel sein soll, dann muss nun dieser ANY-Pointer (welcher die Information über Start-Adresse und Länge des zu kopieren Bereichs enthält) variabel zusammenbaut werden.

Hier ein Beispiel:
Datenbaustein mit 20 Strings mit der Länge 30 Zeichen beginnend ab Byte 100.
Am Anfang des Datenbausteins speichere ich mir noch ein paar Variablen ab welche Information über die Beschaffenheit der Strings enthalten.
Code:
L    10
T    DbStrings.DbNr        //Datenbausteinnummer
L    20
T    DbStrings.StringCnt    //Anzahl der Strings
L    100
T    DbStrings.StringN1Offset    //Offset des ersten Stings im DB
L    32
T    DbStrings.StringByteLEN    //Länge eines Strings (Zeichenanzahl in Byte + 2Byte für Längeninformation)
Jetzt zum erstellen des ANY-Pointers und dem Kopieren
Code:
L    StringIndex        //Nummer des Strings auf den kopiert werden soll (1..20)
L    1
>=I
U(
L    StringIndex
 L    DbStrings.StringCnt    //Prüfen dass kein falscher Index angegeben wurde
<=I
)
SPBN MErr


//Schritt 1 - Berechnen der Startadresse des gewünschten Strings.
L    StringIndex
+    -1
L    DbStrings.StringByteLEN
*I
L    DbStrings.StringN1Offset
+I
T    #tmpStringStartAddr    //Berechnete Startadresse des Strings (TEMP-Bereich)


//Im TEMP-Bereich des Bausteins wurde auf Byte 0 eine Variable "tmpANY" vom Typ "ANY" (ANY-Pointer) angelegt.
//Diesen wird, entsprechend dem FAQ, passend modifiziert

L    B#16#10            //Kennung "S7" auf Byte 0 des ANY
T    LB0
L    B#16#02            //Datentyp Byte
T    LB1
L    DbStrings.StringByteLEN    //Anzahl der zu kopierenden Bytes
T    LW2
L    DbStrings.DbNr         //Datenbaustein-Nummer
T    LW4
L    #tmpStringStartAddr    //Startadresse                    
SLD  3
T    LD6
L    B#16#84
T    LB6                        //Speicherbereich - Datenbaustein


//Jetzt hast du einen ANY-Pointer der z.B. bei Index 5 folgende Information enthalten würde.
//   Speicherbereich Datenbaustein
//   Datenbausteinnummer 10
//   Startadresse 228
//   Länge 32Byte

//Nun zum Kopieren mit SFC20 BLKMOV

      CALL  "BLKMOV"
       SRCBLK :=DBString.StringAusEingabe    //String mit Länge 30 Zeichen aus der Eingabe
       RET_VAL:=#tmpRETVAL            //Rückgabewert der Funktion (bei Erfolg 0)
       DSTBLK :=#tmpANY                //Der ANY-Pointer (Kopier-Ziel)

PS.: Wenn du hier Code postest, verwende entweder das "#"-Symbol im Menü oder füge manuell am Beginn ein
[CODE] und am Ende ein [/CODE] ein.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich Programmiere eine S7/1500 im TIA.

Das FAQ Any-Zeiger für Datentypen habe ich durchgelesen und mehr oder weniger verstanden. Ich verstehe die Funktion des SFC 20 und auch ungefähr wie der Any-Pointer aufgebaut ist, aber ich denke das mir hier noch die Grundlagen im AWL programmieren fehlen. Ich habe dann ein Programm wie folgt aufgebaut, dies hat leider nicht wirklich funktioniert, was mir zeigt das das ich den Any-Zeiger doch nicht verstanden habe.

Das Programm sah so aus.
Code:
      L     B#16#10              // was ist mit :"10h für s7" gemeint ?
      T     %LB0
      L     B#16#13              //Typ String
      T     %LB1
      L     1                    // Keine Wiederholung 
      T     %LW2
      L     1                    //DB1 
      T     %LW4
      L     MW0    //Wird bei jeder Eingabe um 254 erhöht
      SLD   3                    //Pointer
      T     %LD6
      L     B#16#84
      T     %LB6
      CALL  BLKMOV
         SRCBLK  :="HMI Eingabe"."Eingabe über HMI"
         RET_VAL :="Fehlercode"
         DSTBLK  :=#MyZeiger

Den Code welcher du als Beispiel geschrieben hast habe ich leider auch nur ungefähr verstanden, auch hier fehlt mir wahrscheinlich die Erfahrung.

Zu beginn hast du noch von einem Array_of_String gesprochen, welcher bei einer S7/1500 funktionieren sollte.
Was bedeutet das? und wie programmiert man das? Benötigt man auch hier den Any-Zeiger?

Danke Vielmals für eine Hilfe!
 
Ich Programmiere eine S7/1500 im TIA.
Na, dann hätten wir uns den Aufwand gleich sparen sparen können.
Gib das in Zukunft immer gleich an, TIA heist nicht automatisch 1500.

Gelernt hast du aber trotzdem was... :ROFLMAO:

Besagter Code mit dem ANY und dem SFC20 hätte zwar auch auf der 1500 funktioniert, allerdings nur
in "Nicht Optimierten"-Bausteinen. Denn nur dort gibt es Adressen.

Ich habe dann ein Programm wie folgt aufgebaut, dies hat leider nicht wirklich funktioniert, was mir zeigt das das ich den Any-Zeiger doch nicht verstanden habe.
Code:
L     B#16#10    // was ist mit :"10h für s7" gemeint ?
[COLOR=#ff0000]        // Ist eine Konstante die für ANY-Pointer innerhalb einer S7
        // immer den Wert "B#16#10" haben muss. Warum... Keine Ahnung. :-)[/COLOR]


L     B#16#13    // Typ String
L     1        // Keine Wiederholung
        [COLOR=#ff0000]// Hier ist der Fehler warum es nicht geklappt hat.
        // Der Any-Pointer beeinhaltet keine gültige Längeninformation
        // Wie lang ist eine Wiederholung vom Typ String?
         // Ein String kann 10,20,30 bis 254 Zeichen haben.
        // Ich würde hier aber trotzdem den Datentyp Byte nehmen.
        // Selbst wenn man einer Funktion sybolisch einen String an einen ANY-Eingang
        // übergibt bekommt man am inneren (wenn man den ANY zerlegt) trotzdem
        // den Datentyp B#16#2 (Byte) mit Wiederholungsfaktor "Anzahl der Zeichen + 2".
         // Warum gibt es den Datentyp "String" im ANY überhaupt? Weiß ich auch nicht.[/COLOR]

L     MW0    //Wird bei jeder Eingabe um 254 erhöht
        [COLOR=#ff0000]//Darf ich annehmen dass dein String als String[254] deklariert ist?
        //Dann wäre auch diese Angabe falsch da ein String immer zwei Zusatzbytes belegt.
        //Byte0 enthält die maximale Anzahl an Zeichen, bei String[30] eben 30.
        //Byte1 enthält die aktuelle Länge des enthalteten Strings. "Hallo" = 5.[/COLOR]
[COLOR=#ff0000]        //Dann kommen erst die 30Byte Zeichen. Sind dann 32Byte im gesamten.[/COLOR]
Den Code welcher du als Beispiel geschrieben hast habe ich leider auch nur ungefähr verstanden, auch hier fehlt mir wahrscheinlich die Erfahrung.
Du musst dann schon nennen was du konkret nicht verstanden hast....
Zu beginn hast du noch von einem Array_of_String gesprochen, welcher bei einer S7/1500 funktionieren sollte. Was bedeutet das? und wie programmiert man das? Benötigt man auch hier den Any-Zeiger?
Deswegen die Frage nach dem System auf dem du programmierst.
Das mit dem Array ist wahrscheinlich die einfachste Variante, funktioniert in AWL aber nur auf der 1500.
Auf der 300/400 ging das nur in SCL.

Ein Array (google einfach mal danach) ist ein Feld aus Elementen gleichen Datentyps.
Ein "ARRAY[1..10] of INT" ist ein Feld aus 10 Integern wobei z.B. das fünfte Element über Symbolname[5] angesprochen werden kann.

Wenn du ein deinem Ziel-Datenbaustein also ein StringArray wie folgt deklarierst.
Name "MeineZielStrings" und in der Spalte Datentyp "Array[1..20] of String[254]" dann bekommst du 20 Strings welche du wie folgt ansprechen kannst.

"MeinDatenbaustein".MeineZielStrings[1]
"MeinDatenbaustein".MeineZielStrings[2]
"MeinDatenbaustein".MeineZielStrings[3]
...
Die Nummer ist der sogenannte Array-Index und kann auch Variabel gestaltet werden.
"MeinDatenbaustein".MeineZielStrings[#tmpIndexVariable]

Im 1500er AWL kannst du dann die Funktion MOVE verwenden. (Ist das selbe wie die MOVE-Box in KOP/FUP)
Code:
 //Sollte ungefähr so aussehen. Hab kein TIA hier für die genaue Syntax.
//Schreib einfach "CALL MOVE", drück Enter. Den Rest findest du aus der F1-Hilfe.

L     5
T     #tmpIndexVariable        //TEMP-Bereich Typ-Integer

//Vor dem Kopieren solltest du den Index (wo auch immer der herkommt) nochmal auf Gültigkeit prüfen.

CALL  MOVE
IN    :="HMI Eingabe"."Eingabe über HMI"
OUT   :="MeinDatenbaustein".MeineZielStrings[#tmpIndexVariable]
(Genau dieser variable Index geht unter 300/400 nur in SCL)

Das schreibt deinen Eingabe-String auf das 5. Element deines String-Array.
Da brauchst du keine Adressen berechnen und keine ANY-Pointer.
 
Zuletzt bearbeitet:
Habe bei der Simulation gerade bemerkt, das es doch nicht funktioniert. Beim "In" des MOVE Befehles wird angezeigt das hier nicht der Datentyp String verwendet werden darf.
 
Habe bei der Simulation gerade bemerkt, das es doch nicht funktioniert. Beim "In" des MOVE Befehles wird angezeigt das hier nicht der Datentyp String verwendet werden darf.
Hast du zwischen "CALL MOVE" und "IN" auch die Datentypen auf String / String gestellt?

Sonst zeig mal nen Screenshot.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
TIA_Ntzwerk 1.PNG

Da CALL MOVE ein unbekannter Befehl war habe ich es mit dem Baustein programmiert. Unter dem Rot angezeigten Text steht folgende Meldung: Der Datentyp String des Aktualparameters passt nicht zum Datentyp Byte, Char usw.
 
Unter dem Rot angezeigten Text steht folgende Meldung: Der Datentyp String des Aktualparameters passt nicht zum Datentyp Byte, Char usw.
OK, am "IN" hast du einen String angegeben, an "OUT" allerdings einen CHAR. Damit ist die Meldung richtig so. Du hast "Datenbaustein_2"."HMI_Eingabe[MW0]" angegeben.

Dieser Zugriff ist nicht das was ich mit "Verwendung von Arrays" gemeint habe.
Du musst wissen dass der Datentyp String eigentlich selbst ein "Array_of_CHAR" ist.
Wenn man auf einen String mit String[10] zugreift dann bekommt man das zehnte Zeichen und das hat den Datentyp CHAR.

Ich hatte hatte aber ein Array_of_String gemeint. Ist verwirrend ich weiß... ;)
Daher kommen hier jetzt Bilder zum Einsatz.
TIA_String_Array_Move_1.jpgTIA_String_Array_Move_2.jpg

Musste allerdings selbst feststellen das Siemens es wiedereinmal nicht geschafft hat alle Datentypen mit dem Befehl MOVE zu kopieren.
Mann kann Byte, Int, Real, Struct, UDT, DTL und Konsorten jetzt endlich mit dem selben Befehl kopieren, für String musste man aber wieder einen eigenen namens S_MOVE einfügen.
Was soll das denn?

Wenn du für deine Eingaben allerdings mehr als nur einen String speichern willst würde ich die Kombination aus Array und benutzerdefinierten Datentyp vorschlagen.
TIA_String_Array_Move_3.jpgTIA_String_Array_Move_4.jpgTIA_String_Array_Move_5.jpg

PS.: Der MOVE bzw. der S_MOVE gehen problemlos in AWL. Einfach "CALL MOVE" tippen und Enter.
 
Zuletzt bearbeitet:
Super! Jetzt hat es mit der Simulation geklappt und auch die Fehlermeldung ist Weg. Vor allem die Bilder waren sehr Hilfreich und haben mir sehr geholfen, das Ganze zu verstehen. Nochmals vielen Dank für deine Hilfe!
 
Zurück
Oben