TIA TIA AnyPointer auf Wertebereich im IDB anzeigen lassen

MWerner

Member
Beiträge
6
Punkte Reaktionen
0
Zuviel Werbung?
->Hier kostenlos registrieren
Hallo,

ich bin gerade dabei eine Kommunikation zwischen zwei Modbus TCP Partnern (S7-1500 6ES7 515-2AM01-0AB0 und einem Modbus-TCP-TN) zu realisieren. Hierbei ist die SPS mein MB-Client. Hierzu verwende ich den MbClient-Baustein von Siemens. Der Datenaustausch ist gegeben, jedoch wird auf die Datenadresse beim Schreiben ein UINT und beim Lesen ein UDInt verlangt.
Generell wird ein FB geschrieben, der mehrfach aufgerufen werden soll und somit multiinstanzfähig sein muss.
Darum blieb mir nichts anderes übrig als über einen Pointer den entsprechenden Datenbereich anzusprechen wenn ich lese oder schreibe.

Hierbei will ich über den AnyPointer auf die jeweilige Variable in meinem statischen Variablen / Instanzdatenbaustein zeigen lassen und den Wert entsprechend ablegen und anschließend weiterrangieren.
Das Schreiben und Lesen auf einen globalen DB funktioniert, jedoch will ich diesen ja flexibel machen damit ich bei einem Mehrfachaufruf nicht die DB-Nr immer ändern bzw. angeben muss.
Bisher habe ich die Einstellung des Speicherbereichs auf 16#85 = Instanzdatenbaustein gelegt, was jedoch nicht funktioniert hat bzw. ich nicht weiß welche DB-Nr hier gefordert wird.
Hat jemand eine Idee wie ich diese Problematik lösen kann?

Hier ist mein aktueller Quellcode zum Lesen der Daten mit Hilfe eines globalen Datenbausteins.

Code:
LAR1  P##AnyPointer
      L     W#16#10              //SyntaxID. bei S7 immer 10
      T LB [ AR1 , P#0.0 ]
      L     W#16#7               //Typ 7 = DINT
      T LB [ AR1 , P#1.0 ]
      L     1                    //Anzahl Bytes
      T LW [ AR1 , P#2.0 ]
     [B] L     1002                 //Quell-DB 1002 = globaler DB[/B]
      T LW [ AR1 , P#4.0 ]
      L     0                    //Anfang der Quelle
      SLD   3
      T LD [ AR1 , P#6.0 ]
      [B]L     B#16#84              //Speicherbereich (hier DB) 84 = DB / 85 = IDB[/B]
      T LB [ AR1 , P#6.0 ]

...

  CALL  #MbClient01
         REQ          :=#xReq01
         DISCONNECT   :=0
         MB_MODE      :="MbKonfig".ModeOut01
         MB_DATA_ADDR :="MbKonfig".Data_AddrOut01
         MB_DATA_LEN  :=1
         DONE         :=#xDone01
         BUSY         :=#xBusy01
         ERROR        :=#xError01
         STATUS       :=#wStatus01
         MB_DATA_PTR  :=[B]#AnyPointer[/B]
         CONNECT      :="MbKonfig".Connect01


Vielen Dank für eure Hilfe
 

Ralle

Supermoderator
Teammitglied
Beiträge
14.951
Punkte Reaktionen
3.705
du kannst evtl. die DB-Nummer feststellen::

Instanz-DB

L DINO: Nummer eines Instanz-Datenbausteins in Akkumulator 1 laden
Beschreibung
Mit der Anweisung "Nummer eines Instanz-Datenbausteins in Akkumulator 1 laden" laden Sie die Nummer eines über das Datenbausteinregister geöffneten Instanz-Datenbausteins in Akkumulator 1. Der vorherige Inhalt des Akkumulators 1 wird dabei in Akkumulator 2 verschoben.
Wenn vor der Ausführung der Anweisung kein Instanz-Datenbaustein über das Datenbausteinregister geöffnet worden ist, wird in Akkumulator 1 der Wert "0" geladen.
Die Statusbits werden durch die Anweisung nicht beeinflusst.
Beispiel
Das folgende Beispiel zeigt die Funktionsweise der Anweisung:
AWL
Erläuterung
AUFDI "InstanceDataBlock"// Datenbaustein öffnen und die Nummer des Datenbausteins in das DI-Register übertragen.
L DINO// Nummer des geöffneten Datenbausteins in Akkumulator 1 laden.
L "MyTag_1"// Vergleichswert laden
==I// Vergleichen, ob die Nummer des Datenbausteins gleich dem Wert des Operanden "MyTag_1" ist.
= "MyTag_2"// Abfrageergebnis dem Operanden "MyTag_2" zuweisen.

Global-DB:


L DBNO: Nummer eines Global-Datenbausteins in Akkumulator 1 laden
Beschreibung
Mit der Anweisung "Nummer eines Global-Datenbausteins in Akkumulator 1 laden" laden Sie die Nummer eines über das Datenbausteinregister geöffneten Global-Datenbausteins in Akkumulator 1. Der vorherige Inhalt des Akkumulators 1 wird dabei in Akkumulator 2 verschoben.
Wenn vor der Ausführung der Anweisung kein Global-Datenbaustein über das Datenbausteinregister geöffnet worden ist, wird in Akkumulator 1 der Wert "0" geladen.
Die Statusbits werden durch die Anweisung nicht beeinflusst.
Beispiel
Das folgende Beispiel zeigt die Funktionsweise der Anweisung:
AWL
Erläuterung
AUF "GlobalDataBlock"// Globalen Datenbaustein öffnen und die Nummer des Datenbausteins in das DB-Register übertragen.
L DBNO// Nummer des geöffneten Datenbausteins in Akkumulator 1 laden.
L "MyTag_1"// Vergleichswert laden
==I// Vergleichen, ob die Nummer des Datenbausteins gleich dem Wert des Operanden "MyTag_1" ist.
= "MyTag_2"// Abfrageergebnis in den Operanden "MyTag_2" schreiben.

Ich kann nicht genau sagen, ob es reicht eine StatiVar zu öffnen un danach die DI-Nummer gelesen werden kann. Wäre mal auszuprobieren.
 
Zuletzt bearbeitet:

Windoze

Well-known member
Beiträge
209
Punkte Reaktionen
111
Zuviel Werbung?
->Hier kostenlos registrieren
Hallo,

ich kenne den MbClient Baustein nicht genau, aber versuch doch mal an MB_DATA_PTR das Symbol deiner Instanzvariable zu schreiben.
Normalerweise wird dann der passende Pointer intern erzeugt.
 
OP
M

MWerner

Member
Beiträge
6
Punkte Reaktionen
0
Vielen Dank für Ihre Antwort. @Ralle

Jedoch habe ich bei Ihrer Lösung ja wiederum das Problem, dass ich den IDB angeben muss um die Nummer zu ermitteln und wäre somit nicht unabhängig von diesem.
Gibt es eine Möglichkeit über diesen oder einen ähnlichen Befehl wie AUFDI die Nummer des IDBs über den FB zu ermitteln?
 
Zuletzt bearbeitet:
OP
M

MWerner

Member
Beiträge
6
Punkte Reaktionen
0
Hallo,

ich kenne den MbClient Baustein nicht genau, aber versuch doch mal an MB_DATA_PTR das Symbol deiner Instanzvariable zu schreiben.
Normalerweise wird dann der passende Pointer intern erzeugt.

Vielen Dank für Ihre Antwort.
Bei unserer Anwendung wird mit zwei unterschiedlichen Instanzvariablen gearbeitet, eine zum Lesen der Daten vom Typ UDInt udn eine zum Schreiben der Daten vom Typ UInt. Deswegen arbeite ich ja mit dem Anypointer um diese Umschaltung zu gewährleisten.
 

Windoze

Well-known member
Beiträge
209
Punkte Reaktionen
111
Zuviel Werbung?
->Hier kostenlos registrieren
Sorry, das hatte ich nicht genau gelesen.

Für sowas habe ich mir mal eine Hilfsfunktion geschrieben, die einen Any-Pointer umkopiert.
Dieser gibt man dann als Quelle das Symbol in den Instanzdaten und als Ziel einen Any-Pointer im Temp-Bereich.
Wenn man diese Funktion mehrfach mit den Entsprechenden Variablen aufruft kann man Datentyp / Länge relativ einfach umschalten.
Hat meiner Meinung nach den riesen Vorteil, das alles Symbolisch bleibt und man bei Änderungen in den Instanzdaten nichts am Code ändern muss.
Funktioniert auch Problemlos bei Multiinstanzen, der Offset wird automatisch korrekt ermittelt.

Sieht dann ungefähr so aus:
2020-09-17 14_18_03-Window.png

Code:
FUNCTION "CopyAnyPtr" : VOID
TITLE =
VERSION : 0.1


VAR_INPUT
  IN : ANY ;    //Quellpointer
END_VAR
VAR_OUTPUT
  OUT : ANY ;    //Zielpointer
END_VAR
BEGIN
NETWORK
TITLE =ANY-Pointers kopieren

      L     P##IN; 
      LAR1  ; 
      L     P##OUT; 
      LAR2  ; 
// Syntax-ID / Datentyp
      L     W [AR1,P#0.0]; 
      T     W [AR2,P#0.0]; 
// Länge
      L     W [AR1,P#2.0]; 
      T     W [AR2,P#2.0]; 
// DB-Nummer
      L     W [AR1,P#4.0]; 
      T     W [AR2,P#4.0]; 
// Pointer
      L     D [AR1,P#6.0]; 
      T     D [AR2,P#6.0]; 

NETWORK
TITLE =ENO in KOP/FUP aktivieren

      SET   ; 
      SAVE  ; 

END_FUNCTION
 

JesperMP

Well-known member
Beiträge
7.084
Punkte Reaktionen
1.434
Bei unserer Anwendung wird mit zwei unterschiedlichen Instanzvariablen gearbeitet, eine zum Lesen der Daten vom Typ UDInt udn eine zum Schreiben der Daten vom Typ UInt. Deswegen arbeite ich ja mit dem Anypointer um diese Umschaltung zu gewährleisten.
Warum musst du diese Umschaltung machen ?
Einfach zweimal die MB_CLIENT aufrufen, und für die MB_DATA_PTR Parameter einfach die symbolische Adressen für die Empfangs bzw. Sende-Daten.
 
OP
M

MWerner

Member
Beiträge
6
Punkte Reaktionen
0
Vielen Dank für eure Hilfestellung.

Habe nun mithilfe des Befehls "L DINO" die zugehörige IDB-Nr ermittelt und entsprechend weitergegeben. Hierdurch konnte ich die Problematik beheben. Vielen Dank für den Tipp @Ralle.

@JesperMP. Bei einem Mehrfachaufruf des MbClients kann es schnell zu einer Kollission kommen, da eine gewisse Zeit benötigt wird, um den Verbindungsaufbau zum Teilnehmer zu erreichen und beide gleichzeitig nie aktiv sein dürfen, weil diese auf den selben TN mit der selben ID zugreifen wollen. Daher wollte ich einfach einen simplen Aufruf eines MB-Clients aufbauen, was nun funktioniert.
 
Zuletzt bearbeitet:

JesperMP

Well-known member
Beiträge
7.084
Punkte Reaktionen
1.434
Zuviel Werbung?
->Hier kostenlos registrieren
@JesperMP. Bei einem Mehrfachaufruf des MbClients kann es schnell zu einer Kollission kommen, da eine gewisse Zeit benötigt wird, um den Verbindungsaufbau zum Teilnehmer zu erreichen und beide gleichzeitig nie aktiv sein dürfen, weil diese auf den selben TN mit der selben ID zugreifen wollen. Daher wollte ich einfach einen simplen Aufruf eines MB-Clients aufbauen, was nun funktioniert.
Du machst nur 1 Aufruf von MB_CLIENT, aber durch Manipulation von die Parameter ist es funktionell 2 Aufrufe mit Verzögerung ?
Dann hättest du einfach dasselbe machen können mit 2 Aufrufe, und es wäre einfacher durchzuschauen.
Naja wenn es funktioniert...
 

JesperMP

Well-known member
Beiträge
7.084
Punkte Reaktionen
1.434
Was klar ist, dass man DONE, BUSY, ERROR und STATUS überwachen muss, und damit REQ steuern so dass man nicht mehrere sende oder lese Aufträge auf einmal anstosst.
 

PN/DP

User des Jahres 2011-2013; 2015-2017; 2020-2021
Beiträge
18.612
Punkte Reaktionen
5.552
Generell wird ein FB geschrieben, der mehrfach aufgerufen werden soll und somit multiinstanzfähig sein muss.
Einen FB mehrfach aufrufen und multiinstanzfähig sind zwei verschiedene Paar Schuhe. Multiinstanzfähig muß ein FB sein, wenn in seinen Instanzdaten andere FB-Instanzen deklariert werden sollen oder wenn eine Instanz von ihm selbst in anderen FB-Instanzen deklariert werden soll (er als Multiinstanz verwendet wird).

Jetzt willst Du einen ANY-Pointer auf eine Variable in den FB-Instanzdaten bilden? Dann funktioniert Deine "kurz geschossene" "Lösung" nur, wenn Dein FB NICHT als Multiinstanz verwendet wird. Damit der FB auch wirklich als Multiinstanz verwendbar ist, musst Du auch multiinstanzfähig programmieren. Dann musst Du noch den Multiinstanz-Offset aus AR2 zur Adresse der Instanzvariable addieren


Darum blieb mir nichts anderes übrig als über einen Pointer den entsprechenden Datenbereich anzusprechen wenn ich lese oder schreibe.
Es gibt mehr Möglichkeiten. Wenn Du einen Lese- und einen Schreibauftrag hast, dann mußt Du noch mehr Parameter umschalten, dann würde ich das Basteln sein lassen und 2 MB_Client-Aufrufe programmieren - für jeden Auftrag einen (wie auch schon von Jesper empfohlen).


PS: Wieso bastelst Du old style in AWL 'rum wenn Du eine S7-1500 und TIA verwendest? ;)

Harald
 

Larry Laffer

Supermoderator
Teammitglied
Beiträge
13.147
Punkte Reaktionen
2.742
Zuviel Werbung?
->Hier kostenlos registrieren
Mal ein ganz anderer Vorschlag in dieser Sache :
Warum schreibst du das Ganze nicht in SCL ?
Hier gibt es die Möglichkeit, eine Variable als AnyPointer zu deklarieren. Dieser Variablen weißt du dann die Variable, das Variablen-Array oder die Variablen-Struktur (aus deiner Instanz) zu. Nun bildet sich SCL daraus ganz automatisch den passenden AnyPointer, den du dann weiter verwenden kannst.
So hatte ich das zumindestens in Step7-Classic öfter mal gemacht - ich denke mal, dass das auch bei TIA noch funktionieren wird ...

Gruß
Larry
 
OP
M

MWerner

Member
Beiträge
6
Punkte Reaktionen
0
Einen FB mehrfach aufrufen und multiinstanzfähig sind zwei verschiedene Paar Schuhe. Multiinstanzfähig muß ein FB sein, wenn in seinen Instanzdaten andere FB-Instanzen deklariert werden sollen oder wenn eine Instanz von ihm selbst in anderen FB-Instanzen deklariert werden soll (er als Multiinstanz verwendet wird).

Jetzt willst Du einen ANY-Pointer auf eine Variable in den FB-Instanzdaten bilden? Dann funktioniert Deine "kurz geschossene" "Lösung" nur, wenn Dein FB NICHT als Multiinstanz verwendet wird. Damit der FB auch wirklich als Multiinstanz verwendbar ist, musst Du auch multiinstanzfähig programmieren. Dann musst Du noch den Multiinstanz-Offset aus AR2 zur Adresse der Instanzvariable addieren



Es gibt mehr Möglichkeiten. Wenn Du einen Lese- und einen Schreibauftrag hast, dann mußt Du noch mehr Parameter umschalten, dann würde ich das Basteln sein lassen und 2 MB_Client-Aufrufe programmieren - für jeden Auftrag einen (wie auch schon von Jesper empfohlen).


PS: Wieso bastelst Du old style in AWL 'rum wenn Du eine S7-1500 und TIA verwendest? ;)

Harald

Guten Morgen,

vielen Dank für diese ausführliche Antwort Harald.

Vor lauter Datentypänderung habe ich wohl das Prinzip der Multiinstanz vergessen und muss gestehen, dass mein Baustein so wie ich ihn geschrieben habe diese nicht erfüllt.
Daher werde ich nun einen Mehrfachaufruf des MB_Clients doch ausprobieren, auch wenn ich dies eigentlich umgehen wollte.

Gibt es die Möglichkeit den Pointer auf die statischen Variablen eines FBs zeigen zu lassen, wobei ich nicht auf die Adressierung des Instanzdatenbausteins des FBs verweisen muss?
(Bei einer Multiinstanz)

Was hat es mit der Auswahl des Speicherbereichs 85 = IDB auf sich?

Hat irgendjemand gegebenenfalls eine Idee meine Anwendung rein symbolisch aufzubauen ohne Absolutadressen. (Das war in erster Linie mein Wunsch)

zu PS: Darüber reden wir lieber nicht :ROFLMAO:

Code:
/ Ermittlung der IDB - Nr
      L DINO
      T     #IDB_Nr

// Lesemodus
      L     #MbClient01.MB_MODE
      L     0
      ==I
      SPBN  RD
      LAR1  P##AnyPointer        //Lade Daten vom AnyPointer in das Adressregister 1
      L     W#16#10              //SyntaxID. bei S7 immer 10
      T LB [ AR1 , P#0.0 ]       //Lade die Syntax ID in das AR1
      L     W#16#7               //Typ 7 = DINT
      T LB [ AR1 , P#1.0 ]       //Lade den Datentyp in das AR1
      L     1                    //Anzahl der zu übertragenen Bytes
      T LW [ AR1 , P#2.0 ]       //Lade die Datenanzahl in das AR1
      L     #IDB_Nr              //Quell-IDB aktuelle IDB-Nr
      T LW [ AR1 , P#4.0 ]       //Lade die IDB-Nr in das AR1
      L     16                   //Anfang der Quelle - Bei FB-Änderung zu überprüfen
      SLD   3                    //Schiebe um 3 nach links, um in den Bytebereich zu kommen - vorher Bit
      T LD [ AR1 , P#6.0 ]       //Lade den Offset in das AR1
     [B] L     B#16#84[/B]              //Speicherbereich (hier DB) - 84 = DB / 85 = IDB
      T LB [ AR1 , P#6.0 ]       //Lade den Datenspeicherbereich in das AR1
RD:   NOP 0
 

Windoze

Well-known member
Beiträge
209
Punkte Reaktionen
111
Hallo,

du kannst auch den MbClient 2x mit der selben Instanz aufrufen und nur den Pointer ändern.
Dann musst du aber immer einen Aufruf überspringen.
 

JesperMP

Well-known member
Beiträge
7.084
Punkte Reaktionen
1.434
Zuviel Werbung?
->Hier kostenlos registrieren
PS: Wieso bastelst Du old style in AWL 'rum wenn Du eine S7-1500 und TIA verwendest? ;)
zu PS: Darüber reden wir lieber nicht :ROFLMAO:
Nur meiner Meinung, ich habe mit TIA kein Bedarf gehabt mit AWL zu basteln. Ich verstehe wenn man viel AWL code die man von STEP7 Classic in TIA übernehmen will und man hat kein Zeit um es in eine modernere Sprache zu konvertieren. Aber neue AWL Code in TIA erstellen ?
Tust du dies, um deiner Job zu schützen? Zukünftige Programmierer, die deiner Code pflegen sollen, werden es dir nicht danken.

Hat irgendjemand gegebenenfalls eine Idee meine Anwendung rein symbolisch aufzubauen ohne Absolutadressen. (Das war in erster Linie mein Wunsch)
Ist das was du meinst. Beispiel mit interne Instanzdaten:
MBclient_symbolic_data.png
 
OP
M

MWerner

Member
Beiträge
6
Punkte Reaktionen
0
Nur meiner Meinung, ich habe mit TIA kein Bedarf gehabt mit AWL zu basteln. Ich verstehe wenn man viel AWL code die man von STEP7 Classic in TIA übernehmen will und man hat kein Zeit um es in eine modernere Sprache zu konvertieren. Aber neue AWL Code in TIA erstellen ?
Tust du dies, um deiner Job zu schützen? Zukünftige Programmierer, die deiner Code pflegen sollen, werden es dir nicht danken.


Ist das was du meinst. Beispiel mit interne Instanzdaten:
Anhang anzeigen 51070


Ja da bin ich ganz eurer Meinung, ich selbst habe AWL auch nie gelernt, jedoch lassen es gewisse Gegebenheiten nicht zu einen neuen Schwung reinzubringen.

So wie ich ihr Beispiel ist hatte ich es vorher programmiert und werde es jetzt auch in dieser Richtung umsetzen. Jedoch war dies nicht meien eigentliche Frage ich wollte wissen ob ich einen expliziten Zugriff auf die statische Variable machen kann, unabhängig vom Instanzdatenbaustein.
 

JesperMP

Well-known member
Beiträge
7.084
Punkte Reaktionen
1.434
Intern in dem FB, zu dem die Instanz gehört, ist dies die Methode zum Referenzieren der Instanzdaten.

Außerhalb des FB kann man auf die Instanzdaten wie folgt verweisen:
MB_DATA_PTR := "IDB_xx".SomeData ;
Also die DB wird Symbolisch addressiert, sowohl die Daten.
Es wird jedoch als unangemessen angesehen, auf diese Weise auf Instanzdaten zuzugreifen.
 

Einfallsreich91

New member
Beiträge
1
Punkte Reaktionen
0
Zuviel Werbung?
->Hier kostenlos registrieren
Nur meiner Meinung, ich habe mit TIA kein Bedarf gehabt mit AWL zu basteln. Ich verstehe wenn man viel AWL code die man von STEP7 Classic in TIA übernehmen will und man hat kein Zeit um es in eine modernere Sprache zu konvertieren. Aber neue AWL Code in TIA erstellen ?
Tust du dies, um deiner Job zu schützen? Zukünftige Programmierer, die deiner Code pflegen sollen, werden es dir nicht danken.


Ist das was du meinst. Beispiel mit interne Instanzdaten:
Anhang anzeigen 51070
Hallo,
ich bin bei meiner Recherche auf diesen alten Tread gestoßen, da ich genau so etwas umsetzen möchte.
In der TIA-Hilfe steht, dass am Parameter "MB_DATA_PTR" ein Merker oder ein GLOBAL-DB verwendet werden kann. Von statischen lokalen Variablen steht da leider nichts, genau das machst du im Bild aber.
Funktioniert das oder gibt das eine Fehlermeldung aus, wenn eine Verbindung aufgebaut werden soll?
Ich habe leider gerade kein Testsystem da, um das zu überprüfen, ich würde das aber gerne genau so umsetzen. Bloß ist das laut TIA-Hilfe nicht erlaubt, da kein Global-DB...
 

JesperMP

Well-known member
Beiträge
7.084
Punkte Reaktionen
1.434
Habe es nicht getestet. Aber bin recht sicher dass es funktioniert so.
Ich wurde es aber auch mit ein Global-DB machen da die Daten immer von eine andere Programmfunktion stammt.
Das Beispiel mit Daten als Teil von ein Instanz-DB war ein Antwort auf MWerners Frage wie man es macht mit interne Daten.
 
Oben