Step 7 Funktion FC mit ANY-Pointer zur Steuerung/Auslesen der Peripherie

SPS-EK

Level-1
Beiträge
68
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo alle zusammen,

ich habe mal wieder ein kleines Anliegen und hoffe ich bekomme Hilfestellung von euch:

Funktion FC: dient der Steuerung der Profibus/Profinet Antriebe und wurde auf das Standarttelegramm 1 PZD2/2 angepasst. Die Antriebe haben dabei separate DBs.
Über den nutzen von FCs und FBs mit IDBs lässt sich natürlich streiten, nur hier bleibt es beim FC.

Nun soll an einer bestehenden Anlage, die Funktion auf das Telegramm 20 angepasst werden und entsprechend PZD2/6 übergeben/ausgelesen werden.

Daher habe ich in der Funktion unter TEMP folgende Variablen/Strukturen:
Name
Datentyp
Adresse
E_A_AdresseDWord0.0
SENDStruct4.0
RECStruct8.0
HM_scale_value_setpointReal20.0
.........
ZielAny48.0
QuelleAny58.0













Ursprünglicher COde zum auslesen der Daten der Peripherie:
Code:
 L     #HW_Konfig_E_A_Adresse      // Adresse laut HW-Konfig im Integer-Format
      SLD   3                           // Konvertierung ins Pointerformat: 3 Stellen nach links schieben 
      T     #Adresse_E_A                // Adresse in Doppelwort
Code:
 L     PED [#Adresse_E_A]          // Prozessdaten vom Antrieb empfangen
      T     LD     8                    // Transferiere in das Lokaldaten-Doppelwort LD
Hier stellt sich die Frage wie ich mehrere Wörter (6 PZD) empfangen soll,wenn PED nur ein Doppelwort (zwei Wörter) überträgt?!

Ich dachte mir durch die Verwendung von ANY-Pointern könnte ich das etwas besser und variable gestalten, da ich ja somit nur die Länge der Daten ändern muss um den Baustein für weitere Telegramme zu ändern. Anschließend werden mit einem Blockmove die Daten vom Antrieb in den Tempbereich des FC kopiert.
Die Vorlage der Anypointer habe ich hier aus dem Forum und hoffe das ich diese richtig umgeändert habe:
Code:
  L     6                           //Anzahl bzw. Länge der Wörter
      T     #Laenge

// Erstellung des Quell Pointers

      L     P##Quelle
      LAR1                              //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#4                      //Datentyp: 04 = WORD
      T     LB [AR1,P#1.0]
      L     #Laenge                     //Länge der Daten bzw. Anzahl/Wiederholfaktor
      T     LW [AR1,P#2.0]
      L     0                           //Nummer des DB's, wenn nicht benötigt: 0
      T     LW [AR1,P#4.0]
      L     B#16#80                     //Auswahl Speicherbereich: 80 = P (Peripherie)
      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     #Adresse_E_A                //Adressanfang (Zeiger), hier im Peripherieeingang       
      SLD   3                           //dreimal Shift nach links (in Akku 1) damit Adressformat: .Bit = .0
      T     LW [AR1,P#8.0]              //Adressformat: Byte.Bit wobei Byte in Bit0-7 von 8.Byte


// Erstellung des Ziel Pointers

      L     P##Ziel
      LAR1                              //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#4                      //Datentyp: 04 = WORD
      T     LB [AR1,P#1.0]
      L     #Laenge                     //Länge der Daten bzw. Anzahl/Wiederholfaktor
      T     LW [AR1,P#2.0]
      L     0                           //DINO liest DBNR aus, wenn nicht benötigt: 0
      T     LW [AR1,P#4.0]
      L     B#16#86                     //Auswahl Speicherbereich: 86 = Lokaldaten L-Stack
      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##REC                      //relative Adresse/Adressanfang der Struktur (Zeiger)  
      SLD   8                           //8mal Shift DWORD nach links (in Akku 1) damit Bereichskennung ausblenden
      SRD   8                           //8mal Shift DWORD nach rechts (in Akku 1) damit Bereichskennung ausblenden
      SLD   3                           //dreimal Shift nach links (in Akku 1) damit Adressformat: .Bit = .0
      T     LW [AR1,P#8.0]              //Adressformat: Byte.Bit wobei Byte in Bit0-7 von 8.Byte


// Wiederherstellen der Adressregister
      LAR1  #SaveAR1                    //Wiederherstellen des AR1
      LAR2  #SaveAR2                    //Wiederherstellen des AR2 für Zugriff auf Instanzvariable

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

Würde dies funktionieren oder hättet ihr eine bessere Idee zum Auslesen der Daten?
 
Zuletzt bearbeitet:
Ursprünglicher COde zum auslesen der Daten der Peripherie:
Code:
 L     #HW_Konfig_E_A_Adresse      // Adresse laut HW-Konfig im Integer-Format
      SLD   3                           // Konvertierung ins Pointerformat: 3 Stellen nach links schieben 
      T     #Adresse_E_A                // Adresse in Doppelwort
Code:
 L     PED [#Adresse_E_A]          // Prozessdaten vom Antrieb empfangen
      T     LD     8                    // Transferiere in das Lokaldaten-Doppelwort LD
Hier stellt sich die Frage wie ich mehrere Wörter (6 PZD) empfangen soll,wenn PED nur ein Doppelwort (zwei Wörter) überträgt?!
Code für 6 Words:
Code:
      L     #HW_Konfig_E_A_Adresse      // Adresse laut HW-Konfig
      SLD   3                           // Konvertierung ins Pointerformat: Adr --> P#Adr.0
      LAR1

      LAR2  P##REC                      // Anfangsadresse der Struktur REC in TEMP

      L     PED [AR1, P#0.0]            // Prozessdaten vom Antrieb lesen
      T     D [AR2, P#0.0]              // Transferiere Words 1+2 in die Struktur REC
      L     PED [AR1, P#4.0]            // Prozessdaten vom Antrieb lesen
      T     D [AR2, P#4.0]              // Transferiere Words 3+4 in die Struktur REC
      L     PED [AR1, P#8.0]            // Prozessdaten vom Antrieb lesen
      T     D [AR2, P#8.0]              // Transferiere Words 5+6 in die Struktur REC
Code:
//geht beides:
      T     D [AR2, P#8.0]              // Bereichsübergreifende, registerindirekte Adressierung
      T     LD [AR2, P#8.0]             // Bereichsinterne, registerindirekte Adressierung

Die Adressregister AR1 und AR2 müssen nicht gesichert werden.

Wie ist die Konsistenz der 6 PZD eingestellt?
Wenn "Gesamt", dann geht PED-Zugriff nicht, dann muß SFC14 "DPRD_DAT" zum Lesen aus der Peripherie benutzt werden.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Harald,

Konsistenz ist auf "Gesamte Länge" eingestellt. Muss man SFC14 nutzen oder klappt das nicht auch mit den zusammengesetzten Anypointern?
Denn genau das wollte ich umgehen, dass ich eine Funktion habe die immer funktioniert, egal was eingestellt ist. Daher auch der Gedanke mit dem Quellpointer der die 6 Wörter lädt.
Durch die Längen angabe könnte ich so immer auf ein andere Telegramm switchen und es würde immer funktionieren oder nicht?

Wieso machst du den Quellpointer so kurz?
Ist es denn so falsch wie ich es gemacht habe?
Wieso müssen die ARs nicht gesichert? Ich dachte wenn man die Adressregister überschreibt dann sollte man diese wieder herstellen.

Sorry, für die vielen Fragen aber naja so gut kenn ich die Materie ja (noch) nicht :lol:
 
Konsistenz ist auf "Gesamte Länge" eingestellt. Muss man SFC14 nutzen oder klappt das nicht auch mit den zusammengesetzten Anypointern?
Man muß SFC14 nutzen. Das selbstgeschriebene Programm kann nicht bei Gesamt-Konsistenz 6 Wörter aus der Peripherie lesen, das kann nur das Betriebssytem. Wenn man es trotzdem versucht, dann liefern die Lesezugriffe auf die PED... immer 0 - probiere es aus!

Alternative: lege die E/A-Adressen der Antriebe ins Prozessabbild (ggf. Größe des Prozessabbilds vergrößern in den CPU-Eigenschaften), dann kannst Du mit einzel-Zugriffen oder BLKMOV die E/A umkopieren.


Denn genau das wollte ich umgehen, dass ich eine Funktion habe die immer funktioniert, egal was eingestellt ist. Daher auch der Gedanke mit dem Quellpointer der die 6 Wörter lädt.
Durch die Längen angabe könnte ich so immer auf ein andere Telegramm switchen und es würde immer funktionieren oder nicht?
Ja genau, das will jeder - die eierlegende Wollmilchsau die ohne Nachdenken automatisch alles richtig macht, so daß die nächste Maschine vom Azubi programmiert werden kann und man selber überflüssig geworden ist... ;)
Automatisch mit verschiedenen PZD-Längen arbeiten ist nicht mit der Längenangabe alleine gelöst. Wie ändert sich automatisch die Größe der Struktur REC? Der Inhalt der Zusatz-Wörter kann verschieden sein - wie soll das Programm das erkennen? ...? Es erfordert sowieso Fallunterscheidungen.


Wieso machst du den Quellpointer so kurz?
Was heißt "kurz"? :confused:
Der Code kopiert einfach auf kürzestem Weg 6 Wörter von einer vorgegebenen Anfangsadresse. Wozu das ganze noch mit ANY-Pointern künstlich aufblähen?


Ist es denn so falsch wie ich es gemacht habe?
Es ist sinnlos weil BLKMOV kann nicht in/aus Peripherie kopieren.


Wieso müssen die ARs nicht gesichert? Ich dachte wenn man die Adressregister überschreibt dann sollte man diese wieder herstellen.
Es ist überflüssig. Es bringt nichts.
Nur in FB enthält das AR2 einen Wert (Offset dieser Multiinstanz im Mutter-IDB), den man nicht verlieren darf wenn man auf Instanzvariablen zugreifen will. In allen anderen Fällen erwartet das Betriebssystem keine bestimmten Werte in den Adressregistern und initialisiert diese bei Bedarf vor Verwendung - ohne Rücksicht darauf, was da schon drin steht - man kann es selber genauso machen. Insbesondere darf man nicht davon ausgehen, daß nach Aufruf irgendeines anderen Bausteins bei der Rückkehr in den Adressregistern noch die Werte von vor dem Aufruf drinstehen (z.B. weil das Betriebssystem vielleicht schon AR1 für die Parameterübergabe benutzt hat). Nur derjenige, der die Adressregister nutzt, sollte diese sichern, wenn er eigene Werte darin behalten will.

Bei welchen Operationen überschreibt STEP 7 den Akku-Inhalt bzw. den Inhalt von Registern?
Siehe auch die STEP7 Hilfe "Hinweise zur Änderung von Register-Inhalten" und "Vermeiden von Fehlern beim Aufrufen von Bausteinen"

Harald
 
Hallo EK,

.. Konsistenz ist auf "Gesamte Länge" eingestellt. Muss man SFC14 nutzen ..?
Natürlich verwendet man hier die SFC14/15. Hast du mal probiert, auf die Peripherieadressen der konsistenten Bereiche direkt mit Ladebefehlen zuzugreifen? Es würde mich mal interessieren, ob das wirklich nicht geht. Ich dachte immer, es müsste prinzipiell auch möglich sein, dann natürlich mit Verlust der Gesamt-Konsistenz. Möglicherweise habe ich dies jedoch selbst noch nie probiert.

Es gibt aber einen Fall, wo eine solche Funktion durchaus Sinn macht, und zwar bei nichtkonsistenten Datenblöcken im Peripheriebereich. Diese kann man weder mit der SFC14/15 noch mit der SFC20 übertragen. Dazu kann man den Ablagebereich im DB als ANY-Pointer der FC übergeben, sowie die Adresse des Peripheriebereiches lediglich als INT oder WORD. Die Daten sollten im DB sinnvollerweise strukturiert angelegt sein. In der FC zerpflückt man den ANY und gewinnt daraus den DB und die Datenlänge in Byte. Mit diesen Informationen kopiert man byteweise in einer Schleife die Daten, vorzugsweise in SCL.

Gruß, Onkel
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Harald,

Ok, ich muss mir das mal mit dem Prozessabbild anschauen und anpassen.
Ausprobieren kann ich gerade nicht, gerade den seltenen Fall das keine Anlage vor Ort ist und die Testmittel lassen noch zu wünschen übrig.

Naja, wir sind ja im Bereich der Automatisierung also wenn ich so eine Funktion programmier, dann auch entsprechend weitgehend.
Die Wörteranzahl könnte man ja durch einen Übergabeparameter so realisieren, dass man dort angibt welches Telegramm man benutz und in der Funktion wird entsprechend die Datenlänge des ANY-Pointers geändert. Ähnlich wie mit Angabe der EA-Adresse nur dann mit Fallunterscheidung in der Funktion. Problematischer wäre es bei den 32Bit Wörter, nur bei uns wird bisher nur Telegramm 1, 20 und eventuell zukünftig 350 benutzt. Und ob die Strukturen beschrieben werden oder nicht macht ja im Grunde nichts aus, solange diese angelegt sind.
Die Struktur könnte man größt möglich dimensionieren und entsprechend vorbelegen. Über die Angabe welches Telegramm werden dann auch nur die entsprechenden Wörter kopiert. So ähnlich dachte ich es mir oder habe ich ein Denkfehler?

Hallo Onkel Dagobert,
Also das PED mit zwei Wörtern kann ich logischer weise auslesen und laut einer alten Funktion wurde die EAdresse um 4 erhöhrt um somit zb den Stromistwert aus dem FU auszulesen und das alles mit Lade-/Transferbefehlen. Was anderes Macht der MOVE bzw Blockmove ja auch nicht. Theoretisch müsste es gehen, aber wie Harald schon schreibt könnte es daran scheitern. Mir wäre der ANYPOINTER halt dennoch lieber weil ich so wie schon geschrieben eine Fallunterscheidung zwischen den Telegrammen machen kann und die Funktion entsprechend die Wörter ausliest.
 
Zuletzt bearbeitet:
Zurück
Oben