SCL Stringvergleich indirekt aus DB

MFreiberger

Level-3
Beiträge
2.854
Reaktionspunkte
758
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin

ich habe folgende Frage:

Wie kann ich in SCL einen Stringvergleich machen mit einer Stringvariablen (INPUT) und einer Stringvariablen (indirekt aus zwei DB´s)?

Hintergrund:
Ich möchte zwei DB´s nach einem Rezeptnamen durchsuchen. Dabei soll pro Zyklus eine Suchschleife nur 40 Loops haben (wg. Zykluszeitüber- wachung). Ich habe 1000 Rezepte pro DB = 2000 Rezepte insgesamt.

mfg

MFreiberger
 
Mir ist noch nicht ganz klar, wo du dabei das Problem siehst? In der IEC-Library gibt es dafür eine Funktion, den FC10.

Die Funktion FC 10 vergleicht die Inhalte zweier Variablen im Format STRING auf gleich und gibt das Vergleichsergebnis als Rückgabewert aus. Der Rückgabewert führt Signalzustand "1", wenn die Zeichenkette am Parameter S1 gleich der Zeichenkette am Parameter S2 ist. Die Funktion meldet keine Fehler.

Wie genau soll die Suche ablaufen?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin Ralle,

mein Problem: Ich weiß nicht, wie ich indirekt auf die Stringvariable im DB zugreifen soll. Geht das über POINTER?

Die Suche soll folgendermaßen aussehen:
1. Suche anstossen
2. 1. SPS-Zyklus 40 Datensätze durchsuchen
2. SPS-Zyklus weiter 40 Datensätze durchsuchen
...
50. SPS-Zyklus die letzten 40 Datensätze im 1. DB durchsuchen
3. 2. DB...
4. Datensatz nicht gefunden: Info
Datensatz gefunden: suche abbrechen, Info und Datensatz an
Übergabe-DB senden.

Hinweis:
Die Suche ist nicht zeitkritisch und ich möchte die Zykluszeitüberwachung ungern auf einen höheren Wert stellen.
 
Hallo,
du kannst in SCL die Strings (auch eines fremden DB's) direkt ansprechen.
Z.B. so :
Code:
Test := DB5.Datensatz_1 ;
Datensatz_1 ist hierbei der symbolische Name des Strings im DB5.
Test sollte die gleiche Größe haben ...


Gruß
LL
 
Nachsatz:
Wenn dein Quell-DB ein ARRAY of String beinhaltet, dann kannst du sogar die ARRAY-Elemente direkt indexieren.

Wenn du mit mehreren Durchläufen arbeiten willst, dann solltest du dir deinen letzten Index merken ... (vielleicht in der Instanz deines FB).

Gruß
LL
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
du kannst in SCL die Strings (auch eines fremden DB's) direkt ansprechen.
Z.B. so :
Code:
Test := DB5.Datensatz_1 ;
Datensatz_1 ist hierbei der symbolische Name des Strings im DB5.
Test sollte die gleiche Größe haben ...


Gruß
LL

Leider kannst du mit dieser Methode nur direkt einen DB adressieren, willst du noch einen 2. DB vergleichen, mußt die die gesamte Funktion nochmals programmieren. So ist das leider in SCL.

Ich würde auch versuchen ein Array of String im DB zu halten. Dann mit dem Index jeweils einen String aus dem DB holen und den Vergleich durchführen. Das Ganze in einer Schleife und im nächsten Zyklus an der Stelle fortsetzen, wo der letzte mit seiner Schleife geendet hat.

Sind denn der eingelesene Rezeptstring (aus dem DB) und der Rezeptname den du suchst gleich lang? Wenn nicht mußt du ja den Rezeptstring nicht vergleichen, sonder auch noch durchsuchen.
 
Hallo Larry Laffer,

ich habe es mit folgendem Code versucht (Zunächst einmal der indirekte Zugriff auf einen der DB´s (50 und 51)):

TYPE
Datensatz: STRUCT
Artikel:STRING[8];
Minimum:INT;
Maximum:INZ;
END_STRUCT;
END_TYPE



FUNCTION_BLOCK FB50

VAR

Durchlauf_pro_Zyklus : INT;
Zyklus : INT;
Datensatznummer : INT;
Suche_in_DB : WORD;
Rezept:Datensatz;
DB_Artikel:STRING[8];

END_VAR

Suche_in_DB := w#16#32; //DB-Index
Datensatznummer := Durchlauf_pro_Zyklus*Zyklus; //Datenoffset-Index

Rezept := WORD_TO_BLOCK_DB(Suche_in_DB).Datensatz:confused:[Datensatznummer];

DB_Artikel := Rezept.Artikel;

END_FUNCTION_BLOCK



Beim Übersetzen erhalte ich folgende Fehlermeldung: "ungültige Variable".
Dabei zeigt er dann auf die Position des Smilies.
Wenn ich folgende Zeile schreibe:

Rezept := DB50.Datensatz[Datensatznummer];

gibt es keinen Fehler.

Jetzt weiß ich nicht was für eine Variable ich nutzen muß?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Rezept := WORD_TO_BLOCK_DB(Suche_in_DB).Datensatz[Datensatznummer];

Das ist leider so bei SCL nicht möglich, wie ich schon schrieb.

Rezept := DB50.Datensatz[Datensatznummer];

Das geht, denn SCL findet beim übersetzen den DB50 und findet darin die definierte Variable/Struct "Datensatz".

Wenn du den DB variabel halten willst, mußt du auch auf den Inhalt des DB mit Absolutzugriffen ansprechen. Da geht dann bei String eigentlich nicht bzw. nur über wirkliche Indirekte Adressierung.

Entweder du schreibst für jeden DB eine eigene SCL-Funktion oder du suchst mal im Forum hier nach "SCl + Any", das könnte weiterhelfen.
 
Zuletzt bearbeitet:
Entweder du schreibst für jeden DB eine eigene SCL-Funktion oder du suchst mal im Forum hier nach "Any und SCL", das könnte weiterhelfen.

Der Nachteil beim Arbeiten mit dem ANY-Pointer (oder errechneten Zugriffen) ist m.E., dass man sich den String, mit dem man arbeiten möchte erst bilden muss. Das entfällt bei der absoluten Adressierung.

@MFreiberger:
Für mich hat Ralle das Problem noch nicht nachdrücklich genug beschrieben. Du kannst innnerhalb von SCL bei solchen Zugriffen (wie von dir benötigt) nur mit bekannten Strukturen arbeiten. Bekannt heißt hierbei : "Beim Übersetzen des SCL-Codes bekannt".

Eine Idee hätte ich noch :
Man könnte den DB als UDT erzeugen. Der Aufbau des UDT wäre dann vorgegeben und auch für SCL zugänglich (ggf. mit AT eine Beziehung herstellen). Das zu probieren wäre vielleicht einen Versuch wert ...

Gruß
LL
 
... ich habe das gerade mal gegen-gecheckt ...

Wenn ich die Datenstruktur als UDT anlege und den Eingangsparameter vom Typ her als diese UDT angebe und die UDT im DB anlege, dann geht es ...
Code:
VAR_INPUT
   Quell_DB1 : UDT14 ;
   Quell_DB2 : UDT14 ;
   Quell_DB3 : UDT14 ;
end_VAR
 
und im Code dann :
 
Test_Var := QuellDB1.Datensatz[11] ;
der Datenbaustein sieht dann so aus :
Code:
Adresse 0.0 :
Daten : UDT14
der Aufruf für den FB sieht dann so aus :
Code:
call FB500 , DB500
   Quell_DB1 := DB11.Daten
   Quell_DB2 := DB21.Daten
   Quell_DB3 := DB31.Daten

Vielleicht hilft es ja weiter ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin zusammen,

Ich habe mir folgendes überlegt:
Da ich nur 2 DB´s habe und die DBNr feststeht, mache ich einfach zwei Schleifen, adressiere den jeweiligen DB absolut und ändere dynamisch die Zugriffsadresse.

Vielleicht hat ja jemand noch eine andere Idee...

Auf jeden Fall vielen Dank für die Hilfe, jetzt weiß ich wenigstens was geht und was nicht.;)
 
... ich habe das gerade mal gegen-gecheckt ...

Wenn ich die Datenstruktur als UDT anlege und den Eingangsparameter vom Typ her als diese UDT angebe und die UDT im DB anlege, dann geht es ...
Code:
VAR_INPUT
   Quell_DB1 : UDT14 ;
   Quell_DB2 : UDT14 ;
   Quell_DB3 : UDT14 ;
end_VAR
 
und im Code dann :
 
Test_Var := QuellDB1.Datensatz[11] ;
der Datenbaustein sieht dann so aus :
Code:
Adresse 0.0 :
Daten : UDT14
der Aufruf für den FB sieht dann so aus :
Code:
call FB500 , DB500
   Quell_DB1 := DB11.Daten
   Quell_DB2 := DB21.Daten
   Quell_DB3 := DB31.Daten

Vielleicht hilft es ja weiter ...

Wenn das so geht, dann ist das wirklich gut !!!
 
Er hat die Variablen-Deklarationen, die im DB stehen in eine UDT reingeschrieben. Im DB wird nur noch die UDT deklariert, als "Daten". Im SCl-Baustein hat er nun diese UDT als Input deklariert. Nun kannst du beim Aufruf an den FB die UDT ranschreiben, die sich ja jeweils in einem anderen DB befindet. Im SCL-Baustein kannst du mit diesen UDT-Daten intern weiterarbeiten.

@Larry

Hast du mal versucht, eine dieser UDT-Variable an eine weitere Funktion (Stringcompare) weiterzureichen, geht das? Wenn nicht müßte man diesen String dann doch vorher nochmal umkopieren.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
@Larry
Hast du mal versucht, eine dieser UDT-Variable an eine weitere Funktion (Stringcompare) weiterzureichen, geht das? Wenn nicht müßte man diesen String dann doch vorher nochmal umkopieren.

Nein ... das habe ich nicht versucht ...
Aus dem Bauch heraus würde ich aber sagen : "Lieber umkopieren ..." Die String-FC's von Siemens sind ja schließlich nicht so ganz ohne ...

Gruß
LL
 
Nach ein bisschen versuchen scheint dies zu funktionieren. Am mindestens kompiliert es ohne Fehler.

Keine UDTs wird verwendet. Nur ein ARRAY[0..99] of STRING.
Es scheint das man die STRING's nicht auf z.b. STRING[20] begrenzen kann. Dann fängt EQ_STRNG an zu meckern.

Code:
FUNCTION FC1 : VOID
VAR_INPUT
  strSearch : STRING ;
END_VAR
VAR_OUTPUT
  biMatchFound: BOOL ;
  iMatchIndex: INT ;
END_VAR
VAR_TEMP
  i: INT;
  strCompare1 : STRING ;
END_VAR
 
    biMatchFound := FALSE ;
    iMatchIndex := 0 ;
    i := 0 ;
    strCompare1 := strSearch  ; // zuerst zum TEMP Variabel übertragen. Sonnst gibt es fehler mit EQ_STRNG. Warum eigentlich ?
    WHILE biMatchFound = FALSE AND i < 100  DO
        biMatchFound := EQ_STRNG(S1 := strCompare1 , S2 := "Recipe1".StringArray[i] );
        i := i + 1 ;
    END_WHILE;
    IF biMatchFound = TRUE THEN iMatchIndex := i ; END_IF ;
 
END_FUNCTION
 
Zurück
Oben