DB nach Werten durchsuchen und Adresse des Eintrags herausfinden

saarlaender

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

ich habe eigentlich schon eine Funktion gefunden, welche die Aufgabenstellung lösen kann - der FC86 (TBL_Find). Allerdings benötigt dieser FC86 die Quellangabe als TYP Pointer (kein ANY!), welche ich aber nicht durch einen übergeordneren FC/FB durchreichen kann.

Ich hoffe nun, eine vergleichbare Funktion zu finden - welche dann aber variabel mit einem normalen ANY-Pointer (damit sollte es zumindest dann gehen?!) angesteuert werden kann.



Konkret:
Ich muss einen DB nach bestimmten Werten durchsuchen und dessen Position im DB herausfinden. Diese in sich dann geschlossene "Suchfunktion" soll wiederum in einem überlagerten FC/FB aufgerufen werden. Dem überlagerten FC/FB werden dann die variablen Daten (DB, welcher durchsucht werden soll, Suchmuster, ...) übergeben und an den FC86 durchgereicht.
Das Problem mit dem FC86 ist, dass der Pointer (TYP Pointer, kein Typ ANY) vom überlagerten FC/FB nicht an den FC86 übergeben werden kann - der FC86 braucht wie gesagt die Suchquelle als Typ POINTER...


Die Funktion sollte sowohl Int als auch ggf. STRING suchen bzw finden können.
 
Zuletzt bearbeitet:
Wie wärs wenn du dir den Zeiger im Programm einfach anhand der vorgaben am übergeordneten baustein zusammen baust?

Paar sprünge, paar multiplikatoren, fertig! ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich würde das mit einer Schleife lösen.

Die DB-Länge auslesen und damit die Anzahl der Schleifendurchläufe vorbelegen.
In der Schleife den Vergleich mit dem gewünschten Wert machen und bei einem Treffer den Schleifenzähler auswerten um die Adresse des Wertes auszulesen.
 
Wenn man das universell machen wollte, also jeden beliebigen DB durchsuchbar, nach einem beliebigen String oder einer Int, dann muß man den DB byteweise nach dem ersten Byte der Int oder des String durchsuchen, bei Treffern den Rest der Int oder des String vergleichen und ggf. das Ergebnis melden. Dann ist noch die Frage, meldet man den ersten Treffer, alle Treffer oder den jeweils nächsten Treffer? Hat man große DB kann man das u.U. nicht mit einer einzigen Schleife machen, da dann die Zykluszeit vielleicht zu stark steigt. In diesem Falle muß man das auch noch auf mehrere Zyklen aufteilen.

Etwas Anderes ist es dann schon, wenn der zu durchsuchende DB bereits eine feste Struktur hat, also z.Bsp. 50 Einträge, mit je einer Int und einem String. Dann kann man tatsächlich diese jeweils 50 festen Einträge per Schleife durchsuchen, vergleichen und die Fundstellen melden. Das geht recht einfach in SCL, aber auch in AWL kann man das noch lösen, dann aber mit indirekter Adressierung.

Fall 2 ist sicher schneller zu programmieren, als Fall 1.
 
Also erstmal danke für die Antworten.

Ich suche allerdings eine bzw. ggf. mehrere fertige Funktionen, die diese Aufgabe so oder so ähnlich erfüllen können. Die eine, welche ich gefunden hab (TBL_Find) eignet sich wie gesagt ja leider nicht für den dynamischen Einbau in einem überlagerten FC/FB.


Gibts da andere fertige Funktionen von Siemens, der OpenSource-Collection oder ggf. sogar kostenpflichtige?
Ich fand mal irgendwo eine String-Find-Funktion, verwarf die aber da ich direkt im Anschluss die Table-Find-Funktion fand. Kann mir da evt. jmd. auf die Sprünge helfen?


Sofern es außer TBL_Find nichts weiteres gibt: Ist jemand in der Lage, so etwas in AWL/SCL -bezahlbar- zu programmieren?



ps: Der zu suchende bzw. zu findende String/INT/...-Wert wird nur einmal im DB vorkommen, dafür sorgt das Leitsystem.
Es soll eine Ident-Nummer gesucht werden und anschließend über dessen Position im DB die im dazugehörigen UDT liegenden Infos abgefragt werden.


BSP:

UDT:
> Ident-NR (INT/String)
>> Aktion-1 (INT)
>> Aktion-2 (INT)
>> Aktion-3 (INT)

Ich suche eine Ident-Nr, bekomme über die Funktion die entspr. Position im DB zurück und kann dann durch das Offset schauen, welcher Wert zur Aktion-1, Aktion-2 oder Aktion-X gehört.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich bin kein Freund von Any-Pointer Gebastel wenn man in SCL programmiert.
Wenn man die Quellen hat setze ich am liebsten eine konstante Array-Größe an allen Stellen wo es vorkommt ein.
Als Basis könnte dir der Codeschnipsel dienen. Für andere Datentypen muss man einfach den Datentyp des Arrays und des Suchmusters ändern.
Code:
FUNCTION FC100 : VOID

CONST
    ANZ := 10;                    // Größe des Arrays
END_CONST
    
VAR_INPUT
    data : ARRAY[1..ANZ] OF INT;  // zu durchsuchendes Array
    ptrn : INT;                   // zu suchende Zahl
END_VAR

VAR_OUTPUT
    pos : INT;                    // Position, wenn nicht gefunden dann -1
END_VAR

VAR_TEMP
    i : INT;
END_VAR   
   
BEGIN
    pos := -1;
    FOR i := 1 TO ANZ DO
        IF data[i] = ptrn THEN
            pos := i;
            EXIT;
        END_IF;
    END_FOR;
END_FUNCTION
 
Ihr habt alle zu viel speicher in euren SPS'n ...

War am Wochenende schon kurz davor nen universalbaustein zu basteln, einfach weils mir in den fingern juckte!
Ist bisschen tricky aber auch in awl realisierbar ... hätte ich lust drauf.

Könnte dir anbieten dir da was zu schreiben bis ende nächster woche (bin jetzt erstmal viel unterwegs).

Schreib dann aber bitte noch mal detailiert WAS du suchen willst oder ob du einen baustein haben willst der alles suchen kann (INT/WORD/REAL/CHAR/STRING).
Wobei ich immernoch net raffe wieso man auf die idee kommt nen string oder char's in ner sps zu speichern ...
 
Ihr habt alle zu viel speicher in euren SPS'n ...
Du redest von dir, oder wen meinst du?
Ein Universalbaustein muss doch die Auswertung für alle Datentypen mitschleppen, auch wenn sie im konkreten Programm gar nicht benötigt werden.

Und wenn du noch nie einen String oder Char in der SPS speichern musstest ist es kein Wunder dass du bisher mit AWL auskamst.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich hab mir dazu auch schon mal einen Baustein geschrieben...

Der sucht aber eher in einer bestimmten Struktur, vielleicht hilfts ja...

Code:
FUNCTION FC 124 : VOIDTITLE =STD_ANY_SUCHEN
//===================================================
//Technische Daten:
//====================================================
//           Version: 1.00
//             Datum: 25.09.2009
//====================================================
//             Autor: Kühner J.
//Baustein Name Symb: STD_ANY_SUCHEN
//
//====================================================
//Beschreibung:
//
//Such nach einem gegebenen ANY in einem DB.
//
//Dazu kann die Struct größe in der Sich der Any befindet,
//der DB, und die Startadresse eingegeben werden.
//Die Any Länge wird aus den zu suchenden Daten ausgelesen.
//
//Der FC gibt 0 zurück wenn nichts gefunden wurde und >0
//die Nummer des Structes!
//====================================================
VERSION : 0.1




VAR_INPUT
  VERGLEICHS_ANY : ANY ;    //Any zu den Daten die Verglichenwerden sollen (Bsp. der gescannte Barcode)
  DB_VERGLEICH : INT ;    //DB in dem die Daten stehen
  GROESE_STRUCT_VERGLEICH : INT ;    //Größse des zu durchlaufenden Structes
  ANZAHL_VERGLEICH : INT ;    //Anzahl der Struct Elemente
  START_VERGLEICH : INT ;    //Adresse im STruct
END_VAR
VAR_OUTPUT
  ZAEHLER_AUSGABE : INT ;    //Nummer des Datensatzes, 0 = keinen gefunden!
END_VAR
VAR_TEMP
  ANY1 : ANY ;    
  ANY2 : ANY ;    
  ZAEHLER_1 : INT ;    
  ZAEHLER_2 : INT ;    
  RET_VAL_INT : INT ;    
  LAENGE_ANY : INT ;    
  STARTADRESSE_IN_LOKALDAT : INT ;    
  DATEN : ARRAY  [1 .. 100 ] OF BYTE ;    
END_VAR
BEGIN
NETWORK
TITLE =


      L     0; 
      T     #ZAEHLER_AUSGABE; 
      T     #ZAEHLER_1; 


//Startadresse der Temporär in den Lokaldaten abgelegten Daten!
      L     30; 
      T     #STARTADRESSE_IN_LOKALDAT; 


//Vergleichsdaten in Lokaldaten kopieren
//ANY 1 auf Vergleichsdaten nutzen
      L     P##VERGLEICHS_ANY; 
      LAR1  ; 
      L     D [AR1,P#0.0]; 
      T     LD     0; 
      L     D [AR1,P#4.0]; 
      T     LD     4; 
      L     W [AR1,P#8.0]; 
      T     LW     8; 


//ANY 2 auf Lokaldaten befüllen
      L     28; 


      L     W#16#1002; //Typ BYTE
      T     LW    10; 
      L     LW     2; //Anzahl Bytes
      T     LW    12; 
      T     #LAENGE_ANY; 
      L     0; //Quell-DB
      T     LW    14; 
      L     #STARTADRESSE_IN_LOKALDAT; //Startadresse in Lokaldaten
      SLD   3; 
      OD    DW#16#87000000; //87 Vorgänger-Lokaldatenbereich
      T     LD    16; 


      CALL SFC   20 (
           SRCBLK                   := #ANY1,
           RET_VAL                  := #RET_VAL_INT,
           DSTBLK                   := #ANY2);




sl1:  L     #ZAEHLER_1; 
      +     1; 
      T     #ZAEHLER_1; 
      L     #ANZAHL_VERGLEICH; 
      >I    ; 
      BEB   ; 


      L     #ZAEHLER_1; 
      +     -1; 
      L     #GROESE_STRUCT_VERGLEICH; 
      *D    ; 
      L     #START_VERGLEICH; 
      +D    ; 
      SLD   3; 
      LAR1  ; 


      L     #STARTADRESSE_IN_LOKALDAT; 
      SLD   3; 
      LAR2  ; 


      L     0; 
sl2:  T     #ZAEHLER_2; 


      L     DBB [AR1,P#0.0]; 
      L     LB [AR2,P#0.0]; 
      <>I   ; 
      SPB   sl1; //ungleich, weiter springen!


      L     P#1.0; 
      +AR1  ; 
      +AR2  ; 


      L     #LAENGE_ANY; 
      +     -2; 
      L     #ZAEHLER_2; 
      <=I   ; 
      SPB   gl; 


      +     1; 
      SPA   sl2; 


//ergebnis ist gleich
gl:   L     #ZAEHLER_1; 
      T     #ZAEHLER_AUSGABE; 
END_FUNCTION


P.S. : Das umkopieren der Vergleichsdaten hätte Ich mir womöglich sparen können! Warum Ich das gemacht hab? Weiss nimmer...
 
Zuletzt bearbeitet:
Du redest von dir, oder wen meinst du?
Ein Universalbaustein muss doch die Auswertung für alle Datentypen mitschleppen, auch wenn sie im konkreten Programm gar nicht benötigt werden.

Und wenn du noch nie einen String oder Char in der SPS speichern musstest ist es kein Wunder dass du bisher mit AWL auskamst.

;D
Ich weiß noch nicht wo ich lande, aber ich denke ich bleibe unter 1k!
Das man mit SCL auch vieles einfach hinbekommt ist klar, zumindest so lang man die quelle hat!
Aber ein übersetztes SCL programm ist immer größer wie das selbe in AWL direkt geschrieben ...

Aber bitte geb mir ein beispiel wo es NOTWENDIG ist mit chars und strings in ner cpu zu arbeiten! (abgesehen von irgendwelchen kranken kundenvorstellungen)
Das man mit ner CPU viel spielen kann ist mir klar aber ich hab schon viele Zeilen programm geschrieben und noch viel mehr kranken scheiss gesehen und dabei war nix was mit chars oder strings arbeitete ...
Aber ich lass mich gern eines besseren belehren!
Also nur her damit :)
 
;D
Ich weiß noch nicht wo ich lande, aber ich denke ich bleibe unter 1k!
Das man mit SCL auch vieles einfach hinbekommt ist klar, zumindest so lang man die quelle hat!
Aber ein übersetztes SCL programm ist immer größer wie das selbe in AWL direkt geschrieben ...

Aber bitte geb mir ein beispiel wo es NOTWENDIG ist mit chars und strings in ner cpu zu arbeiten! (abgesehen von irgendwelchen kranken kundenvorstellungen)
Das man mit ner CPU viel spielen kann ist mir klar aber ich hab schon viele Zeilen programm geschrieben und noch viel mehr kranken scheiss gesehen und dabei war nix was mit chars oder strings arbeitete ...
Aber ich lass mich gern eines besseren belehren!
Also nur her damit :)

In welcher Branche programmierst du denn, dass du wirklich noch NIE eine string oder char im Programm hattest? Zu S5 Zeiten war das vielleicht exotisch, heutzutage ist das aber doch nicht unüblich.

Ich tue mir für solche Programme im Jahre 2012 kein AWL mehr an, aber das ist sicher Geschmackssache. Meiner Meinung nach ist das AWL Pointergefrickel in Zeiten wo SCL verfügbar ist nach unwartbarer Mist. Und wenn du deine SCL Quellen nach dem Übersetzen löschst ist das ein ganz anderes Problem.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In welcher Branche programmierst du denn, dass du wirklich noch NIE eine string oder char im Programm hattest? Zu S5 Zeiten war das vielleicht exotisch, heutzutage ist das aber doch nicht unüblich.

Ich tue mir für solche Programme im Jahre 2012 kein AWL mehr an, aber das ist sicher Geschmackssache. Meiner Meinung nach ist das AWL Pointergefrickel in Zeiten wo SCL verfügbar ist nach unwartbarer Mist. Und wenn du deine SCL Quellen nach dem Übersetzen löschst ist das ein ganz anderes Problem.

Ich programmier hauptsächlig Wasserwerke aber auch viel für BHKW/Kessel-Anlagen und hab durch kontakte schon durch viele Programme aus der Chemie/Automobil-Industrie schnuppern können.

Ich komm sicherlich nicht auf die Idee Quellen zu löschen, nur die strategen die sich folgeaufträge sichern wollten ^^"
Ich finde man sollte so wenig wie möglich Programmisersprachen durcheinander werfen, aber das ist halt geschmackssache.

Aber noch mal zu den Strings und Chars:
Wo gibts denn sowas z.B.? Interessiert mich ernsthaft!
 
Zuletzt bearbeitet:
Sind wir schon beim "SV"?

Ich finde mich aber auch eher bei Thomas wieder.
Was in AWL oft ein fürchterliches Gewürge ist, kann mit SCL sehr leserlich programmiert werden.
Jochens Post ist für mich so ein Beispiel. Vielleicht geht es vielen von Euch ja nicht so, aber für mich ist das auf den ersten Blick einfach nur kryptisch.
Das soll jetzt aber keine Kritik an dem Code sein!

Beispiele für die Verwendung Strings:
- Rezeptverwaltung auf der SPS. Auch wenn jetzt so mancher rufen mag, dass sowas auf dem HMI gemacht wird. Ich finde das gut so. :cool:
- Telegrammverkehr mit anderen Systemen. Z.B. Materialflussrechner, Scanner, Waagen... Ohne SCL wird das zu dem o.g. "Gewürge"

Alte Programmierhasen mögen aber vielleicht darauf stehen...
 
Ich bin auch eher für SCL, wobei Ich den SCL support in Step7 einfach grauenhaft finde. Der Editor ist schlecht. Und oft erzeugen auch die einfachste Dinge riesige Bausteine, und bei Siemens PLCs muss man das immer noch berücksichtigen, da Speicher recht teuer ist!

Das Pointergefrikel ist bei uns auch meist nur in ein paar wenigen Standardbausteinen drin, welche dann aber meist so oft im Einsatz und ausgiebig getestet sind, das da seltenst jemand noch was ändern muss!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke, ich werd mir die Codeschnipsel mal anschauen.


Für die Interessierten:
Es geht um eine Fertigungsstraße mit Weichen, welche aufgrund der Geschwindigkeit nicht vom Leitsystem sondern von lokalen Steuerungen angesprochen werden (Zeitkritisch). Das Leitsystem schreibt für jedes Teil eine Identnummer oder einen Identcode sowie "darunter" die gewünschten Aktionen für die verschiedenen Weichen in den DB. Kommt nun ein Teil an einer Weiche an, wird der SPS dies signalisiert (durch einen Sensor und die Übermittlung des Identcodes).
Die SPS muss nun herausfinden, welche Aktion an dieser Weiche für dieses Werkstück gewünscht ist.

Ich müss dann also den übermittelten Identcode bzw. die übermittelte Identnummer im DB suchen. Mit der passenden Funktion bekomme ich dann die entspr. Adresse im DB zurück, schaue dann in diesem DB nach was "unter" diesem Eintrag steht und führe die gewünschte Aktion aus.


Das klappte mit TBL_Find auch, allerdings soll es ein Universalbaustein sein dem man dann unter Anderem auch die gewünschte DB-Nummer übergeben kann und nicht im Baustein rumbasteln muss.
 
Nach was willst du alles suchen? Liegen da Strings/Chars zwischen?

Wenn ich weiß wonach du alles suchen können willst (scheiss deutsch ...) kann ich da, wie vorher schon gesagt, bis ende nächster woche was liefern!
 
Ist noch nicht geklärt - dh. ich bin die Geschichte aktuell nur am Durchspielen.
Wir müssen quasi noch alles festlegen - aber dazu muss ich mal schauen wie die Möglichkeiten auf der SPS-Seite aussehen.

Es wird entweder eine Ident-Nummer (also nur Zahlen / INT) oder ein Ident-Code mit Zeichen (Buchstaben und Zahlen). Wenn Letzteres Funktioniert, wären auch INT-Werte ja kein Problem.


Schreib doch mal kurz ne PN, was das etwa kosten würde ;) - die Diskussion würde sonst den Rahmen in diesem Thread wohl sprengen.... thx
 
Zuviel Werbung?
-> Hier kostenlos registrieren
..Schreib doch mal kurz ne PN, was das etwa kosten würde..
Hallo Saarländer,

bist du Einkäufer oder Programmierer? Wo ist dein Ehrgeiz?
Jeder zweite könnte dir hier helfen, wenn du mal ein bisschen Initiative zeigen würdest.

Andererseits, was wäre dir denn die Sache wert :icon_lol: ?


Gruß, Onkel
 
Das klappte mit TBL_Find auch, allerdings soll es ein Universalbaustein sein dem man dann unter Anderem auch die gewünschte DB-Nummer übergeben kann und nicht im Baustein rumbasteln muss.

Der Baustein den Ich angehängt habe, dem kannst du die DB Nummer übergeben... Wobei mir immer noch nicht ganz kalr ist was du genau machen willst...
 
Du hast gesagt, dass der Baustein möglichst "allgemein" funktionieren soll. Möglicherweise macht dieses Ansinnen die Aufgabe nur unnötig kompliziert.

So wie ich das sehe, hast Du ja durchaus Einfluss darauf, wie die Daten im DB abgelegt werden.

Vermutlich würde es genügen einen Global-DB anzulegen, in dem die Daten liegen. Vermutlich macht es Sinn ein UDT anzulegen und dieses als Array[1..n] im DB zu deklarieren.
Dann machst Du halt einen absoluten Zugriff auf den DB und kannst das Ganze mit weniger als 10 Zeilen Code in SCL erledigen.
Das ist dann der etwas leichtere Weg.

Z.B.: (quick and dirty)

Code:
FOR ii := 1 to Anzahl DO
IF Suchstring = "Data".WT_Daten[ii].Index THEN
Aktion_1 := "Data.WT_Daten[ii].Aktion_1;
EXIT;
END_IF;
END_FOR;
 
Zurück
Oben