SCL Stringvergleich indirekt aus DB

Zuviel Werbung?
-> Hier kostenlos registrieren
@Ralle. Das ist klar.

Aber sehr oft ist ein dynamischer zugriff gar nicht notwendig. Wie es von MFreiberger beschrieben ist, hat er 2 DBS die sicherlich feste sind.
Meine erfahrung ist, das wenn man von unnötige Parameter-übertragungen verzichtet, denn vereinfacht sich das kodieren sehr viel.
Keep It Simple.
 
So jetzt habe ich es mit Parameter transfer.
UDT_StringArray enthält ein "Strings" ARRAY[0..99] of STRING[20]

Code:
FUNCTION FC3 : VOID
VAR_INPUT
  strSearch : STRING ;
  strRecipe : UDT_StringArray ;
END_VAR
VAR_OUTPUT
  biMatchFound: BOOL ;
  iMatchIndex: INT ;
END_VAR
VAR_TEMP
  i: INT;
  strCompare1 : STRING ;
  strCompare2 : STRING ;
END_VAR
    
    biMatchFound := FALSE ;
    iMatchIndex := 0 ;
    i := 0 ;
    strCompare1 := strSearch  ;
    WHILE biMatchFound = FALSE AND i < 100  DO
        strCompare2 := strRecipe.Strings[i] ;
        biMatchFound := EQ_STRNG(S1 := strCompare1 , S2 := strCompare2 );
        i := i + 1 ;
    END_WHILE;
    IF biMatchFound = TRUE THEN iMatchIndex := i ; END_IF ;
    
END_FUNCTION
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Idee mit "Any"

Hallo,

hab einiger Zeit habe ich noch eine brauchbare Lösung gefunden:

Code:
FUNCTION_BLOCK FB50
 
(*Variablendeklaration
***************************************************************************************************)
VAR_INPUT                                                                                           //Eingangsvariablen
    IN_suchen:BOOL;
    IN_DBNR:INT;
    IN_DBM:INT; 
    IN_Zyklen:INT;
    IN_Loop:INT;
    IN_DSlen:INT;
    IN_Stringlaenge:INT;
    IN_Artikel:STRING;
END_VAR
VAR_OUTPUT                                                                                          //Ausgangsvariablen
    OUT_busy:BOOL;
    OUT_gefunden:BOOL;
    OUT_DB:INT; 
    OUT_DBB:INT; 
END_VAR
VAR                                                                                                 //Statische Variablen
    STAT_suchen:BOOL;
    STAT_busy:BOOL;
    STAT_gefunden:BOOL;;
    STAT_DBB:INT;
    STAT_Loop:INT;
    STAT_Zyklus:INT;
    STAT_DSNR:INT;
    STAT_DBNR:INT;
    STAT_DBM:INT;
    STAT_For_Min:INT;
    STAT_For_Max:INT;   
    STAT_Zyklen:INT;
    STAT_LoopSoll:INT;
    STAT_DSlen:INT;
    STAT_Stringlaenge:INT;
    STAT_DB_Artikel:STRING;
END_VAR
VAR_TEMP                                                                                            //Temoräre Variablen
       TEMP_Source : ANY;                                                                           //Any Quellzeiger
    VON AT TEMP_Source: STRUCT                                                                      //AT-Befehl: Die einzelnen Bestandteile der vorhergehenden Variablen werden in einer Struktur aufgeschlüsselt
    ID  : WORD;
    NBR : INT;
    DBN : INT;
    PTR : DWORD;
    END_STRUCT;
       TEMP_DESTIN : ANY;                                                                           //Any Zielzeiger
    NACH AT TEMP_DESTIN: STRUCT                                                                     //AT-Befehl: Die einzelnen Bestandteile der vorhergehenden Variablen werden in einer Struktur aufgeschlüsselt
    ID  : WORD;
    NBR : INT;
    DBN : INT;
    PTR : DWORD;
    END_STRUCT;
        TEMP_DB_Artikel:STRING;                                                                     //Vergleichsstring
    Aufbau AT TEMP_DB_Artikel: STRUCT
    MAXlen:BYTE;
    ISTlen:BYTE;
    Zeichen:ARRAY[1..254] OF BYTE;
    END_STRUCT;
    TEMP_SFC_Err:INT;
    TEMP_Faktor:DINT;
    TEMP_Produkt:DINT;
END_VAR
 
(*Initialisierung
****************************************************************************************************)
STAT_Zyklen := IN_Zyklen;                                                                           //Eingangswerte an statische Variablen übergeben
STAT_LoopSoll := IN_Loop;
STAT_Stringlaenge := IN_Stringlaenge;
STAT_DSlen := IN_DSlen;
STAT_DBM := IN_DBM;
(*Programmcode
****************************************************************************************************)
IF (STAT_busy = false) AND (IN_suchen <> STAT_suchen) AND (IN_suchen = true) THEN                   //Suche Starten wenn nicht aktiv und Startflanke
    STAT_busy := true; 
    STAT_gefunden := false;                                                                             //Suche aktiv setzen
    STAT_Zyklus := 0;                                                                               //Zyklusanzahl initialisieren
    STAT_DBNR := IN_DBNR;     
END_IF;
IF (STAT_busy = true) AND (STAT_Zyklus < STAT_Zyklen) AND (STAT_DBNR < (IN_DBNR + STAT_DBM))THEN    //Bedingung: Suchen gestartet und Anzahl Zyklen und DB´s < SOLL
 
            STAT_For_Min := STAT_Zyklus * STAT_LoopSoll;                                            //FOR-Schleife Minimum = Suchzyklus * Anzahl der Durchläufe pro Zyklus
            STAT_For_Max := STAT_For_Min + STAT_LoopSoll;                                           //FOR-Schleife Maximum = Minimum + Anzahl der Durchläufe pro Zyklus
 
            FOR STAT_Loop := STAT_For_Min TO STAT_For_Max DO                                        //FOR-Schleife von Minimum bis Maximum. STAT_Loop: Wert des aktuellen Durchlaufs    
 
                STAT_DSNR := STAT_Zyklus + STAT_Loop;                                               //Die aktuelle Datensatznummer ergibt sich aus der Anzahl der Zyklen und Loops
                TEMP_Faktor := 8 * STAT_DSlen;                                                      //Faktor: 8 (für Bit) * Datensatzlänge in BYTE        
                TEMP_Produkt := STAT_DSNR * TEMP_Faktor;                                            //TEMP_Produkt: Offset des aktuellen Datensatzes
 
                VON.ID := w#16#1002;                                                                //10: "Siemens"; 02: Datentyp BYTE
                VON.NBR := (STAT_Stringlaenge + 2);                                                 //Anzahl der zu Übertragenden Bytes
                VON.DBN := STAT_DBNR;                                                               //aktuelle Datenbausteinnummer
                VON.PTR := DINT_TO_DWORD(TEMP_Produkt) OR 16#8400_0000;                             //keine Berechnung für DINT_TO_DWORD, deshalb Berechnung vorher 84: Speicherbereich Datenbaustein
 
                NACH.ID := w#16#1002;                                                               //10: "Siemens"; 02: Datentyp BYTE
                NACH.NBR := (STAT_Stringlaenge + 2);                                                //Anzahl der zu Übertragenden Bytes
                NACH.DBN := 0;                                                                      //"0", da Instanzdatenbaustein
                NACH.PTR := INT_TO_WORD(302 * 8) OR 16#8500_0000;                                   //Achtung: Offset abhängig von IDB-Aufbau; 85: Speicherbereich Instanzdatenbaustein
 
                TEMP_SFC_Err := BLKMOV(SRCBLK := TEMP_Source, DSTBLK := TEMP_DESTIN);               //SFC20 "Blockmove" Quellzeiger in Zielzeiger. Rückgabewert: Bearbeitungsfehler
                TEMP_DB_Artikel := STAT_DB_Artikel;                                                 //von Any "NACH" wird auf STAT_DB_Artikel gezeigt und dieser dann in TEMP_DB_Artikel geschrieben
                Aufbau.ISTlen := INT_TO_BYTE(STAT_Stringlaenge);                                    //Istlänge des Strings wird beschrieben damit der Vergleich korrekt durchgeführt wird.
 
                IF IN_Artikel = TEMP_DB_Artikel THEN                                                //Stringvergleich (benötigt FC10 "EQ_STRING" Bibliothek: IEC)
                    STAT_gefunden := true;                                                          //Bei "TRUE":   -Artikel gefunden
                    STAT_busy := false;                                                             //              -Suche beenden        
                    OUT_DBB := STAT_DSlen*STAT_DSNR;                                                //              -Offsetwert des Speicherbereichs im DB
                    OUT_DB := STAT_DBNR;                                                            //              -Datenbausteinnummer  
                    EXIT;                                                                           //              -Schleife beenden
                ELSE                                                                                
                    STAT_gefunden := false;                                                         //Bei "FALSE":  -Artikel nicht gefunden
                END_IF;
            END_FOR;
            STAT_Zyklus := STAT_Zyklus + 1;                                                         //Zyklus durchlaufen: 1 Zyklus addieren
ELSE
 
    STAT_busy := false;                                                                             //Suche beenden
END_IF;
IF STAT_Zyklus >= STAT_Zyklen THEN                                                                  //Alle Datensätze dieses DB´s geprüft
 
    STAT_Zyklus := 0;                                                                               //Zykluszähler resetten
    STAT_DBNR := STAT_DBNR + 1;                                                                     //DB durchlaufen: 1 Db addieren        
END_IF;
 
STAT_suchen := IN_suchen;                                                                           //Flankenmerker zum Suchstart neu beschreiben
(*Ausgaben
***********************************************************************************************)
OUT_busy := STAT_busy;                                                                              //Ausgang suche läuft
OUT_gefunden := STAT_gefunden;                                                                      //Ausgang STRING gefunden
 
END_FUNCTION_BLOCK
 
Hallo,
schön, wenn du jetzt eine für dich brauchbare Lösung hast ...
Trotzdem kann ich es mir nicht verkneifen ... die Sache mit dem Any-Pointer und dem BlockMove sowie die ganze fest indizierte Programmierung hättest du dir ersparen können, wenn du meinen Vorschlag aufgegriffen hättest. Dort wäre es für dich möglich gewesen, auf die Elemente des "externen" DB's direkt (symbolisch) zuzugreifen. Möglicherweise wäre das auch von der Bearbeitungszeit günstiger ausgefallen ...

Gruß
LL
 
Zurück
Oben