Step 7 Mit SFC20 "Blockmve" PEWs in DB schreiben

Paul

Level-2
Beiträge
929
Reaktionspunkte
239
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen
Stehe gerade etwas auf dem Schlauch

Wie kann ich mit dem SFC20 "Blockmove" den Peripheriebereich ab PEW256 (-->16 Worte)
in einen DB transferieren?
Code:
    CALL  "BLKMOV"
      SRCBLK :=P#E 256.0 BYTE 32       //PEW256 Breite 32 Byte
       RET_VAL:=MW500
       DSTBLK :="Schrauberschnittstelle".PLC_IN
Mit diesem Code geht es nicht. S7 frisst ihn zwar, aber es kommt nichts an.

Code:
    CALL  "BLKMOV"
      SRCBLK :=P#[COLOR=#FF0000]PEW 256[/COLOR] BYTE 32       //PEW256 Breite 32 Byte
       RET_VAL:=MW500
       DSTBLK :="Schrauberschnittstelle".PLC_IN
P#PEW 256 BYTE 32 oder ähnliche Konstrukte werden erst gar nicht akzeptiert.

Muss doch irgendwie gehen.

Vielen Dank schon mal im voraus.
PS. Bin auch für andere Lösungen offen, muss nicht SFC20 sein.
 
Dein erstes Beispiel greift ja nicht auf PEB256... zu sondern auf EB256...
Sollte klappen, aber ist das PAE der CPU denn groß genug eingestellt?

Zum zweiten Beispiel: BLKMOV kann mMn nicht direkt auf die Peripherie zugreifen.

Gruß
Erich
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Die einfachste Lösung wäre, so du eine relativ neue CPU hast in der HW-Konfig das Prozessabbild zu vergrößern im Reiter "Zyklus/Taktmerker".

Mfg
Manuel
 
.. Muss doch irgendwie gehen ...
Die SFC20 kopiert nichts aus dem Peripheriebereich. Man kann sich jedoch in SCL eine FC stricken, die in einer Schleife indiziert auf den Peripheriebereich zugreift. So eine Funktion ist auch ganz nützlich, um nichtkonsistente Datenblöcke eines Busteilnehmers zu kopieren (analog zur SFC14/15 für konstistente Bereiche).
 
Hallo zusammen,
ich bin neu hier im Forum. Schaue immer mal gerne hier herein, weil ich immer gute Beiträge und Hilfestellungen gelesen habe.
Zurzeit habe ich ein ähnliches Problem, wie Paul.

Ich benötige eine registerindirekte Adressierung für einen bibliotheksfähigen Baustein. Ziel ist es an den Baustein (FB167) einen Prozesseingangs-Adressbereich anzulegen und anschließend sollen intern, in Abhängigkeit von mehreren Variablen (Dateneingangsbyte, Nutzdatenlänge, etc.), die Eingangsbytes eingelesen und in den Instanzdatenbaustein abgelegt werden. Alles soll in AWL programmiert sein.

Hier ist mein erster Ansatz, der leider nicht so funktioniert, wie ich es mir vorstelle:

FB167, DB167
L #I_PEB_Startbyte // lade Nummer von erstem Eingangsbyte (In-Var)
T #S_PEB_Nr // schreibe in statische Variable

L #I_Data_Laenge // lade vorgegebene Daten-Länge (In-Var)
loop: T #S_Laenge // schreibe in statische Variable

L P##E_Result_Data // lade Inhaltswert von E_Result_Data (In-Var)
T #S_PEB_Inhalt // schreibe Wert in PEB_Inhalt
L #S_PEB_Inhalt // lade PEB_Inhalt
T #S_DM_Result_Data[1] // schreibe in Speicherbereich Array

L #S_PEB_Inhalt // lade PEB_Inhalt, eigentlich Speicherort für nächsten Loop-Durchlauf
L 1 // lade Ziffer 1
+I // addiere es zu Pointerinhalt,
T #S_PEB_Inhalt // überschreibe in Variable

L #S_PEB_Nr // lade Nummer vom aktuellen Eingangsbyte
L 1 // lade 1
+I // addiere zusammen
T #S_PEB_Nr // überschreibe in Variable

L #S_Laenge // lade aktuelle Länge (als statische Var, die heruntergezählt wird)
LOOP loop // Sprung zur Marke "loop" nachdem Variable um 1 dekrementiert

Kann mir bitte jemand dabei helfen bzw. gibt es eine andere Lösung?
Ich bin gerade dabei mir mehr AWL-Kenntnisse aufzubauen.

VG
Bit_Schupser
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Für welche SPS soll der Code sein?

Warum soll das ein FB sein? Wäre FC nicht besser?

Soll der "bibliotheksfähige" Baustein die Herkunft der Daten verschleiern oder darf man das auch sauber in den Referenzdaten wiederfinden können?

Ist garantiert, daß der von Deinem Baustein zukünftig von hinten durch die Brust ausgelesene Peripheriebereich byteweise organisiert ist oder wirst Du nicht vielmehr Konsistenzprobleme durch die "zerhackten" Zugriffe bekommen?

Harald
 
Hallo Harald,

die CPU ist eine VIPA SLIO, mit PG/OP und PN-Schnittstelle. Die Daten kommen von einem PN-Teilnehmer. Es ist ein Scanner, der einen Barcode zur Produktidentifizierung aufnimmt und daher eingelesen werden muss.
Mir ist klar, dass ich auch über verschiedene SFBs oder SFCs die Daten einlesen könnte. Es soll aber, wenn möglich, mit einer am FB167 angelegten Eingangsvariable realisiert werden.
Ursprünglich habe ich es statisch mit Move (z.B. lade PEB160 transferiere Array[1]) realisiert. Da sich aber jetzt meine Vorgaben geändert haben, soll die Verarbeitung variabel und dynamisch aufgebaut sein.

Der FB167 besteht aus etwa 30 Netzwerken und hat noch weitere Funktionen zur Ansteuerung des Scanners.

Ich verstehe deine Frage “Daten verschleiern“ nicht. Mein Ziel ist ein Loop, der in Abhängigkeit der Barcodelänge den Prozesseingangsbytebereich aufwärts (ab PEB160) einliest und die Werte dazu in ein Array schreibt. Als maximale Vorgabe vom Scanner sind 64 Byte (als Char) vorgegeben. In meinen Maschinen brauche ich für gewöhnlich 10 – 20 Chars.

Gruß
Bit_Schupser

P.S. kann mir jemand sagen, wie ich hier im Forum die Beiträge zitieren? Bin noch neu hier.
 
Mit "verschleiern" meine ich, daß bei der Übergabe von Adressen als INT die Zugriffe auf die Adressen nicht in den Referenzdaten erscheinen. Sehr schlechter Programmierstil...

Das Kopieren kann man so machen:
Code:
FUNCTION_BLOCK FBxxx
TITLE =
VERSION : 0.1

VAR_INPUT
  I_PEB_Ptr : POINTER ; //PEBxxx Anfangsadresse des PEB-Bereichs
  I_Data_Laenge : INT ; //Länge des PEB-Bereichs
END_VAR
VAR
  S_DM_Result_Data : ARRAY  [1 .. 64 ] OF //internes Byte-Array
  BYTE ;
END_VAR
VAR_TEMP
  t_PEB_Ptr : DWORD ;   //Pointer im Doppelwortformat für speicherindirekte Adressierung
  t_Laenge : INT ;      //Schleifenzähler
END_VAR
BEGIN
NETWORK
TITLE =

//*** Pointer auf übergebenen Peripherieeingangsbereich
      L     P##I_PEB_Ptr;               //Adresse des In-Parameters in dieser Instanz (DI)
      TAR2  ;                           //Offset dieser (Multi-)Instanz (DB)
      UD    DW#16#FFFFFF;               //Bereichskennung (DB) ausblenden
      +D    ;                           //dazuaddieren
      LAR1  ;                           //--> AR1: Adresse des In-Parameters im IDB (DI)
      L     DID [AR1,P#2.0];            //übergebenes PEx als P#Pxxx.0
      T     #t_PEB_Ptr;                 //Pointer auf Peripherieeingangsbereich
//      LAR1  ;                           //(nur zum beobachten)

//*** Pointer auf Byte-Array in STAT
      L     P##S_DM_Result_Data;        //Adresse des Byte-Array in dieser Instanz (DI)
      TAR2  ;                           //Offset dieser (Multi-)Instanz (DB)
      UD    DW#16#FFFFFF;               //Bereichskennung (DB) ausblenden
      +D    ;                           //dazuaddieren
      LAR1  ;                           //--> AR1: Adresse des Byte-Array im IDB (DI)

//*** Länge des Peripherieeingangsbereich prüfen,
//    darf nur 1 bis max Array-Größe von S_DM_Result_Data[1..64] sein 
      L     #I_Data_Laenge;             //darf nur 1..64 sein!
      L     65;                         //Größe+1 des Byte-Array S_DM_Result_Data[1..64]
      MOD   ;                           //auf 0..64 begrenzen, notfalls wrap
      SPN   loop;
      L     1;                          //Länge = 0! --> mit 1 ersetzen

//*** Kopierschleife
loop: T     #t_Laenge;                  //Schleifenzähler

//*** kopieren PEB[adr] --> S_DM_Result_Data[i]
      L     PEB [#t_PEB_Ptr];           //PEB[adr]
      T     DIB [AR1,P#0.0];            //S_DM_Result_Data[i]

//*** beide Pointer weiterstellen
      L     #t_PEB_Ptr;
      L     P#1.0;
      +D    ;
      T     #t_PEB_Ptr;                 //(adr) auf nächstes PEB

      +AR1  P#1.0;                      //(i) auf nächstes Byte im Array S_DM_Result_Data[]

//*** Schleife
      L     #t_Laenge;                  //Schleifenzähler
      LOOP  loop;

END_FUNCTION_BLOCK

An I_PEB_Ptr schreibst Du beim Aufruf dann z.B. "PEB160" (also: I_PEB_Ptr:=PEB160)

Harald
 
Harald,

vielleicht sind meine grauen Zellen schon eingeschlafen, kannst Du mir bitte die Begrenzung erklären:

Code:
//*** Länge des Peripherieeingangsbereich prüfen,
//    darf nur 1 bis max Array-Größe von S_DM_Result_Data[1..64] sein 
      L     #I_Data_Laenge;             //darf nur 1..64 sein!
      L     65;                         //Größe+1 des Byte-Array S_DM_Result_Data[1..64]
      MOD   ;                           //auf 0..64 begrenzen, notfalls wrap
      SPN   loop;
      L     1;                          //Länge = 0! --> mit 1 ersetzen

//*** Kopierschleife
loop: T     #t_Laenge;                  //Schleifenzähler

Wenn in #I_Data_Laenge z.B. 80 steht, wird dann nicht der #t_Laenge auf 15 vorbelegt, statt auf 64?

Gruß
Karl
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn in #I_Data_Laenge z.B. 80 steht, wird dann nicht der #t_Laenge auf 15 vorbelegt, statt auf 64?
Richtig. Das MOD sorgt einfach nur dafür, daß der Wert garantiert kleiner als 65 ist und die nachfolgende Schleife nicht außerhalb des internen Arrays schreibt. Das ist nur eine Notbremse für den Fall eines Programmierfehlers beim Bausteinaufruf. Die zweite Notbremse ist das Ersetzen der unzulässigen Länge=0 zu 1. Ich gehe davon aus, daß #I_Data_Laenge sich nach den ersten Programmtests nicht mehr dynamisch ändert. Mein MOD realisiert die normalerweise dann nicht mehr nötige Notbremse einfacher als Vergleiche.

Man kann natürlich auch klassisch zwei Vergleiche auf < 1 und > 64 machen (unsigned!) und ggf. den Wert auf diese Grenzwerte setzen, oder die Schleife bei unzulässigen Werten überspringen, oder .... Besonders, wenn sich die übergebene Länge dynamisch ändern sollte.

Wichtig ist nur, daß #I_Data_Laenge überhaupt geprüft wird und der Programmierer sollte festlegen, was bei unzulässigen Werten passieren soll.

Harald
 
Zurück
Oben