Pointer <- Indirekter DB möglich ?

rs-plc-aa

Level-1
Beiträge
727
Reaktionspunkte
57
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
ich bin gerade auf etwas gestossen...

Ich möchte dem Pointer P#DB591.DBX 1200.0 BYTE 12 den DB über eine Variable mitteilen - geht das ?

Also z.B. so: P#DB[DB_Nr].DBX 1200.0 BYTE 12

... nur daß es halt so nicht geht :confused:

Weiß jemand die korrekte Syntax ?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn ich das richtig verstanden habe lege ich z.B. eine TEMP_VAR des Typs ANY an und füttere sie am Anfang des Bausteins wie in dem Beispiel, und setze dann die TEMP_VAR an den IN Parameter (anstatt des direkten Pointers) ?
 
ja genau.

schau dir das ruhig mal auf meiner homepage an. ich habe das dort recht ausführlich beschrieben.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Habs immer noch nicht gefunden - aber mal so probiert:

Code:
      L     W#16#1002                   // konstant gleich
      T     LW     0                    // Datentyp: INT
      L     12                          // konstant gleich
      T     LW     2                    // Datentyp: INT
      L     #DI_Number                  // IN (diesen möchte ich variabel haben)
      T     LW     4                    // Datentyp: INT
      L     1200                        // passend zu obigem Beispiel-Pointer
      SLD   3                           // ???
      OD    DW#16#84000000              // ??????
      T     LD     6                    // ?

Finde ich jetzt im VAR_TEMP -> Startadresse 0 meinen ersehnten ANY ?
 
Zuletzt bearbeitet:
@Volker: Habs jetzt gefunden auf deiner Homepage...
Somit müsste mein voriger post eigentlich beantwortet sein.
Jetzt sind mir aber Unterschiede aufgefallen:
Code:
[FONT=Lucida Console][COLOR=#000000]-> L     B#16#10                   //10h für s7[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> T     LB     0[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> L     B#16#02                   //Typ BYTE[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> T     LB1     0[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]   L     8                         //Anzahl (Wiederholungsfaktor)[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]   T     LW     2[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]   L     33                        //Datenbaustein[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]   T     LW     4[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]   L     14                        //Anfangsadresse[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]   SLD   3                         //Pointer bauen[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]   T     LD     6[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> L     B#16#84                   //Speicherbereich (hier DB)[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> T     LB     6[/COLOR][/FONT]
Am Anfang und am Ende (mit Pfeilen markiert) ist das unterschiedlich - welche Version ist jetzt richtig (für eine S7-300) ?

(Ja ich weiß - man soll sich nicht selber antworten:) )
 
@Volker: Habs jetzt gefunden auf deiner Homepage...
na also. geht doch. ;) Und nicht vergessen: Beiträge bewerten (hier und auch auf meiner hp)

Code:
[FONT=Lucida Console][COLOR=#000000]-> L     B#16#10                   //10h für s7[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> T     LB     0[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> L     B#16#02                   //Typ BYTE[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> T     LB1     0[/COLOR][/FONT]
vom prinzip das gleiche wie L w#16#1002 nur dass du die bytes einzeln transferierst (linkes byte, rechtes byte des wortes)
so kannst du aber den typ leichter angeben.
Code:
[FONT=Lucida Console][COLOR=#000000]L     14                        //Anfangsadresse[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]SLD   3                         //Pointer bauen[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]T     LD     6[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> L     B#16#84                   //Speicherbereich (hier DB)[/COLOR][/FONT]
[FONT=Lucida Console][COLOR=#000000]-> T     LB     6[/COLOR][/FONT]
sieht ein bisschen komisch aus. hat aber durchaus seinen sinn.
du lädst den pointer in das ld 6. weil, dort gehört er hin.
der speicherbereich des anyzeigers liegt aber im LB 6 (bedenke: nur das byte) deshalb wird der vorige transfer teilweise durch diesen überschrieben.
Code:
(Ja ich weiß - man soll sich nicht selber antworten:) )
würde ICH so nicht sagen.
wenn du die lösung selbst gefunden hast, und die lösung hier präsentierst, müssen sich andere leute keine weiteren gedanken darüber machen und leute die evtl das gleiche prob haben finden eine lösung
 
So nun für die Nachwelt die Version für die ich mich nun entschieden habe:

@Volker: Da war noch ein Tippfehler drin bei dir in der Version von deiner Homepage - T LB1 0 sollte mit sicherheit T LB 1 heissen...

Mein Verwendungszweck ist der daß ich nun meinen "Alarm_FB" (beinhaltet die komplette Abwicklung der Alarm_S / Alarm_SQ geschichte) nun endlich auch multiinstanzfähig hinbekommen habe !

Der Pointer ist zuständig für die Übergabe der jeweiligen Begleitwerte an die SFC 17 / 18 Aufrufe. Er bildet sich aus dem Instanzdatenbaustein des FBs, der Länge und der Anfangsadresse (hier Beginn des STAT-Bereichs)

So baute ich nun im ersten Netzwerk folgendes ein, und kann - da die Struktur immer gleich ist die Nummer des Instanz-DBs von aussen reinschieben !

Für alle die es interressiert:

Code:
// Den Begleitwerten einmalig den passenden Instanzdatenbaustein zuweisen
// Hierzu einen ANY_Pointer verwenden:
// Pointer im Format für die Begleitwerte der Alarm_S und SQ SFCs bilden
      L     B#16#10                     // TYP (Teil1): 10h für s7
      T     LB     0
      L     B#16#2                      // TYP (Teil2): BYTE
      T     LB     1
      L     12                          // Anzahl (Bytes) ab Startadresse
      T     LW     2
      L     #DI_Number                  // Nummer des Datenbausteins (IN:INT)
      T     LW     4
      L     1200                        // Startadresse im DB (Beginn STAT-Bereich)
      SLD   3                           // Pointer erzeugen
      T     LD     6
      L     B#16#85                     // Speicherbereichstyp: 85h für IDB
      T     LB     6
// Der hiermit erzeugte Pointer liegt nun im TEMP-Bereich ab Adresse 0
// Dort eine Variable #Begleitwerte des Typs ANY anlegen und bei SD zuweisen.

edit: Speicherbereichstyp von 84 auf 85 geändert (da Instanz-DB) !
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Irgendwas stimmt da doch noch nicht

:confused: ...
Jetzt muss ich die Geschichte doch noch mal aufgreifen - leider.

Also ich stehe jetzt kurz vor der Abnahme der Anlage und musste mich mit allerhand Kram rumärgern (Teile kamen nicht rechtzeitig / defekt - usw.) und hatte im zuge der IB manchmal schon ein wenig gestutzt daß bis jetzt noch kein Begleitwert funktionierte (immer 0). Heute hatte ich dann mal Zeit der Sache auf den Zahn zu fühlen.

Die beschriebene Methode muss irgendwo noch einen Fehler haben - ich habe nun mal zum Test an einer Störung die ich auf jeden Fall herbei bringe und die einen Begleitwert hat am SD-Eingang der SFC17 den AnyZeiger entfernt und direkt den ersten (in dem Fall einzigen) Begleitwert direkt angegeben -> das hat funktioniert

Das bedeutet also daß am Panel der richtige Text mit dem passenden Begl.Wert ankam.

Was also geht an dem AnyZeiger nicht ?

Der AnyZeiger wird am Beginn des FBs gebildet und verweist im Prinzip auf den aktuellen Instanzdatenbaustein des Alarm-FBs, genauer gesagt auf dessen Beginn des STAT-Bereichs. Hier sind 3 Begleitwerte deklariert die vor jedem Aufruf einer SFC 17/18 mit den passenden Werten gefüllt werden. Im Endeffekt wird das so benötigt da die SFC 17/18 nur alle Begleitwerte in einem Rutsch einlesen kann, also bei mehr als einem mit einem Pointer. Das hatte bisher bei nur einer einzigen Instanz funktioniert da der Pointer die Adresse des IDBs beinhaltete. Nun möchte ich aber den selben FB in mehreren Instanzen laufen lassen - daher benötige ich nun einen Umweg um die Adresse anzugeben. Der Ansatz war eigentlich auch schlüssig nur verstehe ich jetzt nicht so ganz was da nicht gehen soll.

ABER: Vielleicht geht das ja noch viel einfacher...

Ne Alternative hätte ich schon mal ausgedacht:

Warum den Umweg überhaupt über den STAT-Bereich machen ? Wäre es nicht schon ausreichend die Begleitwerte in den TEMP-Bereich zu verschieben und einen "normalen" Pointer darauf zu richten ?

Damit stets der korrekte Wert mitgegeben wird muß dieser ja sowieso immer neu zugewiesen werden.

Sprich: Die Begleitwerte müssen ja gar nicht gespeichert werden da sie beim nächsten SFC17/18 Aufruf im selben FB ohnehin immer erneuert werden müssen...

Bin mir jetzt auch ziemlich sicher daß das klappen würde, nur hätte ich trotzdem zu gern gewusst was da jetzt mit dem AnyZeiger nicht geht.
 
Hallo!

Stelle sonst mal deinen Pointer so wie du ihn gemacht hast hier herein.

Ich mache es so: (Habe ich jetzt auf einen Instanz DB geändert)
Code:
//Für Flexible gestalteten Datenbaustein
      L     DINO                        //Wenn der Pointer in dem FB gebildet wird von dem du auf den Instanz Datenbaustein zugreifen willst (DINO = Nummer des Insatnzdatenbaustein)
      T     #DB_Nummer                  //Es kann aber auch ein X beliebige Datenbaustein Nummer (vorrausgesetzt es gibt den Datenbaustein) in DB_Nummer Transferiert werden
 
//ANY Pointer für Datentypen
      L     P##Temp_ANY_Pointer_in      //Lade Pointer von Variable
      LAR1                              //Schreibe Pointer in Adressregister 1
      L     B#16#10                     //Syntax ID für Step7
      T     LB [AR1,P#0.0]
      L     B#16#2                      //Wert für TYP: 1 Bool, 2 Byte, 3 Char, 4 Word, 5 Int, 6 Dword, 7 Dint, 8 Real, 9 Date, A TOD, B Time, C S5Time, E DT, 13 String
      T     LB [AR1,P#1.0]
      L     DILG                        //Anzahl der zu Übertragenden Daten zb. für 5 Byte einfach 5 (in diesem fall wird der ganze DB kopiert, Bei globalen DB den Befehl DBLG)
      T     LW [AR1,P#2.0]
      L     #DB_Nummer                  //Datenbausteinnummer
      T     LW [AR1,P#4.0]
      L     P#DBX 0.0                   //Bereichszeiger, in diesem Fall vom ersten Bit an. Wenn von Byte 10 an erwünscht dann  P#DBX 10.0 
      T     LD [AR1,P#6.0]
 
      CALL  SFC   20
       SRCBLK :=#Temp_ANY_Pointer_in
       RET_VAL:=MW0
       DSTBLK :=#Temp_ANY_Pointer_out
 
Alle Variablen sind im Temp bereich abgelegt
Temp_ANY_Pointer_in : ANY ; 
Temp_ANY_Pointer_out : ANY ; 
DB_Nummer : INT ;

Ich hoffe es hilft dir nochmals weiter.

godi
 
Na ja ich hatte es so wie es oben gepostet ist - also:
Code:
// Den Begleitwerten einmalig den passenden Instanzdatenbaustein zuweisen
// Hierzu einen ANY_Pointer verwenden:
// Pointer im Format für die Begleitwerte der Alarm_S und SQ SFCs bilden
      L     B#16#10                     // TYP (Teil1): 10h für s7
      T     LB     0
      L     B#16#2                      // TYP (Teil2): BYTE
      T     LB     1
      L     12                          // Anzahl (Bytes) ab Startadresse
      T     LW     2
      L     #DI_Number                  // Nummer des Datenbausteins (IN:INT)
      T     LW     4
      L     1200                        // Startadresse im DB (Beginn STAT-Bereich)
      SLD   3                           // Pointer erzeugen
      T     LD     6
      L     B#16#85                     // Speicherbereichstyp: 85h für IDB
      T     LB     6
// Der hiermit erzeugte Pointer liegt nun im TEMP-Bereich ab Adresse 0
// Dort eine Variable #Begleitwerte des Typs ANY anlegen und bei SD zuweisen.

Ok die Übergabe von #DI_Number wäre überflüssig wenn man L DINO verwendet, klar.

Was bei deinem Beispiel für mich nicht klar ist - und das ist ja genau das Thema wo ich null Ahnung von habe - was mit dem Adressregister passiert?

Ganz einfach formuliert hätte es ein variabler Pointer werden sollen der unabhängig welche Nummer der aktuelle Instanz-DB hat -> immer auf den Beginn des STAT_Bereichs zeigt, weil dort die drei einzelnen Begleitwerte zwischengespeichert werden die nur als "12 Byte Stück" der SFC 17/18 mitgegeben werden können...

Daher meine Idee das aus dem STAT Bereich rauszuschmeißen und in den TEMP Bereich verschieben.

Dann würde der Pointer IMMER z.B. P#L0.0 Byte 12 heissen - an jedem SFC17/18 CALL. Der aktuelle Wert muss ja ohnehin passend zur Meldung UNMITTELBAR vorher reinkopiert werden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Habe dir das mit der indirekten Adressierung noch mal Kommentiert villeicht hilfts weiter. Ansonsten im Forum suchen und die Hilfe von S7 lesen. Da ist das ganze auch brauchbar beschrieben.

Code:
//Für Flexible gestalteten Datenbaustein
      L     DINO                        //Wenn der Pointer in dem FB gebildet wird von dem du auf den Instanz Datenbaustein zugreifen willst (DINO = Nummer des Insatnzdatenbaustein)
      T     #DB_Nummer                  //Es kann aber auch ein X beliebige Datenbaustein Nummer (vorrausgesetzt es gibt den Datenbaustein) in DB_Nummer Transferiert werden
//ANY Pointer für Datentypen
      L     P##Temp_ANY_Pointer_in      //Lade Pointer von Variable
      LAR1                              //Schreibe Pointer in Adressregister 1. Jetzt steht die Anfangsadresse der Variable im Adressregister 1 (wenn du in der Deklaration den Temp Bereich aufmachst hast du eine Spalte wo die Adresse steht. Dieser Wert steht jetzt im AR 1)
      L     B#16#10                     //Syntax ID für Step7
      T     LB [AR1,P#0.0]              //Transferiere Syntax ID für Step7 in das Byte 0 von Temp_ANY_Pointer_in (Warum Byte 0? Wegen dem P#0.0 => gibt Offset an)
      L     B#16#2                      //Wert für TYP: 1 Bool, 2 Byte, 3 Char, 4 Word, 5 Int, 6 Dword, 7 Dint, 8 Real, 9 Date, A TOD, B Time, C S5Time, E DT, 13 String
      T     LB [AR1,P#1.0]              //Hier wird in Byte 1 Transferiert weil AR1 + P#1.0 = Byte 1 von Temp_ANY_Pointer_in
      L     DILG                        //Anzahl der zu Übertragenden Daten zb. für 5 Byte einfach 5 (in diesem fall wird der ganze DB kopiert, Bei globalen DB den Befehl DBLG)
      T     LW [AR1,P#2.0]              //Hier wird das AR1 um P#2.0 erhöht. Also jetzt wird das Byte 2 angesprochen 
      L     #DB_Nummer                  //Datenbausteinnummer
      T     LW [AR1,P#4.0]
      L     P#DBX 0.0                   //Bereichszeiger, in diesem Fall vom ersten Bit an. Wenn von Byte 10 an erwünscht dann  P#DBX 10.0 
      T     LD [AR1,P#6.0]

      CALL  SFC   20
       SRCBLK :=#Temp_ANY_Pointer_in
       RET_VAL:=MW0
       DSTBLK :=#Temp_ANY_Pointer_out
 
Alle Variablen sind im Temp bereich abgelegt
Temp_ANY_Pointer_in : ANY ; 
Temp_ANY_Pointer_out : ANY ; 
DB_Nummer : INT ;
 
Ok, ich komm schon in etwa mit...

Jetzt dämmerts glaube ich schon langsam.

Der von mir gepostete Code macht doch eigentlich das selbe nur wird dort direkt in den Lokaldatenbereich geschrieben.

Q1: Warum also überhaupt das Adressregister benutzen ? - Geht es NUR so ? (vielleicht geht es bei mir deshalb nicht?)

Q2: Muss dies vor JEDEM Ansprechen der Daten erneut ausgeführt werden ? - Ich habe das ja nur am Anfang des FBs stehen und es soll für alle Operationen die danach den Speicherbereich verwenden gültig sein -> geht es vielleicht deshalb nicht ?
 
vom prinzip sollte dein zeiger funktionieren.
siehe mal ein bild

im unteren beispiel baust du den zeiger indirekt.
bei der anweisung lar1 siehst du, dass im ar1 die anfangsadresse 12.0 steht wie auch im deklarationsbereich.
die folgenden anweisungen mit dem ar1 beziehen sich nun auf diese anfangsadresse.
T LD [AR1,P#6.0]
dies transferiert also in das ld18

der vorteil ist offensichtlich.
fügst du ein variable vor dem any-zeiger in den dekl.bereich ein verschieben sich seine adressen und bei direkter adressierung müsstest du dein programm anpassen. bei indirekten ist das egal, da du ja mit
L P##varany
LAR1
die anfangsadresse des any-zeigers ins ar lädst.
 

Anhänge

  • Zwischenablage02.gif
    Zwischenablage02.gif
    21,3 KB · Aufrufe: 44
Zuviel Werbung?
-> Hier kostenlos registrieren
Soweit klar,
nur wenn ich das auf meinen Fall umlege dann sieht das so aus:

Du lädst "33" in den DB, baust den Zeiger und setzt Ihn an "SRCBLK"...

Ich baue den Zeiger, lade anschließend "33" und setze ihn an "SRCBLK"...

Dann fasse ich den Zeiger nicht mehr an und lade dann z.B. "44", transferiere das in den DB und gehe davon aus daß der Zeiger immer noch dort hinzeigt - setze also ohne ihn erneut zu bauen an "SRCBLK" und dachte daß dann "44" übertragen wird...

Ist hier der Fehler ?
 
die richtung ist völlig egal.
der anyzeiger bleibt dir auf jeden fall erhalten.
prüfe mal, ob du irgendwo im baustein in den lokaldatenbereich schreibst.
 

Anhänge

  • Zwischenablage04.gif
    Zwischenablage04.gif
    8,9 KB · Aufrufe: 17
Zurück
Oben