Step 7 SCL Anfänger Frage (im Prinzip Indiziert Zugriff auf DB's)

Boxy

Level-3
Beiträge
1.478
Reaktionspunkte
149
Zuviel Werbung?
-> Hier kostenlos registrieren
Oute mich jetzt einmal als SCL Anfänger bzw. Umsteiger.
Bin nun dabei (nach gut 20 Jahre S7) mich in SCL (Step 7 Classic) einzuarbeiten ;)

Habe folgende Denkblockade und suche eine Lösung bzw. Hinweise für mein Problem.

Ich möchte im Prinzip nur indirekt in SCL auf DBs zugreifen.
Mir ist schon bekannt, das ich am FB einen Eingangsparameter mit BLOCK_DB anlegen kann und dann Symbolisch darüber auf den DB zugreifen kann.

Code:
VAR_INPUT
    DBNr        : BLOCK_DB;     //--> Hier wird DBNr. als DB übergeben
END_VAR

 // Hier Zugriff auf DBW10 aus DBNr.
  iSchmier[1] := WORD_TO_INT(DBNr.DBW10);   
END_FUNCTION_BLOCK

Was ich aber nun möchte ist im Prinzip über zB einem INT oder Word (also zB. 123) auf den DB123 zugreifen.
Also im Prinzip lese ich nun einen Interger Wert aus (H-Funktion) und möchte nun darüber auf den jeweiligen DB entsprechend zugreifen.

Als Bsp.: (ist aber nur sinnbildlich)
Code:
VAR
wQuellDB   : INT;
END_VAR


wQuellDB := 123;

 // Hier Zugriff auf DBW10 aus DBNr. 123
 iSchmier[1] := WORD_TO_INT(wQuellDB.DBW10);   
DB234.Spalte.Zeile_1 := [B]wQuellDB[/B].Spalte.Zeile_1;

Mir ist schon bekannt, dass ich das Word nach Block_DB wandeln muss (WORD_TO_BLOCK_DB) aber was für nen Variable lege ich da an, wo der DB gespeichert ist um darüber Symbolisch darauf zugreifen zu können ???

Hintergrund wäre z.B. ich habe 20 DBs mit Einstellungen (Aufbau wie eine Tabelle Zeilen [1..20] und Spalten [1..9]) welche abhängig der Vorgewählten / übergebenen Nummer ausgelesen und verarbeitet werden. Der Aufbau aller DBs ist gleich, nur die Werte sind ja anders.

Code:
wQuellDB := 123;  <-- als Bsp. ansonsten zB. Typ 100, 101 o.ä.

 FOR iZeile := 1 TO 20 DO 
   FOR iSpalte := 1 TO 9 DO 
          Abbild.Zeile[iZeile].Spalte[iSpalte].Funktion_Index := WORD_TO_BLOCK_DB([B]wQuellDB[/B]).Tabelle.Zeile[iZeile].Spalte[iSpalte].Funktion_Index;
   END_FOR
END_FOR

funktioniert leider nicht ...

Danke vorab für euere Hinweise :cool:
 
Zuletzt bearbeitet:
Hi,

bin auch kein Profi :) aber....
"wQuellDB" ist doch ein INT und du wandelst "WORD_TO_BLOCK_DB". Eventuell fehlt eine "INT_TO_WORD" Wandlung.
Kann gut sein, dass es am Schluss so ähnlich aussieht: WORD_TO_INT(WORD_TO_BLOCK_DB(INT_TO_WORD(wQuellDB)).........
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich hatte in dem pseudo Beispiel die Wandlung von INT_TO_WORD vergessen.
Genau um eine Word-Variable für die Wandlung zu haben ...

Code:
wQuellDB := INT_TO_WORD(123); //Vorgabe DB Nr. 

FOR iZeile := 1 TO 20 DO 
   FOR iSpalte := 1 TO 9 DO 
          Abbild.Zeile[iZeile].Spalte[iSpalte].Funktion_Index := WORD_TO_BLOCK_DB([B]wQuellDB[/B]).Tabelle.Zeile[iZeile].Spalte[iSpalte].Funktion_Index;
   END_FOR
END_FOR

Habe es also versucht und bekomme es auch nicht übersetzt.
Kann es sein das es hier Probleme wegen dem Symbolischen Zugriff gibt?

Gibt es da keine Möglichkeit irgendwie auf verschiedene DBs , im Prinzip DB-Nummer[+1...20] zuzugreifen?
Also wQuellDB ist dann z.B. DB121-DB139 ...
 
Zuletzt bearbeitet:
Moin!
WORD_TO_BLOCK_DB(wQuellDB).Tabelle.Zeile[iZeile].Spalte[iSpalte].Funktion_Index;
das wird nicht funktionieren, weil der Compiler ja die Struktur deines indizierten DBs nicht kennt. Mit WORD_TO_BLOCK_DB kannst du also nur wie folgt arbeiten (siehe auch Siemens Hilfe):
WORD_TO_BLOCK_DB("Adressindex").DX(0,0), wobei das Byte 0 und das Bit 0 in diesem Fall dann wieder Laufvariablen deiner FOR-Schleife sein können.
 
Zuletzt bearbeitet:
Moin!

das wird nicht funktionieren, weil der Compiler ja die Struktur deines indizierten DBs nicht kennt. Mit WORD_TO_BLOCK_DB kannst du also nur wie folgt arbeiten (siehe auch Siemens Hilfe):
WORD_TO_BLOCK_DB("Adressindex").DX(0,0), wobei das Byte 0 und das Bit 0 in diesem Fall dann wieder Laufvariablen deiner FOR-Schleife sein können.


Das ist leider langsam auch meine Vermutung gewesen.
Gibt es da evtl. irgendwie ein Trick oder Tipps was ich da machen könnte ??? Wo bleiben die SCL Spezialisten :cool:

Oder kann man anders irgendwie Symbolisch indiziert auf den DB bzw. die DBs zugreifen?
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Es geht schlichtweg nicht. Entweder voll symbolisch, also jeden DB einzeln in einer FOR-Schleife behandeln, oder aber wie zuvor beschrieben über den WORD_TO_BLOCK_DB indirekt mit den bekannten Nachteilen (bspw. keine Querverweise des Zugriffs). Manchmal muss man halt zwischen Pest oder Cholera wählen ;)
Du kannst natürlich auch komplett via ANY-Pointer zugreifen, wird aber am Tagesende auch nicht besser.
 
Gemischt symbolisch (Variablenname) und absolut (DB-Nummer) adressiert zugreifen geht nicht.
Damit symbolisch zugreifen geht muß der Compiler wissen welche Struktur der DB hat - was er nicht wissen kann, wenn da nur eine Nummer übergeben wird.

Wenn der DB-Bereich nicht groß ist, dann könntest Du in TEMP ein STRUCT mit der Struktur der DBs anlegen und am Bausteinanfang den indirekt adressierten DB auf diese TEMP-Struktur kopieren (BLKMOV). Danach kannst Du symbolisch auf die Kopie in TEMP zugreifen. Falls Du auch in den DB-Bereich schreiben willst, dann am Ende wieder zurückkopieren.

Oder Du deklarierst den INPUT-Übergabeparameter mit der Struktur des DB-Bereichs, dann kennt der Compiler die Struktur der übergebenen Daten. Da wird vor Aufruf Deines Bausteins der DB-Bereich in den Übergabebereich kopiert. Wenn Du die Übergabestruktur in VAR_IN_OUT deklarierst, dann wird der DB-Inhalt nicht kopiert sondern ein Zeiger auf die Struktur übergeben (sozusagen ein Pointer auf einen Datentyp). Das klingt zunächst clever, benötigt aber im Baustein für jeden Zugriff auf die übergebene Struktur (im Quelltext unsichtbar!) viel mehr Programmcode als ein Zugriff auf VAR_INPUT (ich meine, bei Step7 classic ist das ca. 10..20 mal soviel Codegröße - hab' mal ein Auge auf die Bausteingröße).

Weil die Struktur des DB-Bereichs exakt übereinstimmend!/konsistent an mehreren Stellen deklariert werden muß, bietet es sich an für die Struktur einen UDT zu verwenden.

Wegen der Details der Parameterübergabe wird es langsam Zeit, daß Du uns verrätst, welche CPU Du da programmieren willst (sieht aus wie S7-300/400 in Step7 V5.x?).

Harald
 
Wegen der Details der Parameterübergabe wird es langsam Zeit, daß Du uns verrätst, welche CPU Du da programmieren willst (sieht aus wie S7-300/400 in Step7 V5.x?).

Harald

Danke mal für die Antwort.
Ich nutze ne 840D sl mit der PLC 317 ;) daher ja auch "Classic, noch V5.5 (evtl. 5.6 demnächst)" ... In der Sinumerik Welt sind wir ja bisschen hinter her ...
Gibt es große Änderungen zwischen SCL V5.5 und V5.6?

Oder Du deklarierst den INPUT-Übergabeparameter mit der Struktur des DB-Bereichs, dann kennt der Compiler die Struktur der übergebenen Daten.

Irgendwie stehe ich da gerade auf dem Schlauch, hättest Du mir da mal ein kleines Bsp.?


Weil die Struktur des DB-Bereichs exakt übereinstimmend!/konsistent an mehreren Stellen deklariert werden muß, bietet es sich an für die Struktur einen UDT zu verwenden.

Da ich ja später ca. 20 gleiche DBs haben werden (soll), habe ich mir da eh nen UDT angelgt!

Mein Gedanken wäre auch, das ich mir den jeweiligen DB (temporär in eine lokale Kopie in der Instanz des DB's ablege und mit dem Abbild arbeite)
Hier kann ich ja das Abbild mit dem UDT deklarieren welcher für die DBs ja angelegt wurde... Somit muss ich halt über BLOMOV mir den Entsprechenden Quell/Daten DB lokal abspeichern.

Code:
VAR
    Abbild   : UDT123;         //Struct wie Daten DB der Tabelle
    iTemp   : INT;
END_VAR

      wQuellDB := INT_TO_WORD(123); //Vorgabe DB Nr.
      
   iTemp:=   BLKMOV(SRCBLK :=  wQuellDB      // IN: ANY
          ,DSTBLK :=  Abbild                   // OUT: ANY
          );                                            // INT
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn Du einen FB hast, dann brauchst Du nicht im FB die Struktur von VAR_INPUT zu VAR in Dein "Abbild" kopieren - da würden die Daten nämlich zweimal kopiert: einmal vom FB-Aufrufer vom DB in den Übergabeparameter in VAR_INPUT und einmal im FB von VAR_INPUT zu VAR. Dein FB kann direkt mit den Daten-Kopien in VAR_INPUT arbeiten. (Technisch möglich ist es auch, daß der FB-Aufrufer vor dem FB-Aufruf die Daten vom DB direkt in VAR kopiert, doch der Zugriff von außen auf die Instanzdaten ist schlechter Programmierstil.)
Code:
VAR_INPUT
    Abbild   : UDT123;         //Struct wie Daten DB der Tabelle
END_VAR

DB234.Spalte.Zeile_1 := Abbild.Spalte.Zeile_1;
Aufruf des FB:
Code:
myFB_Instanz(Abbild:=DB_Tabelle_1.Tabelle);

Harald
 
Danke mal für die Antwort.
Ich nutze ne 840D sl mit der PLC 317 ;) daher ja auch "Classic, noch V5.5 (evtl. 5.6 demnächst)" ... In der Sinumerik Welt sind wir ja bisschen hinter her ...

Wenn du willst kannst du auch mit TIA wurde mit 4.8SP1 freigegeben ab 4.8 SP2 erfolgt auch eine generelle Freigabe für Safety mit F- PLC
Für SCL ist TIA schon die bessere Wahl.

Da ich ja später ca. 20 gleiche DBs haben werden (soll), habe ich mir da eh nen UDT angelgt!

Da ist meiner Meinung nach der Fehler. (falsche Datenstruktur) Warum kein DB mit einem Array of UDT ? Da kann man dann auch schön symbolisch arbeiten.
 
Wenn du willst kannst du auch mit TIA wurde mit 4.8SP1 freigegeben ab 4.8 SP2 erfolgt auch eine generelle Freigabe für Safety mit F- PLC
Für SCL ist TIA schon die bessere Wahl.

Na ja, so einfach ist dies nun auch nicht, einen ganzen Hersteller von Namhaften Werkzeugmaschinen dann einmal (kurz) umzustellen ;).
Da müssten einige Serien von Bearbeitungszentren sowie die gesamte Entwicklung umgestellt werden.
Auch gibt es da akut dann weitere Fragen bzgl. Integration Bedienoberfläche, Spezifische Erweiterungen usw. welche zuerst mit der Entwicklung bei Siemens gelöst / bearbeitet werden müssen.
Diese Umstellung wird bei uns dann (so bisher geplant) mit der bzw. auf die 840 Evo Line erfolgen. Es sei denn wir müssen wegen bestimmt NC Optionen noch 4.8 Sp2 einführen, was dann aber auch noch mit Classic sein wird. Wenn wir z.B. Safety (SPL) umstellen, dann wollen wir dies 1-mal und kpl. machen ... Ist aber alles ein komplexes Thema ...

Da ist meiner Meinung nach der Fehler. (falsche Datenstruktur) Warum kein DB mit einem Array of UDT ? Da kann man dann auch schön symbolisch arbeiten.

Die Finale Lösung steht ja noch nicht, aktuell ist ja Lösungsfindung für die Entwicklung angesagt und der erste Gedanke war einmal das auf einzelne DBs aufzuteilen und zu speichern.
Der Gedanke mit einem DB ist aber nicht zu verachten und manchmal sieht man halt auch den Wald vor lauter Bäume nicht :rolleyes:

Muss allerdings einmal auch schauen ob dies mit RunMyScreen und der Tabellenfunktion dann auch so machbar wäre. Hier gibt halt das Bedienkonzept unserer Maschinen auch bestimmt Grenzen vor.
WinCC (flex) wäre mir da auch lieber, aber gibt's halt net :oops:, da könnte man dann auch einiges in den Bildern schon abarbeiten, was es leichter macht ...
Alternative ist ja dies via lokaler Kopie der Daten in der Instanz des FBs.

Bei Entwicklungen ist es halt meist so, jede Tag / Woche kommt einer mit neuen Ideen und Wünsche und da wächst alles rapide an :ROFLMAO:
Muss einmal dann überschlagen wie viele Tabellen ich in einen DB rein bekomme um zu sehen ob die DB Größe ausreichen würde.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich versuche gerade einen DB (dessen Inhalt in ein lokales Abbild zu kopieren).

Code:
VAR
  Abbild          :UDT2101; 
  wQuellDB     :WORD;
    
END_VAR


     wQuellDB := INT_TO_WORD(2101);           //Vorgabe DB Quelle (DB ist ebenfalls Typ vom UDT2101)
      
     itmpWert:= BLKMOV(SRCBLK := WORD_TO_BLOCK_DB(wQuellDB)          // IN: ANY
                                   ,DSTBLK := Abbild                                                  // OUT: ANY
                                   ); // INT

Bekomme immer 8043 (-32385) als Fehler zurück geliefert von der Funktion.
Trage ich in SRCBLK := DB2101 direkt ein, wird alles ins Abbild kopiert und RETVAL = 0 ...

Dachte jetzt, durch die Wandlung WORD_TO_BLOCK_DB(wQuellDB), wird die Quelladresse für den DB2101 (hex 835) dem BLKMOV übergeben :confused:


Wenn ich einen Any Pointer erzeuge, bekomme ich ebenfalls als RETVAL 8043 (-32385)

Code:
VAR
  Abbild          :UDT2101; 
  wQuellDB     :WORD;
    
END_VAR
VAR_TEMP
     pANYQuellDB  : ANY;
END_VAR

      wQuellDB := INT_TO_WORD(2101); //Vorgabe DB Nr.
            pANYQuellDB := WORD_TO_BLOCK_DB(wQuellDB);

     itmpWert:= BLKMOV(SRCBLK := pANYQuellDB   // IN: ANY
                                   ,DSTBLK := Abbild             // OUT: ANY
                                   ); // INT

Irgendwer einen Tipp ...
 
Wenn ich einen Any Pointer erzeuge, bekomme ich ebenfalls als RETVAL 8043 (-32385)
Du erzeugst keinen ANY-Pointer sondern schreibst einfach eine Zahl in die ANY-Variable - das ist aber kein Pointer.
Siehe den speziellen Aufbau des Datentyps ANY in der Step7-Hilfe oder hier in der FAQ

Harald
 
Du erzeugst keinen ANY-Pointer sondern schreibst einfach eine Zahl in die ANY-Variable - das ist aber kein Pointer.
Siehe den speziellen Aufbau des Datentyps ANY in der Step7-Hilfe oder hier in der FAQ

Harald

Leider ist mir nicht bekannt wie ich das in SCL mache :confused: kämpfe hier mit zu vielem und habe gerade keinen Durchblick mehr ...
Ich war halt der Meinung das durch dieses WORD_TO_BLOCK_DB(Wert) dies die selbe Wirkung hat wie wenn ich zB DB2101 direkt eintrage :confused::confused::confused:

Hast Du da bitte en kleines Bsp.? Wäre super ...
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hier ein Beispiel, wie man in SCL einen ANY aus den einzelnen Bytes zusammenbastelt. (ich meine, vollmi hatte mal einen schöneren Beispielcode, doch den finde ich jetzt nicht)
Das Prinzip: per AT ein STRUCT mit der Strukturbeschreibung des ANY über eine ANY-Variable legen, und die Strukturmember/Bytes mit den nötigen Werten füllen.
Danach kann die ANY-Variable an BLKMOV übergeben werden.

Harald
 
Hier ein Beispiel, wie man in SCL einen ANY aus den einzelnen Bytes zusammenbastelt. (ich meine, vollmi hatte mal einen schöneren Beispielcode, doch den finde ich jetzt nicht)
Das Prinzip: per AT ein STRUCT mit der Strukturbeschreibung des ANY über eine ANY-Variable legen, und die Strukturmember/Bytes mit den nötigen Werten füllen.
Danach kann die ANY-Variable an BLKMOV übergeben werden.

Harald

Danke , schaue ich rein :TOOL:

Ist halt leider nicht so einfach alles als Einzelkämpfer, wenn Probleme keinen Interessieren (sind doch nur Herausforderungen ...)
 
Ist jemanden eine Grenze der maximalen Anzahl Daten welcher der SFC20 (BLKMOV) kopieren kann bekannt?
In der Online Doku zum SFC20 im Step 7 Manager, stehen keine Grenzen bei einer S7-300 (PLC 317F-3 PN/DP der 840D sl).

Irgendwie stoße ich bei 905 Wörter an die Grenze und bekomme als RET_VAL 8x23 (Bereichslängenfehler beim Schreiben eines Parameters) zurück.
Der Ziel-DB hat die selbe Größe wie der QQuell-DB (1808 Wörter) ...
 
BLKMOV kann > 64000 Byte

Zeige doch mal Deinen Code zum Erstellen/Ausfüllen des ANY. Dein Problem klingt, als ob Du da eine INT-Operation hast wo eine DINT-Operation nötig ist.

Harald

Danke für dein Replay, ich glaube ich habe meinen Denkfehler da gefunden.
Bin irgendwie mit der Zählweise durcheinander gekommen, wie ich gerade im Versuch merkte.
Das Byte 1800 ist ja natürlich auch das Wort 1800 aber für Blockmove sind es halt 900 Wörter :oops: ...
Irgendwie habe ich mich da bzgl. Adresse im DB Editor verleiten lassen ... Asche auf mein Haupt :shock:

Wird Zeit das es Weekend oder Weihnachten wird, glaube bin am Ende für dieses Jahr ... :)


Aber nochmals ne Frage, weist Du wie ich in SCL dann auf einen Variablen Bereich (Abbild : UDT2101) als Zieladresse den Any-Pointer lege?
Wie kann ich da die Speicheradresse dieser Variable ermitteln, damit ich diese als Ziel an den BLKMOV übergeben kann?
Dies hätte ja den Vorteil das ich nicht eine feste Adresse im Instanz DB als Ziel hätte und somit auch dynamischer wäre.

Code:
VAR
    // statische Variablen
    Abbild   : UDT2101;         //Struct wie Daten DB der Tabelle
END_VAR

VAR_TEMP
    // temporäre Variablen
    src: STRUCT //ANY struct
        ANY_id:         BYTE;
        DataType:       BYTE;
        Length:         WORD;
        DB_Nummer:      WORD;
        MemoryArea:     BYTE;
        ByteAddressMSB: BYTE;
        ByteAddressLSB: WORD;
    END_STRUCT;
    srcAdr    :    WORD;   
    p_src  AT src  :ANY;
    
    dst: STRUCT //ANY struct
        ANY_id:         BYTE;
        DataType:       BYTE;
        Length:         WORD;
        DB_Nummer:      WORD;
        MemoryArea:     BYTE;
        ByteAddressMSB: BYTE;
        ByteAddressLSB: WORD;
    END_STRUCT;
    dstAdr     :    WORD;  
    p_dst   AT dst  :ANY;
            
    iret_val_blk :INT;
    
    
    Data_Length :    WORD;  //BYTE;
    Src_Type    :    BYTE; 
    Src_DbNr    :    WORD;  //BYTE;  
    Src_Adr     :    INT;  
    Dst_Type    :    BYTE; 
    Dst_DbNr    :    WORD;  //BYTE;  
    Dst_Adr     :    INT;    
    
END_VAR
   
(* Baustein Code *)   
BEGIN     
    // Anweisungsteil
    ; 
        Data_Length :=INT_TO_WORD(904); //Word (max 905 Wörter);

        Src_Type    :=B#16#84;          //BYTE //81 = Input, 82 = output, 84 = Datablock, 85 = Instanz DB  
        Src_DbNr    :=INT_TO_WORD(211); //WORD;  //BYTE;  
        Src_Adr     := 0;               //INT

        Dst_Type    :=B#16#84;          //BYTE; 
        Dst_DbNr    :=INT_TO_WORD(212); //WORD;  //BYTE;  
        Dst_Adr     := 0;               //INT
        
        srcAdr := SHL (IN:=INT_TO_WORD(Src_Adr), N:=3);
        dstAdr := SHL (IN:=INT_TO_WORD(Dst_Adr), N:=3);
            
        //Quelle
        src.ANY_id := B#16#10; //for S7 always 10h
        src.DataType:= B#16#04; //Type Word
        src.Length:= Data_Length; 
        src.DB_Nummer:= Src_DbNr; //no DB than 0
        src.MemoryArea:= Src_Type; //81 = Input, 82 = output, 84 = Datablock, 85 = Instanz DB 
        src.ByteAddressMSB:= B#16#0;
        src.ByteAddressLSB:= srcAdr; 

        //Ziel
        dst.ANY_id := B#16#10; //for S7 always 10h
        dst.DataType:= B#16#04; //Type Byte
        dst.Length:= Data_Length; //28 Byte
        dst.DB_Nummer:= Dst_DbNr; 
        dst.MemoryArea:= Dst_Type; //81 = Input, 82 = output, 84 = Datablock 
        dst.ByteAddressMSB:= B#16#0;
        dst.ByteAddressLSB:= dstAdr;
                
        iret_val_blk := BLKMOV(srcblk:= p_src, dstblk:= p_dst);

END_FUNCTION_BLOCK
 
Zuletzt bearbeitet:
Hallo Boxy,

nebenbei erwähnt, DB_Nummer und Length sind beides positive Integerwerte. Deine statische Variable "Abbild" kann direkt symbolisch an die SFC20 als Parameter weiter gegeben werden. Hierfür musst du den Pointer nicht selbst zusammenbasteln.

Wenn du jedoch deinen "Arbeitsdatensatz" nicht in den Lokaldaten des Bausteins, sondern extern in einem weiteren DB als UDT ablegst, wird es noch wesentlich einfacher. Dann bleibt dir allerdings der ganze masochistische Kram mit dem Any-Pointer vergönnt :sad: . Ich weiß jetzt nicht, ob ich dir diesen Spaß verderben soll?


Gruß, Onkel
 
Zurück
Oben