Step 7 Ein Array of Char im DB suchen und kopieren

tommylik

Level-2
Beiträge
130
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Servus,

Dieser FC ist mit Euer Hilfe entstanden.

Macht seit fast 3 Jahren sein Job und braucht jetzt eine Erweiterung, die mich überfordert.

Code:
FUNCTION X_FC2395_Code_suchen : VOID

TITLE = 'Suche'

//
// Baustein-Kommentar ...
//

VERSION : '1.0'
AUTHOR  : author
NAME    : name
FAMILY  : family

// Bausteinparameter

VAR_INPUT
Start_suchen           : BOOL;                                 // Trigger Signal
PrCode                   : ARRAY[1..12] OF CHAR;      // 8 Byte werden nur genutzt

END_VAR

VAR_IN_OUT
// Durchgangsparameter
END_VAR

VAR_OUTPUT
// Ausgangsparameter
PrCode_gefunden        : BOOL;    // niO Prägecode im Datenbaustein gefunden BT wird ausgeschleust
Done                            : BOOL;    // DB durchsucht und kein Prägecode gefunden

END_VAR

VAR_TEMP
// temporäre Variablen
i                   : INT;
END_VAR

BEGIN

PrCode_gefunden := FALSE;
IF Start_suchen THEN

FOR i := 1 TO 127 DO

IF "X_DB2390_NIOTeile".Teil[i].PraegeCode[1] = PrCode[1]
AND "X_DB2390_NIOTeile".Teil[i].PraegeCode[2] = PrCode[2]
AND "X_DB2390_NIOTeile".Teil[i].PraegeCode[3] = PrCode[3]
AND "X_DB2390_NIOTeile".Teil[i].PraegeCode[4] = PrCode[4]
AND "X_DB2390_NIOTeile".Teil[i].PraegeCode[5] = PrCode[5]
AND "X_DB2390_NIOTeile".Teil[i].PraegeCode[6] = PrCode[6]
AND "X_DB2390_NIOTeile".Teil[i].PraegeCode[7] = PrCode[7]
AND "X_DB2390_NIOTeile".Teil[i].PraegeCode[8] = PrCode[8] THEN

PrCode_gefunden := True;

EXIT;
END_IF;
END_FOR;

Done := NOT PrCode_gefunden;

END_IF;
END_FUNCTION

Der UDT wurde erweitert und es sind 0..127 Array of UDT Aufrufe im DB. Der UDt ist 204 Byte groß.
Die Erweiterung, die ich bräuchte, sieht wie folgt aus.
Die alte Suche bleibt die gleiche, der Ausgang soll auch weiterhin gesetzt werden.
Hinzukommen soll:
Wird etwas gefunden, dann soll der UDT in dem Array wo es gefunden wurde in einen anderen DB kopiert werden.

So ähnlich habe ich schon mal in einem anderen FC etwas kopiert.
Es soll aber einfacher gehen. Aber ich weiß nicht ob ich das hierfür überhaupt nutzen kann.

Code:
IF Bedingung AND NOT Bedingung THEN
                    
    ret_val_SFC20  :=  BLKMOV(SRCBLK :=  QuellDB, DSTBLK :=  ZielDB);  //kopieren
           
END_IF;

Was ich aber überhaupt nicht weiß und deswegen frage ich Euch, ist wie ich die Startadresse von dem Array der Fundstelle herausfinde.
Ich vermute mit dem Schleifenzähler von der Suche?? Der Suchbereich befindet sich immer in den ersten 36 Byte von einem Array.
0 bis 35
204 bis 239
usw...

Im Anhang ist ein Bild mit dem Aufbau vom UDT und ein paar Erklärungen.

Dann noch eine Frage kann man eine DB Nr. als Inputvariable anlegen?
Ich würde gerne anstatt "X_DB2390_NIOTeile".Teil.PraegeCode[1] besser DB_Nr.Teil.PraegeCode[1] schreiben, damit ich diesen FC öfters aufrufen kann.
Wer von Euch wäre so nett und hilft mir bei meinem Dilemma.

Viel Dank

Grüße Tommylik
 

Anhänge

  • Screenshot 2024-12-04 202812.jpg
    Screenshot 2024-12-04 202812.jpg
    193,6 KB · Aufrufe: 23
Tmp_c:= 0;
Tmp_a :=0;
Abort := false;
For c := x to y by 1 do
For a := x to y by 1 do
If xxx[c].bbb[a] = code[a] then
Tmp_a := a;
Abort := true;
Exit;
End_if;
End_for;

If abort then
Tmp_c := c;
Exit;
End_if;
End_for;


Sorry, irgendwie funktionieren die code tags nicht..

DEine Datenstrukturen aus den dbs könntest du als InOut übergeben, sofern es udts sind
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Mrtain,

Vielen Dank für deine schnelle Antwort und für den Code.
Ist dieses Beispiel für das kopieren oder für beides.
Ich habe Schwierigkeiten ihn zu verstehen. Könntest du bitte ein paar Kommentare noch reinschreiben,

Vielen Dank nochmal.
 
Servus,

Ich habe probiert, ob der alte Code mit dem neuen DB (neuer UDT) funktioniert.
Es geht und somit brauche ich keine neue Suchfunktion.

Als Nächstes habe ich mir eine Variable "Fundstelle" angelegt.
Nachdem (PrCode_gefunden := True;) wenn was gefunden wurde, speichere ich den Schleifenzähler ab.
Mit IF und "True" kopiere ich die ("X_DB2388_Prodfehler".Teil[Fundstelle]) in den ZielDB.

Ich habe meine Idee in den alten Code eingebaut, siehe unten, es ist rot eingerahmt.
Ist das richtig? Ich traue mich nicht zu testen, da ich keinen CPU-Stopp riskieren möchte.

Code:
FUNCTION X_FC2396_Code_suchen_2 : VOID
TITLE = 'Suche'
//
// Baustein-Kommentar ...
//
VERSION : '1.0'
AUTHOR  : author
NAME    : name
FAMILY  : family

// Bausteinparameter
VAR_INPUT
    Start_suchen           : BOOL;                  // Trigger Signal
    PrCode                 : ARRAY[1..12] OF CHAR;               
END_VAR

VAR_IN_OUT
    // Durchgangsparameter
    ZielDB                  : ANY; <------------------- Neu
    
END_VAR

VAR_OUTPUT
    // Ausgangsparameter
    PrCode_gefunden        : BOOL;    // Prägecode im Datenbaustein gefunden BT wird ausgeschleusst
    Fundstelle             : INT;     // An welcher Stelle wurde der Code gefunden. Schleifenwert <------------------- Neu
    Done                   : BOOL;    // DB durchsucht und kein Prägecode gefunden
      
END_VAR

VAR_TEMP
    // temporäre Variablen
       i                   : INT;         
END_VAR

BEGIN

PrCode_gefunden := FALSE; 

IF Start_suchen THEN     
    
    FOR i := 1 TO 127 DO   
        IF "X_DB2388_Prodfehler".Teil[i].x27MS01.PraegeCode[1] = PrCode[1]
            AND "X_DB2388_Prodfehler".Teil[i].x27MS01.PraegeCode[2] = PrCode[2]
            AND "X_DB2388_Prodfehler".Teil[i].x27MS01.PraegeCode[3] = PrCode[3]
            AND "X_DB2388_Prodfehler".Teil[i].x27MS01.PraegeCode[4] = PrCode[4]
            AND "X_DB2388_Prodfehler".Teil[i].x27MS01.PraegeCode[5] = PrCode[5]
            AND "X_DB2388_Prodfehler".Teil[i].x27MS01.PraegeCode[6] = PrCode[6]
            AND "X_DB2388_Prodfehler".Teil[i].x27MS01.PraegeCode[7] = PrCode[7]
            AND "X_DB2388_Prodfehler".Teil[i].x27MS01.PraegeCode[8] = PrCode[8] THEN
                
            PrCode_gefunden := True;
#########################################################################                        
            IF PrCode_gefunden = true THEN
                
                Fundstelle := i;
              
                ZielDB := "X_DB2388_Prodfehler".Teil[Fundstelle];
                
            END_IF;         
#########################################################################            
            EXIT;
            
        END_IF;       
              
    END_FOR;
        Done := NOT PrCode_gefunden;
END_IF;

END_FUNCTION

Was aber noch sehr wichtig wäre, ob man eine DB Nr. als Inputvariable anlegen kann?
Weil so kann ich diesen FC nur mit diesen DB nutzen ("X_DB2388_..........)

Hat einer von Euch eine Idee für mich?

Grüße, Tommylik
 
Servus,

@Januar
vielen Dank. Ja, das wäre eine gute Möglichkeit, aber in der Woche darf ich nichts an der Anlage testen, nur am Wochenende.

@circlehook
Vielen Dank habe ich ausprobiert und CPU Stopp bekommen.

Die Diagnose sagt, dass ich den DB4098 nicht geladen habe. Das kann nicht sein, wir haben keine DBs mit diesen Nummern.

Es liegt an dieser Zeile. Wenn ich sie auskommentiere, dann habe ich keinen CPU-Stopp.
//ZielDB := "X_DB2388_Prodfehler".Teil[Fundstelle];
Ich schaffe es nicht den ganzen UDT auf den ZielDB zu kopieren.

Diese Zeile funktioniert glaube ich auch nicht.
Fundstelle := i;

Ich habe im DB einen Datensatz präpariert, dass die Variable Fundstelle den Wert 2 haben müssen.

Variabletabelle:

1733404368655.png

Fundstelle 2

1733403314082.png

1733403845772.png

Wer kann mir bitte sagen, wie der Code richtig aussehen muss?

Vielen Dank nochmal für die Hilfe.

Tommylik
 
Ich weiß nicht, ob ich es ganz verstehe aber deine Quell-/ und Zieldaten haben den gleichen UDT, oder?

Du kannst dein Array of UDT (welches du durchsuchen willst) und dein Ziel als UDT an deinen FC per IN/OUT übergeben.

Dein Such-Array kopierst du dann vor der Suche in die Temp-Daten des FC's, danach suchst du in den Temp-Daten nach deiner Nummer.
Falls deine Suche erfolgreich ist, übergibst du einfach im FC den gefundenen Datensatz an deinen Zieldatensatz.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Servus circlehook,

Vielen Dank für deine Antwort.

Ja genau Quell-/ und Zieldaten haben den gleichen UDT. Die Übergabe als IN/OUT ist einfach.
Aber den Teil mit den Temp Daten ist zu kompliziert für mich.
Das heißt ich muss alles neu machen weil ich den Temp-Bereich nutzen muss. Wie soll ich das anstellen?
die FOR Schleife vergleicht die 8 Zeichen und findet einen Datensatz z.B. bei der Adresse 420 bis 427.
Der UDT beginnt weil es das Array 2 ist bei Adresse 408. Wie soll ich mit 408 auf Array 2 schließen da fehlt mir die Logik.

Vielleicht hast du ja einen Link für mich wo schon etwas ähnliches gemacht wurde.

Vielen Dank für deine Hilfe
 
Ich habe jetzt deinen Code von weiter oben genutzt als Vorlage, ob dieser soweit noch passt, weiß ich nicht.
So in etwa könnte man es machen.

Code:
// Bausteinparameter
VAR_INPUT
    Start_suchen           : BOOL;                  // Trigger Signal
    PrCode                 : ARRAY[1..12] OF CHAR;               
END_VAR

VAR_IN_OUT
    // Durchgangsparameter
    QuellDaten              : ARRAY[x..x] OF "UDT_DATA";
    ZielDB                  : "UDT_DATA"
        
END_VAR

VAR_OUTPUT
    // Ausgangsparameter
    PrCode_gefunden        : BOOL;    // Prägecode im Datenbaustein gefunden BT wird ausgeschleusst
    Fundstelle             : INT;     // An welcher Stelle wurde der Code gefunden. Schleifenwert <------------------- Neu
    Done                   : BOOL;    // DB durchsucht und kein Prägecode gefunden
      
END_VAR

VAR_TEMP
    // temporäre Variablen
       i                   : INT;         
       tmpQuellDaten       : ARRAY[x..x] OF "UDT_DATA";
      
END_VAR

BEGIN

tmpQuellDaten:= QuellDaten;

PrCode_gefunden := FALSE; 

IF Start_suchen THEN     
    
    FOR i := 1 TO 127 DO           
        IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[1] = PrCode[1] THEN
            IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[2] = PrCode[2] THEN
                IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[3] = PrCode[3] THEN
                    IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[4] = PrCode[4] THEN
                        IF  tmpQuellDaten.Teil[i].x27MS01.PraegeCode[5] = PrCode[5] THEN
                            IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[6] = PrCode[6] THEN
                                IF  tmpQuellDaten.Teil[i].x27MS01.PraegeCode[7] = PrCode[7] THEN
                                    IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[8] = PrCode[8] THEN

                                        PrCode_gefunden := True;
                                        Fundstelle := i;
                                        ZielDB := tmpQuellDaten.Teil[Fundstelle];
                                        EXIT;
                                        
                                    END_IF;
                                END_IF;
                            END_IF;
                        END_IF;
                    END_IF;
                END_IF;
            END_IF;
        END_IF;
    END_FOR;
        Done := NOT PrCode_gefunden;
END_IF;

END_FUNCTION
 
Hallo Circlehook,

Vielen Dank für deine Mühe und für den Code.

So einfach holt man sich mit SCL die Daten in den Temp-Bereich.
Kannst du mir noch erklären warum den Temp-Bereich nutzen muss?
Ich kann es erst morgen testen oder sogar erst am Montag habe keine Step7 hier

Vielen Dank nochmal.

Schon mal vorab ein schönes Wochenende.

Grüße Tommylik
 
Servus Circlehook,

Habe deinen Code in 2 Varianten übernommen, weil es beim Übersetzen Probleme gibt.
Als Erstes habe ich mit Array of UDT getestet. Danach mit ANY.


Code:
FUNCTION X_FC2396_Code_suchen_2 : VOID
TITLE = 'Suche'
//
// Baustein-Kommentar ...
//
VERSION : '1.0'
AUTHOR  : author
NAME    : name
FAMILY  : family

// Bausteinparameter
VAR_INPUT
    Start_suchen           : BOOL;                  // Trigger Signal
    PrCode                 : ARRAY[1..12] OF CHAR;               
END_VAR

VAR_IN_OUT
    // Durchgangsparameter
    // QuellDaten             : ARRAY[1..127] OF "S_UDT_1203_TYP_ANLAGE";
     QuellDaten             : ANY;
     ZielDB                 : ANY;
    
END_VAR

VAR_OUTPUT
    // Ausgangsparameter
    PrCode_gefunden        : BOOL;    // Prägecode im Datenbaustein gefunden BT wird ausgeschleusst
    Fundstelle             : INT;     // An welcher Stelle wurde der Code gefunden. Schleifenwert 
    Done                   : BOOL;    // DB durchsucht und kein Prägecode gefunden
      
END_VAR

VAR_TEMP
    // temporäre Variablen
       i                   : INT;
      // tmpQuellDaten       : ARRAY[1..127] OF "S_UDT_1203_TYP_ANLAGE";
       tmpQuellDaten       : ANY;       
END_VAR

BEGIN

tmpQuellDaten := QuellDaten;

PrCode_gefunden := FALSE; 

IF Start_suchen THEN     
    
   FOR i := 1 TO 127 DO           
        IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[1] = PrCode[1] THEN
            IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[2] = PrCode[2] THEN
                IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[3] = PrCode[3] THEN
                    IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[4] = PrCode[4] THEN
                        IF  tmpQuellDaten.Teil[i].x27MS01.PraegeCode[5] = PrCode[5] THEN
                            IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[6] = PrCode[6] THEN
                                IF  tmpQuellDaten.Teil[i].x27MS01.PraegeCode[7] = PrCode[7] THEN
                                    IF tmpQuellDaten.Teil[i].x27MS01.PraegeCode[8] = PrCode[8] THEN

                                        PrCode_gefunden := True;
                                        Fundstelle := i;
                                        ZielDB := tmpQuellDaten.Teil[Fundstelle];
                                        EXIT;
                                        
                                    END_IF;
                                END_IF;
                            END_IF;
                        END_IF;
                    END_IF;
                END_IF;
            END_IF;
        END_IF;
    END_FOR;
        Done := NOT PrCode_gefunden;
END_IF;

END_FUNCTION


1733464943024.png
Das sieht doch gut aus. Was soll daran falsch sein?
Quelldaten:
"X_DB2388_Prodfehler".Teil[0].x27MS01.Praegecode[1]

Liegt das am SCL von Step7?

Grüße, Tommylik
 
Sorry.
Sollte dann im Code wahrscheinlich so sein:

Code:
 tmpQuellDaten[i].x27MS01.PraegeCode[1]

Da die temporäre Variable das Array of UDT ist und nicht noch eine Subkomponente *Teil* hat.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Servus,

Vielen Dank für deine Hilfe.

Ok, das Übersetzen funktioniert.

Hier musste ich auch das Wort "Teil" entfernen.
ZielDB := tmpQuellDaten.[Fundstelle];

Ich habe jetzt aktuell das Problem, dass ich den In/Out für die Quelldaten nicht parametrieren kann.


1733478245146.png


Also Array sollte eigentlich mit Array zusammenpassen.

Ich habe einige Versuche gemacht, das zu parametrieren.

Hast du eine Idee, was noch falsch sein könnte?

Grüße, Tommylik
 
Hallo Januar,

Wie meinst du das?

So ist es im Baustein.

VAR_IN_OUT
// Durchgangsparameter
QuellDaten : ARRAY[1..127] OF "S_UDT_1203_TYP_ANLAGE";
ZielDB : ANY;
END_VAR

QuellDB

1733481307964.png



VAR_TEMP
// temporäre Variablen
i : INT;
tmpQuellDaten : ARRAY[1..127] OF "S_UDT_1203_TYP_ANLAGE";

END_VAR


ZielDB ist als Any festgelegt und macht keine Probleme.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo circlehook,


Allerdings sollte sich das, im Vergleich zu einem Array, nicht zusätzlich
hinderlich auswirken, da sich in FC auch Arrays nicht weiterreichen lassen, siehe Ausszug aus der S7 Onlinehilfe:

Code:
Obwohl kein Typkonflikt zwischen Aktualparameter (rechte Seite) und
Formalparameter (linke Seite) vorliegt, kann diese Parameterzuweisung
nicht zugelassen werden. Folgende Gründe können vorliegen:

...

· Das Maschinenmodell STEP 7 erlaubt die Zuweisung nicht,
z.B. kann ein STRUCT/ARRAY/ANY/UDT/STRING -
INPUT/OUTPUT/IN_OUT - Parameter eines FCs nicht an einen darin
aufgerufenen Baustein weitergereicht werden.


Ich habe diesen Post von Ralle gefunden. Kann das sein?

Aber eigentlich auch nicht. Von den Quelldaten gehen wir auf Tempdaten und von da auf den ZielDB.
 
Zuletzt bearbeitet:
Dein Problem dürfte die inkonsistente Array-Definition sein.

Deinem Baustein sagst du "Du bekommst hier ein Array mit 127 Elemente vom Typ "S_UDT_1203_TYP_ANLAGE"". Allerdings übergibst du dem Baustein ein Array mit 128 Elementen (0-127).

Ohne den Rest des Threads näher verfolgt zu haben, würde ich dir vorschlagen, deine Bausteinschnittstelle auf 0-127 zu ändern.
 
Hallo Januar,

Wie meinst du das?

So ist es im Baustein.

VAR_IN_OUT
// Durchgangsparameter
QuellDaten : ARRAY[1..127] OF "S_UDT_1203_TYP_ANLAGE";
ZielDB : ANY;
END_VAR

QuellDB

Anhang anzeigen 83701



VAR_TEMP
// temporäre Variablen
i : INT;
tmpQuellDaten : ARRAY[1..127] OF "S_UDT_1203_TYP_ANLAGE";

END_VAR


ZielDB ist als Any festgelegt und macht keine Probleme.
Du hast ein Feld mit 127 Elementen (1..127) angegeben, aber die UDT hat 128 Elemente (0..127)
 
Zurück
Oben