Step 7 SCL Code aus TIA in Step7 classic

VooDooDog

Level-2
Beiträge
18
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin Moin.

Ich verzweifele gerade etwas und bin mit Step7 classic auch nicht so richtig bewandert muss ich gestehen.

In TIA habe ich mir ein kleines SCL Script zum erstellen einer einmaligen ID erstellt im Muster:

W1_xxxx

Als Input gibt es lediglich eine INT Variable, die bei jeder steigenden Flanke +1 addiert und dann die obrige ID generieren soll.
Also W1_0001, W1_0002 usw....

In Tia klappt dies auch ohne Probleme. In Step7 classic komme ich da irgendwie auf keinen grünen Zweig.
Das hochzählen klappt dort, aber wenn ich in die Datenbank schaue, wo die generierte ID stehen soll, passiert nichts.
Ich vermute mal, dass es an meiner unwissenheit im Umgang mit Step7 Classic liegt und habe bisher auch keine Lösung gefunden. Daher hoffe ich, dasss ihr mir weiter helfen könnt.

Mein Code in TIA:
Code:
//Initialisierung
#iString := '';         //Leere Variable iString
#sErgebnis := '';       //Leere Variable sErgebnis
#hString := '0000000';  //Fülle Variable hString mit Nullen
#max_len := 4;          //Maximale Länge der ID

#iString := INT_TO_STRING(IN := #i);    //Wandelt Int zu String
#len1 := LEN(#iString);                 //Ermittelt die Länge des Strings
#len2 := #len1 - 1;                     // Ziehe Vorzeichen von der Stringlänge ab
#sErgebnis := RIGHT(IN := #iString, L := #len2);
#sErgebnis := RIGHT(IN := CONCAT(IN1 := #hString, IN2 := #sErgebnis), L := #max_len);
#ID:= CONCAT(IN1 := #WAESCHE1, IN2 := #sErgebnis);

Dazu das Step 7 Classic gegenstück:

Code:
FUNCTION FC498 : VOID

VAR_TEMP
  // temporäre Variablen
    iString     :   STRING[16];
    sErgebnis   :   STRING[16];
    hString     :   STRING[16];
    Zusatz      :   STRING[16];
    tmp         :   STRING[16];
    len1        :   INT;
    len2        :   INT;
    max_len     :   INT;
END_VAR

VAR_INPUT
  i : int;
END_VAR

VAR_OUTPUT
   ID : STRING[16];
END_VAR

BEGIN
//Initialisierung
iString     := '';
sErgebnis   := '';
Zusatz      := 'W1_';
hString     := '0000000';
max_len     := 4;

iString := INT_TO_STRING(IN := i);    //Wandelt Int zu String
len1 := LEN(iString);                 //Ermittelt die Länge des Strings
len2 := len1 - 1;                   
sErgebnis := RIGHT(IN := iString, L := len2);
sErgebnis := RIGHT(IN := CONCAT(IN1 := hString, IN2 := sErgebnis), L := max_len);
tmp := CONCAT(IN1 := Zusatz, IN2 := sErgebnis);
ID := tmp;

END_FUNCTION

Vielen Dank :)
 
die TEMP-Variable tmp muss initialisiert werden
In Step7 classic und S7-300/400 werden TEMP-Variablen nicht initialisiert.

(übrigens sollte man auch bei S7-1200 und S7-1500 TEMP-Variablen vor Verwendung immer selbst initialisieren)

Was für eine CPU programmierst du da? Bei S7-300/400 sollte man nicht so sorglos Ressourcen-verschwenderisch programmieren. Umständlicher als mit 4 String-Funktionen geht es ja fast gar nicht... ;)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich würde mal sagen, dass es an der Variablen "tmp" liegt - das ist die Einzige der String-Variablen, die am Anfang nicht initialisiert worden ist. Der CONCAT kann aber nun auch nur als OUT mit einer initialisierten Variablen etwas anfangen ...
 
die TEMP-Variable tmp muss initialisiert werden
In Step7 classic und S7-300/400 werden TEMP-Variablen nicht initialisiert.

(übrigens sollte man auch bei S7-1200 und S7-1500 TEMP-Variablen vor Verwendung immer selbst initialisieren)

Was für eine CPU programmierst du da? Bei S7-300/400 sollte man nicht so sorglos Ressourcen-verschwenderisch programmieren. Umständlicher als mit 4 String-Funktionen geht es ja fast gar nicht... ;)


Ah das hatte ich übersehen, bzw. habe ich die Variable erst zum Schluss hinzugefügt, weil ich ansonsten Zuweisungsfehler hatte und diese als Zwischenschritt genutzt habe.

Leider brachte die initialisierung der tmp Variable aber auch nicht den gewünschten Effekt.

Als CPU wird eine 319-3 PN/DP benutzt. Mir ist bewusst, dass diese Vorgehensweise nicht die Resourcen schonenste Variante ist.
Leider wüsste ich nicht wie ich das auf Anhieb anders lösen soll, da ich mich mit STRING Funktionen als solches nicht gut genug auskenne und mir Step7 Classic an vielen Stellen echt Verständnisprobleme bereitet. Ich bin überwiegend nur mit TIA unterwegs.

Wie würde man das denn am sinnvollsten und Ressourcen schonensten lösen?


Deklariere die Temp-Variablen hinter den Ein- / Ausgängen.

Ansonsten kann ich das erst morgen simulieren, mir fällt sonst auch nichts auf.
Habe ich probiert, so wurde zumindest irgendwas gemacht, aber nicht das gewünschte :D
Als Rückgabewert kam "$00" raus.

EDIT: ich bin jetzt erst in ein paar Stunden wieder aktiv. Hab eine länger fahrt vor mir.
 
die TEMP-Variable tmp muss initialisiert werden
Ich würde mal sagen, dass es an der Variablen "tmp" liegt - das ist die Einzige der String-Variablen, die am Anfang nicht initialisiert worden ist. Der CONCAT kann aber nun auch nur als OUT mit einer initialisierten Variablen etwas anfangen ...

Aus der Bausteinhilfe des CONCAT:
Ist die Ergebniszeichenkette länger als die am Ausgangsparameter angelegte Variable, wird die Ergebniszeichenkette auf die maximal eingerichtete Länge begrenzt und das BIE-Bit auf "0" gesetzt.
Ergo: der String-Header (zumindest das erste Byte) muss initialisiert werden, idealerweise auf die max. deklarierte Stringlänge, z.B. so: tmp := '';
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@PN/DP : wenn ich das bei dir gesehen hätte dann hätte ich die Antwort nicht auch nochmal gegeben ... Unabhängig davon aber hast du auch schon das eine oder andere Mal einen Vorschlag von mir einfach auch noch mal gepostet ...

@VooDooDog : vielleicht solltest du, nur mal testweise, deinen String "tmp" nicht in seiner Länge begrenzen sondern auf max setzen. Es könnte ja vielleicht auch daran liegen. In jedem Fall aber : anders als du hätte ich es auch nicht gelöst - das Ganze hat jetzt für mich auch erstmal nichts mit Classic ./. TIA zu tun ...
 
Ich habe während der fahrt auch mal etwas meine Gedanken schweifen lassen und vermute mittlerweile auch ganz stark, dass es was mit den längen der Strings zu tun hat. Ich teste da nachher noch etwas wenn ich zu Hause bin.

Bis hierhin aber schon einmal danke euch
 
Hallo VooVooDog,

Hast du sicher die Hilfs FC^s für die String Funktion sicher in die CPU geladen?
Die werden gerne vergessen?
Evtl mal einen Online Offline vergleich machen.

Gruß TIA
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo VooVooDog,

Hast du sicher die Hilfs FC^s für die String Funktion sicher in die CPU geladen?
Die werden gerne vergessen?
Evtl mal einen Online Offline vergleich machen.

Gruß TIA
Oh, da bin ich mir, jetzt wo du fragst, nicht 100%ig sicher. Prüfe ich nachher ebenfalls einmal nach. Danke für den Hinweis
 
Leider brachte die initialisierung der tmp Variable aber auch nicht den gewünschten Effekt.
bei meinem Test aber. Es reicht, die Zeile tmp := ''; hinzuzufügen, und schon funktioniert dein Code

Oder ist dein am FC-OUT angeschaltete String auch nicht initialisiert?
Wie bereits geschrieben, muss mindestens das erste Header-Byte des String (die max Länge) initialisiert sein. Wenn da 0 drin steht, dann kopiert keine Stringfunktion etwas in den String.

Oder hattest du die 4 String-FC nicht in die CPU geladen? Da sollte die CPU in STOP gehen, wenn die Fehler-OB nicht geladen sind.

Wie würde man das denn am sinnvollsten und Ressourcen schonensten lösen?
spontan: durch Ziffern-Zerlegung bei der INT-nach-ASCII-Wandlung, anstatt String Funktionen.

Allerdings stellt sich der SCL-V5.x-Compiler da etwas umständlich an. Ich würde bei Step7 classic (für S7-300 oder S7-400) die Funktion in AWL programmieren. Weil das Kopieren eines String von TEMP nach OUT in einem FC sehr aufwendig ist, würde ich die Funktion als FB programmieren.
SCL Compiler V5.x :
- initialisieren TEMP-String ist aufwendig
- MOD mit INT ist etwas aufwendig/umständlich übersetzt
- Index-Adressierung in TEMP-Array ist sehr aufwendig
- kopieren von TEMP nach FC-OUT ist aufwendig

Ich habe mal 2 SCL-Varianten und eine AWL-Variante programmiert und die Codegrößen verglichen:
Code:
Vergleich Codegröße SCL original Programm mit Stringfunktionen, SCL besser, SCL optimiert, AWL
Größe der String-FC I_STRNG + LEN + RIGHT + CONCAT = 966 Bytes

SCL orig. #1 + tmp : 752 Bytes + Code der 4 String-FC 966 Bytes
SCL ohne String-FC : 472 Bytes
SCL optimiert DINT : 464 Bytes
AWL FB (by PN/DP)  : 104 Bytes
Code:
VAR_TEMP
    ....
    tmp         :   STRING[16];
    atmp AT tmp : ARRAY[-1..16] OF CHAR;
    d : DINT;
END_VAR

//SCL ohne Stringfunktionen mit Ziffernzerlegung
tmp     := 'W1_';
atmp[7] := INT_TO_CHAR(i MOD 10 + 48);
atmp[6] := INT_TO_CHAR(i / 10 MOD 10 + 48);
atmp[5] := INT_TO_CHAR(i / 100 MOD 10 + 48);
atmp[4] := INT_TO_CHAR(i / 1000 MOD 10 + 48);
ID := tmp;
Code:
//SCL optimiert DINT
d := i; //INT TO DINT
tmp := 'W1_';
atmp[7] := INT_TO_CHAR(DINT_TO_INT(d MOD 10) + 48);
atmp[6] := INT_TO_CHAR(DINT_TO_INT(d / 10 MOD 10) + 48);
atmp[5] := INT_TO_CHAR(DINT_TO_INT(d / 100 MOD 10) + 48);
atmp[4] := INT_TO_CHAR(DINT_TO_INT(d / 1000 MOD 10) + 48);
ID := tmp;
Code:
//AWL FB : i in ID-String 'W1_nnnn' wandeln
//Pointer auf den OUT-Parameter ID in der Instanz
      TAR2                              //FB-Multiinstanzoffset aus AR2
      UD    DW#16#FFFFFF                //Bereichskennung (DB) ausblenden
      L     P##ID                       //Adresse ID in der Instanz
      +D                                // Adresse ID im IDB
      LAR1                              //Pointer auf den OUT-Parameter ID

      L     W#16#807                    //maxLen 8 + IstLen 7
      T     DIW [AR1,P#0.0]             //String-Header initialisieren

//Prefix-Zeichen 'W1_' in String eintragen
      L     'W1_0'
      T     DID [AR1,P#2.0]

//INT 4 Ziffern nach ASCII
      L     #i                          //INT 0..9999, z.B. 1234
      DTB                               //00_00_12_34 (BCD)
      SLD   4                           //00_01_23_40
      SRW   4                           //00_01_02_34
      SLD   12                          //10 23_40_00
      SRW   4                           //10_23_04_00
      SRD   4                           //01_02_30_40
      SRW   4                           //01_02_03_04 (Hex)
      L     '0000'
      OD                                //in ASCII-Chars '1234' wandeln
      T     DID [AR1,P#5.0]             //'1234' in String eintragen
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
falls du mit "Datenbank" einen DB-Baustein meinst: "DB" bedeutet nicht "Datenbank" sondern "Datenbaustein"
Ich meinte natürlich Datenbaustein. Sorry für die falsche Wortwahl.

Nach einem einem erneuten nachgucken hatte ich tatsächlich nicht dran gedacht die entsprechen Hilfs FC's mit in die Steuerung zu laden.
Dann hatte ich ja Glück, dass die CPU nicht in STOP gegangen ist.

Jetzt funktioniert das Script zumindest so wie es soll.

Also Lösung für mein Problem:
  1. Variable initiieren tmp := ''; Danke an Larry und PN/DP
  2. Hilfs FC's in die Steuerung laden nicht vergessen. Danke an Wincctia
Ich werde da auf jeden Fall die STRING Längen noch anpassen, damit der Speicherplatz nicht ganz so unnötig verramscht wird.

@PN/DP
Deine Varianten sind vom Speicherverbauch wesentlich effizienter. Nur leider verstehe ich auf Anhieb die AWL Anweisungen nicht, da ich bestenfalls mit AWL nichts zu tun habe :D
Ich werde mir das aber dennoch mal anschauen und versuche mir das anzueignen.

Nachtrag: 3 der 4 Hilfs FC's waren so oder so schon im Programm benutzt. Ich habe leiglich CONCAT neu einfügen müssen.
 
Zuletzt bearbeitet:
Die Funktion INT_TO_STRING erzeugt in in S7-classic SCL falsche Längeninformationen.
Ganz im Detail hab ich es nicht nachverfolgt aber ich bin vor ca. 3 Wochen auf so ein Thema gestoßen.
Es lässt sich definitiv reproduzieren wenn das Ziel ein längenbeschränkter String ist im Temp-Bereich ist.
DINT_TO_STRING ist es auch so.

Die LEN-Instruktion liefert dann Mist.

Ich hab beim Runterportieren auch feststellen müssen, dass SCL in S7-classic auch ein Problem damit hat, wenn man Strings, die man einem FC als Eingang mitgibt, innerhalb dieses FC direkt einem Bausteinaufruf mitgibt, geht das schlicht nicht.

Generell ist der SCL Compiler für S7-300/400 in TIA viel mächtiger und effizienter sls jener in classic. Man kann sich beim Runterportieren nicht drauf verlassen dass alles geht.
 
@maxder2te : so ganz kann das aber nicht sein was du schreibst - ob nun Classic oder TIA ... es werden ja für die genannten Funktion FC's herangezogen ... und die verhalten sich bei derselben CPU in TIA nicht anders als in Classic ... kann ja nicht ...

Das mit den Längenbeschränkten Strings hatte ich aber auch schon - es ist hier aber möglich, dass Siemens das für die 1500er CPU's etwas modifiziert hat ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@maxder2te : so ganz kann das aber nicht sein was du schreibst - ob nun Classic oder TIA ... es werden ja für die genannten Funktion FC's herangezogen ... und die verhalten sich bei derselben CPU in TIA nicht anders als in Classic ... kann ja nicht ...
Ja das kann nicht sein und ich hab das geträumt.

Spannenderweise lief der gleiche Code auf S7-300 V3.2 fehlerfrei, auf S7-400 V5.3 und V6.0 gabs das o.g. Problem. SCL Code ist 20 Jahre alt und war ursprünglich für Codesys 2.3 geschrieben.
Ich hab das schnell in 2 Stunden versucht zu finden und gefixt während mir 10 Leute vom Kunden per Anydesk zugesehen haben.

Der o.g. funktionierende Lösungsansatz mit tmp := ''; ist auch nicht ganz logisch für mich. Der Umgang mit Strings in S7-classic und das was der SCL Compiler damit macht ist nicht immer nachvollziehbar.
 
Ja das kann nicht sein und ich hab das geträumt.
das wollte ich damit nicht sagen ...
Spannenderweise lief der gleiche Code auf S7-300 V3.2 fehlerfrei, auf S7-400 V5.3 und V6.0 gabs das o.g. Problem.
300 und 400 sind natürlich stellenweise auch schon wieder unterschiedliche Welten ...
Der o.g. funktionierende Lösungsansatz mit tmp := ''; ist auch nicht ganz logisch für mich.
Durch diese "Krücke" trägt der SCL-Compiler bei dem deklarierten String die Längeninfo ein. Warum das aber nicht schon gleich beim Deklarieren passiert erschließt sich mir auch nicht ...


Ist halt Siemens ...
 
Die Funktion INT_TO_STRING erzeugt in in S7-classic SCL falsche Längeninformationen.
Hmm, sowas habe ich noch nie erlebt. Das glaube ich erst, wenn ich einen dies bestätigenden Code sehe.
Ich denke eher, da wird ebenfalls ein fehlendes Initialisieren die Ursache sein.
Bugs und Funktionsänderungen in String-Funktionen sind eher eine Spezialität der TIA-Versionen.

Der o.g. funktionierende Lösungsansatz mit tmp := ''; ist auch nicht ganz logisch für mich.
Das ist eigentlich sehr logisch. Wenn in einem String-Header die max Länge = 0 drin steht, dann darf keine String-Funktion in diesen String schreiben. Bei der Deklaration in TEMP wird der Speicherplatz des String nicht initialisiert (genau so wie bei anderen Datentypen), erst bei einer Zuweisung einer String-Konstante wird der String-Header initialisiert.
 
Zurück
Oben