Step 7 Auslesen Array aus DB über zwei Funktionen (ANY-Zeiger und Blkmov)

UsernameS7

Level-1
Beiträge
11
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Tag liebe Member,

ich bin schon länger stiller Mitleser und konnte mir hier immer gute Lösungsansätze holen, nun komme ich nicht weiter und benötige Hilfe.
Zu meinem Vorhabenn:

In einem FB x rufe ich FB y auf dieser besitzt auch einen DB y.
Im FB y habe ich eine IN-Variable als Daten mit dem Datentyp ANY deklariert.
Im FB x (FUP) gebe ich an der Variable Daten ein Array aus einem anderen DB an, Form: DB z.dbx 202.0 BYTE 12
Dieser Eingang wird dann von Step 7 zu: "DB_z".S[2].A1.Read.DATEN.Datenteile.teilenummer umgeformt. Soweit ist alles gut.

Jetzt will ich aber die Daten mit der Länge von 12 Bytes im FB y über ein Blockmove in den DB y schreiben/kopieren.

Im FB y habe ich schon die Eingangswerte von E 0.0 bis E100.0 über ein ANY-Zeiger in den DB y geschrieben und genauso wieder raus. Sinn und Zweck der Verwendung des Anyzeiger war, das die Bausteine immer wieder verwendet werden können und sich selbst über die Variablen die Adresse holen. Das funktioniert auch, nur bei meinem vorhaben mit dem Array nicht.

Mein Programm sieht folgender Maßen aus:
Code:
// Erstellung des Quell-Pointers

      LAR1     P##Quelle             //Lade die Anfangsadresse des ANY-Pointers in AR1
      L     B#16#10                     //S7-code immer b#16#10 = 10hex
      T     LB [AR1,P#0.0]
      L     B#16#2                      //Datentyp: 02 = Byte
      T     LB [AR1,P#1.0]
      L     12                      //Anzahl/Wiederholfaktor
      T     LW [AR1,P#2.0]
      L     0                           
      T     LW [AR1,P#4.0]
      L     B#16#0                      //Auswahl Eingänge bzw Speicherbereich
      T     LB [AR1,P#6.0]
      L     B#16#0                      //Adressbelegung: 0 = 000
      T     LB [AR1,P#7.0]              //Adressformat: Byte.Bit wobei Byte aufgeteilt in Bit0-2 von 7. Byte
      L     P##Datenholen            //Adressanfang (Zeiger)   
      SLD   3
      L     #Offset_Quelle              //Laden des Offsets
      +D                                // Addieren

      T     LW [AR1,P#8.0]              //Adressformat: Byte.Bit wobei Byte in Bit0-7 von 8.Byte


 CALL  "BLKMOV"
       SRCBLK :=#Quelle
       RET_VAL:=#RET_VAL_Block
       DSTBLK :=#Ziel
      NOP   0

Der Fehler an Ret_Val lautet 8124 entspricht "Bereichsfehler beim lesen eines Parameters"
Jedoch kann ich mit dem Fehler nicht viel anfangen, ich vermute es liegt an der Angabe im Speicherbereich des ANY-Zeigers.
Nur was gebe ich an wenn meine Adresse eine ANY Variable (Datenholen) ist?


Ich hoffe mir kann hier einer auf die Sprünge helfen und danke im Voraus!
 
Zuletzt bearbeitet:
Hallo,
also erstmal vorab - ich mußte das Ganze 3mal lesen um es so zu verstehen, wie ich es nun verstanden habe.
Außerdem - ich kann meinen Vorschlag gerade nicht gegen-checken ... (ich schieße also aus der Hüfte - quasi aus der Erinnerung)
Ich nehme folgendes an :
Der IN-(oder INOUT-) Parameter deines FB_y vom Typ ANY ist, wenn du die die Instanz ansiehst, als Pointer ausgeführt (also in der Instanz nicht 10 Bytes sondern nur 6).
Wenn dem so ist, dann mußt du dir den Pointer laden und an der Stelle stehen dann die Inhaltsdaten des ANY's mit dem du eigentlich arbeiten willst.
Das heißt (noch einmal anders geschrieben) : die ANY-Daten für deinen Blockmove stehen an der Adresse, auf die dein IN-Parameter zeigt.
Check das bitte mal ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo UsernameS7!

Mit
Code:
 L     P##Datenholen            //Adressanfang (Zeiger)
lädst Du die Anfangsadresse Deiner Variable #Datenholen in den Akku und nicht den Inhalt Deines Pointers.
Wenn Du den Any einfach "durchreichen" willst, dann schau Dir das Beispiel vom Harald (PN/DP) an:
http://www.sps-forum.de/simatic/63603-any-pointer-ueber-bausteinschnittstelle-2.html#post481732

Damit sollte es funktionieren.

Grüße
Gebs
 
Also ich muß auch mehrmals lesen... und verstehe womöglich trotzdem nicht richtig, was Du da tun willst. Dein Programmcode passt auch irgendwie nicht zu dem was ich aus Deinen Ausführungen interpretiere...

Der Fehler an Ret_Val lautet 8124 entspricht "Bereichsfehler beim lesen eines Parameters"
In Deinem Programmcode bastelst Du einen ungültigen ANY-Pointer, indem Du 0 in die Speicherbereichskennung (Byte 6 von #Quelle) schreibst. Auf welchen Speicherbereich soll Dein ANY #Quelle zeigen?

#Quelle ist eine ANY-Variable in TEMP?
Wo taucht nun Dein ANY aus dem IN-Parameter "Daten" auf? (der, wo P#DB?.DBX202 BYTE 12 drinstehen soll)
Und was sind #Datenholen und #Offset_Quelle für Variablen? Was steht da drin?


Im FB y habe ich schon die Eingangswerte von E 0.0 bis E100.0 über ein ANY-Zeiger in den DB y geschrieben und genauso wieder raus. Sinn und Zweck der Verwendung des Anyzeiger war, das die Bausteine immer wieder verwendet werden können und sich selbst über die Variablen die Adresse holen. Das funktioniert auch, nur bei meinem vorhaben mit dem Array nicht.
Hat das was mit Deinem Problem zu tun? Ich komm' nicht drauf... genausowenig, was die Verwendung von ANY-Pointern mit Wiederverwendbarkeit zu tun hat.


PS: ANY werden an FB direkt als ANY (10 Byte) übergeben. (also nicht als 6-Byte-Pointer auf einen ANY)

Harald
 
@Harald:
OK ... dann war es bei den IN_OUT ein Pointer. Ich hatte das nicht mehr ganz sicher auf dem Schirm (hatte ich aber ja auch geschrieben).

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Morgen,

vielen Dank schonmal für die Antworten.

@ Larry: Der IN-Parameter Datenholen ist als ANY ausgeführt und hat eine Länge von 10 Bytes in der Instanz.

@ Gebs: Mein Gedanke war auch durch die Anfangsadresse von Datenholen und durch die Längenangabe beim gebastelten ANY-Zeiger dem Blkmov zu übergeben. Also quasi die Daten die über den ANY Datenholen über die Bausteinschnittstelle kopieren und in meine Instanz kopieren. Die Daten bzw den Inhalt durchreichen würde dem ja gleich kommen, die Daten müssen in InstanzDB gespeichert sein.

@ PN/DP: Genau das war mein Problem. Über den Speicherbereich also Byte 6 des ANY-Zeiger gebe ich ja an was es ist durch den Hexcode, also ob es E, A, DB, IDB oder Lokaledaten sind. Nur wusste ich nicht was ich hierangeben soll, da Datenholen ja an sich kein Eingang E ist.
Ja, #Quelle ist eine ANY-Variable in Temp.
#Offset-Quelle ist eine INT-Variable in Temp und gibt den Offset der Adresse wo die Daten beginnen an, hier ist dieser Null. Da die Anfangsadresse und die Länge der Daten ja schon über "DB z.dbx 202.0 BYTE 12" am IN-Parameter angegeben sind.
Ich will die Daten die über die Bausteinschnittstelle "Datenholen" anliegen, über ein Blockmove in mein DB kopieren.

Naja den ANY-Zeiger kann man für Wiederverwendbarkeit schon verwenden. Dadurch das ich ja den ANY-Zeiger verwende und die Adresse als Variable angebe, "sucht" der ja quasi im DB danach und über die Längenangabe weiß er wieviele Daten es sind. Hat den Vorteil das ich den Baustein ja auf andere SPSen kopieren kann, den DB erzeuge und alles funktioniert genauso ohne das ich im Programm Änderungen vornehme, sondern nur noch über die Bausteinschnittstellen etwas angebe. Das hat ja auch funktioniert, wie schon in dem Kommentar erwähnt, nur da kopiere ich mit Blkmov die Daten von meinen Eingängen in den DB und genauso davon auf die Ausgänge in dem Fall ja nicht.


Ich werd mir das Beispiel morgen genauer anschauen, habe gerade leider wenig Zeit. Wollte mich aber trotzdem melden und schonmal Danke sagen.
 
Hallo,

wenn ich das Beispiel richtig verstehe, dann müsste ich mein Code wie folgt umändern:

Code:
      L     P##Datenholen            //relative Adresse #Datenholen in dieser Instanz (DI)
      TAR2                              //Transferiere Adressregister 2 in Akku 1
      UD    DW#16#FFFFFF                //Bereichskennung (DB) ausblenden
      +D                                //Addiere
      LAR1                              //Lade AR1 mit Inhalt von Akku 1: absolute Adresse #Datenholen im IDB (DI)

      LAR2  P##Quelle                   //Lade AR2: Adresse des TEMP-ANY
      L     DID [AR1,P#0.0]             //S7-code immer b#16#10 = 10hex + Datentyp + Wiederholfaktor
      T     LD [AR2,P#0.0]              //Transferiere nach Lokaldaten-Doppelwort Byte 0 von AR2
      L     DIW [AR1,P#4.0]             //Lade DB-Nummer
      T     LW [AR2,P#4.0]              //Transferiere nach Lokaldaten-Wort Byte 4 von AR2
      L     DID [AR1,P#6.0]             //Lade Bereichsadresse
      T     LD [AR2,P#6.0]              //Transferiere nach Lokaldaten-Doppelwort Byte 6 von AR2

Wäre das so korrekt? Entschuldigt, bin aber leider noch nicht so firm mit ANY-Zeiger.
 
Ja, so geht das.
Davor MUSS aber noch der Inhalt des AR2 gesichert werden (TAR2 #tmp_DW_AR2_Save) und danach wiederhergestellt (LAR2 #tmp_DW_AR2_Save).

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich mach's immer so:
Code:
      TAR1  #SaveAR1
      TAR2  #SaveAR2

      LAR1  #SaveAR2
      L     P##pTCON_PAR  //ANY-Pointer am FB-IN
      +AR1  
      LAR2  P##pTCON_PAR_tmp //ANY-Pointer im Temp

      L     D [AR1,P#0.0]
      T     LD [AR2,P#0.0]
      L     D [AR1,P#4.0]
      T     LD [AR2,P#4.0]
      L     W [AR1,P#8.0]
      T     LW [AR2,P#8.0]

      LAR1  #SaveAR1
      LAR2  #SaveAR2

Muss man eigentlich L DID [AR1,P#0.0] schreiben?
Funktionieren tut's zumindest...
 
Die Sicherung des AR1 und AR2 mache ich am Anfang meiner Funktion und am Ende wird diese wiederhergestellt.

Dann wäre es komplett so richtig:

Code:
//Sicherung
TAR1  #SaveAR1
TAR2  #SaveAR2


// Quelle
L     P##Datenholen            //relative Adresse #Datenholen in dieser Instanz (DI)
TAR2                              //Transferiere Adressregister 2 in Akku 1
UD    DW#16#FFFFFF                //Bereichskennung (DB) ausblenden
+D                                //Addiere
LAR1                              //Lade AR1 mit Inhalt von Akku 1: absolute Adresse #Datenholen im IDB (DI)

LAR2  P##Quelle                   //Lade AR2: Adresse des TEMP-ANY
L     DID [AR1,P#0.0]             //S7-code immer b#16#10 = 10hex + Datentyp + Wiederholfaktor
T     LD [AR2,P#0.0]              //Transferiere nach Lokaldaten-Doppelwort Byte 0 von AR2
L     DIW [AR1,P#4.0]             //Lade DB-Nummer
T     LW [AR2,P#4.0]              //Transferiere nach Lokaldaten-Wort Byte 4 von AR2
L     DID [AR1,P#6.0]             //Lade Bereichsadresse
T     LD [AR2,P#6.0]              //Transferiere nach Lokaldaten-Doppelwort Byte 6 von AR2


//Ziel
LAR1  P##Ziel                     //Lade die Anfangsadresse des ANY-Pointers in AR1
L     B#16#10                     //S7-code immer b#16#10 = 10hex
T     LB [AR1,P#0.0]
L     B#16#2                      //Datentyp: 02 = Byte
T     LB [AR1,P#1.0]
L     #Laenge                     //Länge der Daten bzw. Anzahl/Wiederholfaktor
T     LW [AR1,P#2.0]
L     DINO                        //DINO liest DBNR aus, wenn nicht benötigt: 0
T     LW [AR1,P#4.0]
L     B#16#84                     //Auswahl Eingänge bzw Speicherbereich: 84 = DB
T     LB [AR1,P#6.0]
L     B#16#0                      //Adressbelegung: 0 = 000
T     LB [AR1,P#7.0]              //Adressformat:Byte.Bit wobei Byte aufgeteilt in Bit0-2 von 7. Byte
L     P##OUT                      //Adressanfang (Zeiger), hier im Eingang       
SLD   16                          //16mal Shift DWORD nach links (in Akku 1) damit Adressformat: .Bit = .000
SRD   16                          //16mal Shift DWORD nach rechts (in Akku 1) damit Adressformat: .Bit = .000
L     #Offset_Ziel                //Laden des Offsets
+D    
SLD   3                           //dreimal Shift nach links (in Akku 1) damit Adressformat: .Bit = .000
 T     LW [AR1,P#8.0]              //Adressformat: Byte.Bit wobei Byte in Bit0-7 von 8.Byte





// Blockmove

      CALL  "BLKMOV"
       SRCBLK :=#Quelle
       RET_VAL:=#RET_VAL_Block
       DSTBLK :=#Ziel
      NOP   0


//Wiederherstellen
LAR1  #SaveAR1
LAR2  #SaveAR2

Oder habt ihr noch Verbesserungsvorschläge?
Wieso funktioniert auch Ronins Beispiel ohne Bereichskennung ausblenden?
 
Zuletzt bearbeitet:
Ich mach's immer so:
[...]
Muss man eigentlich L DID [AR1,P#0.0] schreiben?
Funktionieren tut's zumindest...
Nein, muß man nicht - ist aber sicherer und deutlicher lesbar. Die Speicherbereichskennung ist ja schon in den ARx enthalten - hoffentlich auch richtig!!!

Du hast Glück daß Dein Code funktioniert, denn Dein Code hat 2 Probleme:
- er funktioniert nur mit Instanz-DB max. 4kB, weil bei +AR1 nur ein 16-Bit-Offset addiert wird
- Dein AR1 zeigt auf "DB" statt "DI"! Die Bereichskennung, die vor dem +AR1 in AR1 ist wird durch +AR1 nicht verändert. Würdest Du "L DID" verwenden, dann wäre das egal. Irgendwie hat Siemens das wohl vorausgesehen und dafür gesorgt, daß beim Eintritt in einen FB das DI- und das DB-Register auf den selben DB zeigen.

siehe den Link in #3 http://www.sps-forum.de/simatic/63603-any-pointer-ueber-bausteinschnittstelle-2.html#post481732
Da ist das Problem mit +AR1 erklärt und es sind beide Varianten des indirekten Kopierens gezeigt (bereichsinterne und bereichsübergreifende registerindirekte Adressierung)

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wieso funktioniert auch Ronins Beispiel ohne Bereichskennung ausblenden?
Weil er zum Addieren des Multiinstanz-Offsets aus AR2 die Operation "+AR1" verwendet - da ist das Ausblenden (genauer: Ignorieren) schon enthalten.

Oder habt ihr noch Verbesserungsvorschläge?
Dein zusammenbasteln des #Ziel-ANY sieht verdächtig falsch aus. Ich kann es nicht nachvollziehen.
Wo holst Du den gewünschten Zielbereich her? Aus welchen Teil-Werten soll die Adresse zusammengesetzt werden?

Code:
//Ziel
LAR1  P##Ziel                     //Lade die Anfangsadresse des ANY-Pointers in AR1
L     B#16#10                     //S7-code immer b#16#10 = 10hex
T     LB [AR1,P#0.0]
L     B#16#2                      //Datentyp: 02 = Byte
T     LB [AR1,P#1.0]
L     #Laenge                     //Länge der Daten bzw. Anzahl/Wiederholfaktor
T     LW [AR1,P#2.0]
[COLOR="#FF0000"]L     DINO                        //DINO liest DBNR aus, wenn nicht benötigt: 0[/COLOR]
T     LW [AR1,P#4.0]
[COLOR="#FF0000"]L     B#16#84                     //Auswahl [B]Eingänge (???)[/B] bzw Speicherbereich: 84 = DB
T     LB [AR1,P#6.0]
L     B#16#0                      //Adressbelegung: 0 = 000
T     LB [AR1,P#7.0]              //Adressformat:Byte.Bit wobei Byte aufgeteilt in Bit0-2 von 7. Byte
L     P##OUT                      //Adressanfang (Zeiger), hier im Eingang       
SLD   16                          //16mal Shift DWORD nach links (in Akku 1) damit Adressformat: .Bit = .000
SRD   16                          //16mal Shift DWORD nach rechts (in Akku 1) damit Adressformat: .Bit = .000
L     #Offset_Ziel                //Laden des Offsets
+D    
SLD   3                           //dreimal Shift nach links (in Akku 1) damit Adressformat: .Bit = .000
 T     LW [AR1,P#8.0]              //Adressformat: Byte.Bit wobei Byte in Bit0-7 von 8.Byte
[/COLOR]

Die "hardcodierte" Angabe der Speicherbereichskennung "16#84" löst man übersichtlicher durch "L P#DBX0.0" - da muß man nicht wissen, welche Kennung der Speicherbereich hat.

Harald
 
Danke Euch und vorallem Harald,
dass heißt wenn ich eine feste Adresse Angeben anstatt P##Out in Form von L P#DBX0.0 bräuchte ich nicht den Speicherbereich in Byte 6 schreiben oder wie meinst du das?

Byte 7 musste ich mit "0" beschreiben, da es mit der "hardcodierten" Variante sonst nicht funktioniert hat.
Byte 8 musste ich so komisch shifften, da mir auch sonst die übergabe nicht funktioniert hat.
 
- er funktioniert nur mit Instanz-DB max. 4kB, weil bei +AR1 nur ein 16-Bit-Offset addiert wird
Ne das passt schon. Über das bin ich aber auch schon drüber gestolpert. Es kommt darauf an in welcher Reihe man die ARs addiert. (Siehe hier - letzter Beitrag)
Im Screenshot unten ist es schön ersichtlich.

- Dein AR1 zeigt auf "DB" statt "DI"! Die Bereichskennung, die vor dem +AR1 in AR1 ist wird durch +AR1 nicht verändert. Würdest Du "L DID" verwenden, dann wäre das egal. Irgendwie hat Siemens das wohl vorausgesehen und dafür gesorgt, daß beim Eintritt in einen FB das DI- und das DB-Register auf den selben DB zeigen.
Da hast du mich auf was interessantes gebracht. Die Variante die ich verwende arbeitet tatsächlich mit der DB-Bereichskennung. Dann wir der Pointer also direkt aus dem DB ins Temp kopiert...
Ist zwar nicht unbedingt falsch aber, ob ich beim nächsten mal nicht deine verwenden... ;)

Hier noch mal beide Varianten mit simulierten Werten....
CopyAny.jpg

[EDIT] Hab's grad nochmal mit L DBNO und L DINO verifiziert. Siemens sorgt tatsächlich dafür dass das DB-Register und das DI-Register beim eintreten in den FB gleich sind....
Mann, da hätte ich, wenn irgendwo das DB-Register nicht passt, aber irgendwann mal ganz schön auf die Schnauze fallen können... :icon_redface:
Danke nochmal PN/DP!
[/EDIT]
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
dass heißt wenn ich eine feste Adresse Angeben anstatt P##Out in Form von L P#DBX0.0 bräuchte ich nicht den Speicherbereich in Byte 6 schreiben oder wie meinst du das?

Byte 7 musste ich mit "0" beschreiben, da es mit der "hardcodierten" Variante sonst nicht funktioniert hat.
Byte 8 musste ich so komisch shifften, da mir auch sonst die übergabe nicht funktioniert hat.
Es kommt immer gut, wenn man die eigentliche Problemursache erkundet und es dann gezielt richtig macht, statt solange irgendwas auszuprobieren bis es anscheinend funktioniert. Man muß auch wissen, warum es funktioniert. Gerade bei der Maschinenprogrammierung ist es sehr wichtig daß man genau weiß was man tut.

Nochmal meine Frage:
Wo holst Du den gewünschten Zielbereich her? Aus welchen Teil-Werten soll die Adresse zusammengesetzt werden?
Was willst Du eigentlich erreichen?
Wenn Du diese Fragen beantworten kannst, dann können wir Dir zeigen wie es richtig gemacht wird.

Wenn Du schon die Quelladresse als ANY übergibst, warum übergibst Du dann die Zieladresse nicht auch als ANY?

Harald
 
Im Grunde geht es darum einen Datensatz (DB z) von einem IN-Parameter in den DB y des FB y zuschreiben.
Der Datensatz ist ein Array und liegt wie schon beschrieben am IN (Datenholen) an: "DB_z".S[2].A1.Read.DATEN.Datenteile.teilenummer

In dem DB y habe ich ein Datensatz als Struktur OUT in STAT hinterlegt. In OUT sollen ab einem Byte x die Daten die am IN anliegen übertragen werden.
Durch den ANY-Zeiger Ziel und Blockmove sollte die Anzahl Bytes übertragen werden.
Ziel ist wie Quelle als ANY im Temp des FB hinterlegt.

Reicht euch das als Beschreibung und ist es verständlich?
 
Ich schätze ich habe Dich jetzt verstanden.
Dein FB soll einen an seinem IN:Datenholen angegeben Datensatz in sein eigenes STAT in die Struktur OUT (+ evtl. x Byte Versatz zum Anfang der Struktur) kopieren?

Das könnte so aussehen:
Code:
//AR2 sichern  (Offset dieser Multiinstanz mit Bereichskennung DB!)
      TAR2  #SaveAR2

//Quelle
      L     P##Datenholen               //relative Adresse #Datenholen in dieser Instanz (DI)
      TAR2                              //Lade Adressregister2 mit Offset dieser Multiinstanz (DB) in Akku1
      UD    DW#16#FFFFFF                //Bereichskennung (DB) ausblenden
      +D                                //Addiere
      LAR1                              //Lade AR1 mit Inhalt von Akku1: absolute Adresse #Datenholen im IDB (DI)

      LAR2  P##Quelle                   //Lade AR2 mit Adresse des TEMP-ANY #Quelle
      L     DID [AR1,P#0.0]             //S7-ID 16#10 + Datentyp + Wiederholfaktor aus #Datenholen
      T     LD [AR2,P#0.0]              //schreibe in den ANY #Quelle
      L     DIW [AR1,P#4.0]             //Lade DB-Nummer aus #Datenholen
      T     LW [AR2,P#4.0]              //schreibe in den ANY #Quelle
      L     DID [AR1,P#6.0]             //Lade Bereichsadresse aus #Datenholen
      T     LD [AR2,P#6.0]              //schreibe in den ANY #Quelle


//Ziel  (hier AR2: Adresse des TEMP-ANY #Quelle)
      LAR1  P##Ziel                     //Lade AR1 mit Adresse des TEMP-ANY #Ziel
      L     LD [AR2,P#0.0]              //S7-ID 16#10 + Datentyp + Wiederholfaktor aus #Quelle
      T     LD [AR1,P#0.0]              //übernehmen in den ANY #Ziel

      L     DINO                        //Lade eigene Instanz-DB-Nr
      T     LW [AR1,P#4.0]              //schreibe die in den ANY #Ziel

      L     P##OUT                      //relative Adresse der Struktur #OUT in STAT dieser Instanz (DI)       
      L     #SaveAR2                    //Offset dieser Multiinstanz (DB)
      UD    DW#16#FFFFFF                //Bereichskennung (DB) ausblenden
      +D                                //Addiere
//= Akku1 enthält jetzt die absolute Adresse der Struktur #OUT in STAT dieser Instanz (DI)

//sollte noch ein Versatz zum Anfang der Struktur #OUT addiert werden müssen: 
//A falls der Versatz in einer Instanz-Variable (IN, INOUT, STAT) gespeichert ist
//A      LAR2  #SaveAR2                    //AR2 wiederherstellen für Zugriff auf Instanz-Variable
//A      L     #iExtraOffset               //INT: Anzahl Bytes Versatz (aus einer Instanz-Variable)
//A      SLD   3                           //in Pointerformat P#<versatz>.0 wandeln 
//A      +D                                //zur absoluten Adresse #OUT im Akku1 dazuaddieren 

//B oder falls Versatz fest angegeben werden kann:
//B      L     P#10.0                      //z.B. fest 10 Byte im Pointerformat
//B      +D                                //zur absoluten Adresse #OUT im Akku1 dazuaddieren 

//= Akku1 enthält jetzt die absolute Adresse des Ziels in STAT dieser Instanz (DI)
      T     LD [AR1,P#6.0]              //schreibe Akku1 in die Bereichsadresse in den ANY #Ziel


//AR2 wiederherstellen
      LAR2  #SaveAR2

//Blockmove
      CALL  "BLKMOV"
       SRCBLK :=#Quelle                 //von IN:#Datenholen
       RET_VAL:=#RET_VAL_Block
       DSTBLK :=#Ziel                   //nach STAT:#OUT (+ ExtraOffset)

//...
//AR2 wiederherstellen
      LAR2  #SaveAR2

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Harald,
ja genau das habe ich vor. Nur von einem z.B. DB20 in den DB30 des FB30.

Paar Fragen hätte ich noch:


Code:
//Quelle
L     P##Datenholen               //relative Adresse #Datenholen in dieser Instanz (DI)
TAR2                              //Lade Adressregister2 mit Offset dieser Multiinstanz (DB) in Akku1

Stimmt das TAR2 weil du LADE AR2 kommentierst?

Code:
//Ziel  (hier AR2: Adresse des TEMP-ANY #Quelle)
LAR1  P##Ziel                     //Lade AR1 mit Adresse des TEMP-ANY #Ziel
L     LD [AR2,P#0.0]              //S7-ID 16#10 + Datentyp + Wiederholfaktor aus #Quelle
T     LD [AR1,P#0.0]              //übernehmen in den ANY #Ziel

Ist es wirklich besser den Datentyp und Wiederholfaktor direkt zu übernehmen, also der ANY übernimmt dann die Länge über den Datensatz der am IN anliegt?
Mir gefällt das nämlich nicht so gut, wenn mal durch ein Zufall jemand den Datensatz am Eingang ändern sollte, kopiert der ja automatisch zuviel und würde die Werte auf ein Adressbereich in meinem DB schreiben was nicht vorgesehen ist..
Deshalb habe ich hier lieber explizit die Länge bzw Wiederholfaktor angegeben, quasi Zur Sicherheit, das nicht mehr Werte wie vorgesehen geschrieben werden.


Code:
//Ziel  (hier AR2: Adresse des TEMP-ANY #Quelle

      L     P##OUT                      //relative Adresse der Struktur #OUT in STAT dieser Instanz (DI)       
      L     #SaveAR2                    //Offset dieser Multiinstanz (DB)
      UD    DW#16#FFFFFF                //Bereichskennung (DB) ausblenden
      +D                                //Addiere

Mit Bereichskennung ausblenden und Laden des AR2 ist dann die schönere Form anstelle meinem shiften (SLD 16 / SRD 16)?



Code:
//Ziel  (hier AR2: Adresse des TEMP-ANY #Quelle)

//sollte noch ein Versatz zum Anfang der Struktur #OUT addiert werden müssen: 
//A falls der Versatz in einer Instanz-Variable (IN, INOUT, STAT) gespeichert ist
//A      LAR2  #SaveAR2                    //AR2 wiederherstellen für Zugriff auf Instanz-Variable
//A      L     #iExtraOffset               //INT: Anzahl Bytes Versatz (aus einer Instanz-Variable)
//A      SLD   3                           //in Pointerformat P#<versatz>.0 wandeln 
//A      +D                                //zur absoluten Adresse #OUT im Akku1 dazuaddieren  

//= Akku1 enthält jetzt die absolute Adresse des Ziels in STAT dieser Instanz (DI)
      T     LD [AR1,P#6.0]              //schreibe Akku1 in die Bereichsadresse in den ANY #Ziel

Oder ersetzt hier das LAR2 #SaveAR2 mein shiften?
Am Ende Transferierst du Lokaldoppelwort auf Byte 6 was ist mit Byte 8? Wird das somit mit überschrieben wegen LD statt LW?

Danke für die Hilfe und hoffe meine Fragen klingen nicht zu stupide.
 
Stimmt das TAR2 weil du LADE AR2 kommentierst?
Deutsche Sprake, schwere Sprake...
gemeint ist: "Lade das Adressregister2 (enthält den Offset dieser Multiinstanz mit Bereichskennung "DB") in den Akku1"

Eigentlich ist es nicht nötig, Lade/Transfer-Befehle mit "Lade/Transferiere von Register x zu Register y" zu kommentieren - das sagt der Befehl ja selber schon aus. Der Kommentar sollte zeigen, was da kopiert wird.


Ist es wirklich besser den Datentyp und Wiederholfaktor direkt zu übernehmen, also der ANY übernimmt dann die Länge über den Datensatz der am IN anliegt?
Mir gefällt das nämlich nicht so gut, wenn mal durch ein Zufall jemand den Datensatz am Eingang ändern sollte, kopiert der ja automatisch zuviel und würde die Werte auf ein Adressbereich in meinem DB schreiben was nicht vorgesehen ist..
Deshalb habe ich hier lieber explizit die Länge bzw Wiederholfaktor angegeben, quasi Zur Sicherheit, das nicht mehr Werte wie vorgesehen geschrieben werden.

Wo bleibt denn da Deine "Wiederverwendbarkeit", wenn Du bei jeder Wiederverwendung den FB anpassen mußt?

Du kannst die Länge sicherheitshalber explizit angeben, entweder aus einer Variable oder direkt als Konstante hardcodiert:
Code:
//Wenn die Länge in einer Instanz-Variable (IN, INOUT, STAT) gespeichert ist 
//Ziel
      LAR1  P##Ziel                     //Lade AR1 mit Adresse des TEMP-ANY #Ziel
      L     W#16#1002                   //S7-ID 16#10 + Datentyp Byte 16#02
      T     LW [AR1,P#0.0]              //schreibe in den ANY #Ziel

      LAR2  #SaveAR2                    //AR2 wiederherstellen für Zugriff auf Instanz-Variable
      L     #iLaenge                    //INT: Anzahl Bytes
      T     LW [AR1,P#2.0]              //schreibe als Wiederholfaktor in den ANY #Ziel

      L     DINO                        //Lade eigene Instanz-DB-Nr
      ...

//besser: die Länge fest als Konstante, z.B. 10 Bytes
//Ziel
      LAR1  P##Ziel                     //Lade AR1 mit Adresse des TEMP-ANY #Ziel
      L     DW#16#1002000A              //S7-ID 16#10 + Datentyp Byte 16#02 + Wiederholfaktor 10
      T     LD [AR1,P#0.0]              //schreibe in den ANY #Ziel

      L     DINO                        //Lade eigene Instanz-DB-Nr
      ...

//oder besser lesbar/anpassbar
      LAR1  P##Ziel                     //Lade AR1 mit Adresse des TEMP-ANY #Ziel
      L     W#16#1002                   //S7-ID 16#10 + Datentyp Byte 16#02
      T     LW [AR1,P#0.0]              //schreibe in den ANY #Ziel
      L     10                          //Wiederholfaktor 10
      T     LW [AR1,P#2.0]              //schreibe in den ANY #Ziel

      L     DINO                        //Lade eigene Instanz-DB-Nr
      ...


Mit Bereichskennung ausblenden und Laden des AR2 ist dann die schönere Form anstelle meinem shiften (SLD 16 / SRD 16)?
Ja. Weil meine Form ist die korrekte und kürzere Form. ;)
Das Ausblenden der Bereichskennung kann man natürlich auch mit Shiften machen, dann aber bitteschön korrekt: SLD 8 + SRD 8
Das Laden und Addieren des AR2 fehlt bei Dir. Weil #OUT eine Instanz-Variable ist muß aber der Instanzoffset aus AR2 noch addiert werden. (oder soll das Dein #Offset_Ziel sein? das ist aus Deinem Code nicht ersichtlich)
Dein SLD 3 steht an der falschen Stelle, P##OUT ist schon im Pointerformat und darf nicht nochmal geshiftet werden.


Oder ersetzt hier das LAR2 #SaveAR2 mein shiften?
Nein, das hat nichts damit zu tun.
Es soll auf eine Instanzvariable zugegriffen werden, dazu muß in AR2 der originale Instanzoffset stehen.
Siehe meinen Kommentar: "LAR2 #SaveAR2 //AR2 wiederherstellen für Zugriff auf Instanz-Variable"


Am Ende Transferierst du Lokaldoppelwort auf Byte 6 was ist mit Byte 8? Wird das somit mit überschrieben wegen LD statt LW?
Jetzt enttäuschst Du mich aber... wer mit ANY und AWL 'rummacht sollte solche Basics eigentlich wissen...
"T LD [AR1,P#6.0]" transferiert den Akku1 in das LokalDoppelwort, dessen Adresse aus dem Inhalt von AR1 + P#6.0 berechnet wird. Im Klartext: der Akku1 wird in die Bytes 6 und 7 und 8 und 9 der ANY-Variable #Ziel geschrieben.

Harald
 
Deutsche Sprake, schwere Sprake...
gemeint ist: "Lade das Adressregister2 (enthält den Offset dieser Multiinstanz mit Bereichskennung "DB") in den Akku1"

Eigentlich ist es nicht nötig, Lade/Transfer-Befehle mit "Lade/Transferiere von Register x zu Register y" zu kommentieren - das sagt der Befehl ja selber schon aus. Der Kommentar sollte zeigen, was da kopiert wird.
Alles Klar, habe ich mir so gedacht, wollte nur auf Nummer sicher gehen.

Wo bleibt denn da Deine "Wiederverwendbarkeit", wenn Du bei jeder Wiederverwendung den FB anpassen mußt?

Du kannst die Länge sicherheitshalber explizit angeben, entweder aus einer Variable oder direkt als Konstante hardcodiert:
Code:
//Wenn die Länge in einer Instanz-Variable (IN, INOUT, STAT) gespeichert ist 
//Ziel
      LAR1  P##Ziel                     //Lade AR1 mit Adresse des TEMP-ANY #Ziel
      L     W#16#1002                   //S7-ID 16#10 + Datentyp Byte 16#02
      T     LW [AR1,P#0.0]              //schreibe in den ANY #Ziel

      LAR2  #SaveAR2                    //AR2 wiederherstellen für Zugriff auf Instanz-Variable
      L     #iLaenge                    //INT: Anzahl Bytes
      T     LW [AR1,P#2.0]              //schreibe als Wiederholfaktor in den ANY #Ziel

      L     DINO                        //Lade eigene Instanz-DB-Nr
      ...

//besser: die Länge fest als Konstante, z.B. 10 Bytes
//Ziel
      LAR1  P##Ziel                     //Lade AR1 mit Adresse des TEMP-ANY #Ziel
      L     DW#16#1002000A              //S7-ID 16#10 + Datentyp Byte 16#02 + Wiederholfaktor 10
      T     LD [AR1,P#0.0]              //schreibe in den ANY #Ziel

      L     DINO                        //Lade eigene Instanz-DB-Nr
      ...

//oder besser lesbar/anpassbar
      LAR1  P##Ziel                     //Lade AR1 mit Adresse des TEMP-ANY #Ziel
      L     W#16#1002                   //S7-ID 16#10 + Datentyp Byte 16#02
      T     LW [AR1,P#0.0]              //schreibe in den ANY #Ziel
      L     10                          //Wiederholfaktor 10
      T     LW [AR1,P#2.0]              //schreibe in den ANY #Ziel

      L     DINO                        //Lade eigene Instanz-DB-Nr
      ...
Der FB wird bei den Längen der Datensätze in diesem Projekt nicht mehr angepasst, da wir eine feste und vorgegebene Länge haben.
Nur der Adressanfang kann sich ändern. Durch die Verwendung von P##OUT wird da im DB aber immer wieder passend draufzugegriffen. Diese Wiederverwendbarkeit ist hier wichtig.
Dennoch, weiß ich jetzt wenigstens wie ich auch sonst die "Wiederverwendbarkeit" nutzen kann, also vielen Dank :)
Die Besser/Lesbare Variante hatte ich ja zuvor auch so, dann belasse ich diese so an den Stellen.

Ja. Weil meine Form ist die korrekte und kürzere Form. ;)
Das Ausblenden der Bereichskennung kann man natürlich auch mit Shiften machen, dann aber bitteschön korrekt: SLD 8 + SRD 8
Das Laden und Addieren des AR2 fehlt bei Dir. Weil #OUT eine Instanz-Variable ist muß aber der Instanzoffset aus AR2 noch addiert werden. (oder soll das Dein #Offset_Ziel sein? das ist aus Deinem Code nicht ersichtlich)
Dein SLD 3 steht an der falschen Stelle, P##OUT ist schon im Pointerformat und darf nicht nochmal geshiftet werden.
Wieder was dazu gelernt, ich wusste nicht das SLD/SRD 16 falsch ist, hatte das so im Internet gelesen. Ist das Abhängig von der CPU?
Mein #Offset_Ziel ist die INT-Variable um den Offset in der Struktur zu markieren bzw den Datensatz dort abzulegen quasi: #OUT+#Offset_Ziel ab da soll der Datensatz im DB abgelegt werden.
OK, also kann ich mir der Einfachheit halber merken, dass SLD 3 nichts zusuchen hat bei ANY-Zeigern im Pointerformat also wenn die ohne direkte Adressangabe codiert wurden?


Nein, das hat nichts damit zu tun.
Es soll auf eine Instanzvariable zugegriffen werden, dazu muß in AR2 der originale Instanzoffset stehen.
Siehe meinen Kommentar: "LAR2 #SaveAR2 //AR2 wiederherstellen für Zugriff auf Instanz-Variable"



Jetzt enttäuschst Du mich aber... wer mit ANY und AWL 'rummacht sollte solche Basics eigentlich wissen...
"T LD [AR1,P#6.0]" transferiert den Akku1 in das LokalDoppelwort, dessen Adresse aus dem Inhalt von AR1 + P#6.0 berechnet wird. Im Klartext: der Akku1 wird in die Bytes 6 und 7 und 8 und 9 der ANY-Variable #Ziel geschrieben.

Harald

Sorry, ich weiß das LD 4 Bytes entspricht und somit Byte 6 bis Byte 9 beschreiben müsste, wollte aber sicher gehen. Quäl mich momentan mit ner fiesen Erkältung rum, da ist man nicht immer ganz schnell von Begriff!
Aber Vielen Dank :)
 
Zuletzt bearbeitet:
Zurück
Oben