Sonstiges Instanz DB in Global DB verschieben - blkmov in SCL

newirobi

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

derzeit programmiere ich einen FB, der Werte aufnehmen und diese aufbereiten soll, um im Anschluss daran die Werte vom eigenen Instanz-DB in ein globalen DB zu schieben.
Um dies zu realisieren, will ich den SFC20 blkmov verwenden.
Leider habe ich es bis jetzt noch nicht geschafft und bin mit meinem Latein am Ende, weswegen ich hoffe, hier Hilfe zu finden.
Das habe ich bis jetzt (nur Code, welcher für den BlockMove relevant ist):

Code:
VAR_INPUT    

    PV_COUNT : WORD;    //exemplarische Input-Variable

END_VAR  

VAR_TEMP

    //ANY-Pointer zur Ermittlung der Nummer des Instanz-DBs
    IDBPointer : ANY;
    AnyPointerIDB AT IDBPointer: STRUCT
        BYTE0   :BYTE;
        TYP     :BYTE;
        ANZ     :WORD;
        DBNR    :WORD;
        BZ      :DWORD;
    END_STRUCT;
    
    //ANY-Pointer auf den Quell-DB (Instanz-DB)
    SourcePointer: STRUCT
        BYTE0   :BYTE;
        TYP     :BYTE;
        ANZ     :WORD;
        DBNR    :WORD;
        BZ      :DWORD;
    END_STRUCT;    
    AnyPointerSource AT SourcePointer: ANY;    
    
    //ANY-Pointer auf den Ziel-DB
    DestinPointer: STRUCT
        BYTE0   :BYTE;
        TYP     :BYTE;
        ANZ     :WORD;
        DBNR    :WORD;
        BZ      :DWORD;
    END_STRUCT;        
    AnyPointerDestin AT DestinPointer: ANY;
END_VAR
Variablendeklaration


Code:
    IDBPointer  := PV_COUNT;    //Zuweisung des Instanz-DB-Pointers zur Ermittlung der Nummer des Instanz-DBs
    

    //Initialisierung des ANY-Pointers auf den Quell-DB (Instanz-DB)
    SourcePointer.BYTE0     := 16#10;                    //Syntax-ID
    SourcePointer.TYP         := 16#02;                    //02 für Datentyp BYTE
    SourcePointer.ANZ         := 16#a;                    //Länge der zu kopierenden Daten 10Byte
    SourcePointer.DBNR         := AnyPointerIDB.DBNR;        //DB-Nummer (Nummer des eigenen Instanz-DBs)
    SourcePointer.BZ         := 16#2a;                    //Startadresse des Quell-DBs 42
    
    //Initialisierung des ANY-Pointers auf den Ziel-DB
    DestinPointer.BYTE0     := 16#10;    //Syntax-ID
    DestinPointer.TYP         := 16#02;    //02 für Datentyp BYTE
    DestinPointer.ANZ         := 16#a;    //Länge der zu empfangenden Daten 10Byte
    DestinPointer.DBNR         := 16#2;    //DB-Nummer DB2
    DestinPointer.BZ         := 16#22;    //Startadresse des Ziel-DBs 34    
   

    erg := SFC20(srcblk := AnyPointerSource, dstblk := AnyPointerDestin);    //Schiebe den Quell-DB in Ziel-DB
Quellcode zum Befüllen des Quell-DBs

Zwar gibt mir der Kompiler keine Fehlermeldung aus, jedoch werden die erwarteten Werte auch nicht im DB2 geschrieben/angezeigt.
Ich weiß nicht, was ich noch falsch mache.
Ich hoffe hier kann mir jemand bei meinem Problem helfen. Vielen Dank dafür schonmal im Voraus!
 
es fehlt die Angabe des Speicherbereichs: 84 - globalDB und 85 - IDB
die Startadressen sollten auch in das richtige Format (Pointer: DWORD, 3BIT - Bitadresse, 16BIT - Byteadresse) gebracht werden
 
Vielen DANK!!!
Nach so einer Übersicht habe ich vorhin schon ewig gesucht...

Jetzt funktioniert es auch so wie ich es haben wollte!

Vielen Dank nochmal
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Dieses Zusammenbauen der Any-Pointer sollte in der Regel nicht nötig sein. Wenn die Werte in einem UDT stehen, muss nur der Name der UDT-Variablen an srcblk und dstblk übergeben werden. Step7 erzeugt den ANY-Pointer intern selbst, das gilt für SCL wie AWL.

Selbst wenn es kein UDT ist, sondern nur eine anonyme STRUCT, funktioniert das. Bei Teilen von Arrays würde ich statt BLKMOV mit Bastelpointern eine FOR-Schleife nehmen. BLKMOV ist strikt langsamer als Alternativen, anders als C - memmove. Das Kopieren erfolgt nicht schneller als selbstgeschriebener Code und dazu kommt die Parameterübergabe.
 
BLKMOV ist strikt langsamer als Alternativen, anders als C - memmove. Das Kopieren erfolgt nicht schneller als selbstgeschriebener Code und dazu kommt die Parameterübergabe.

GERÜCHT!
schau in die Baugruppendaten der jeweiligen CPUs ... vor 6 Jahren haben wir diese Rechnung in diesem Forum auch schon aufgemacht. BLKMOV ist ab dem Wert x ... ich glaube mich zu erinnern, 12 Byte, schneller als Lade- und Transferbefehle.
 
Hallo,

nach Durchsicht der Antworten habe ich noch mal beispielhaft eine "Operationsliste" gelesen. Ja, es ist tatsächlich denkbar, dass BLKMOV intern etwas schneller arbeitet als eine gut optimierte Schleife. Aber wenn schon eine optimierte Schleife fast 2x so lang braucht wie eine "normale", dann ist der Test und seine Folgerungen von begrenzter Aussagekraft. Ein Faktor 7, eine Grenze von 12 Byte erfordern ein passend "optimiertes" Vergleichsprogramm.

BLKMOV ist oft das Mittel der Wahl, auch schon für 2-Byte-UDTs, weil es ohne unlesbaren/unwartbaren Code auskommt. SCL kann hier schneller sein, wenn es einfache L; T; -Befehle erzeugt. Das nächste Mittel wären automatisch erzeugte L; T; -Befehle in AWL, die sind übrigens laut meiner Beispielliste je nach CPU schneller oder zumindest nicht wesentlich langsamer als BLKMOV, selbst wenn die konstanten (mehr als) 75-90 µs ignoriert werden.

AWL-Schleifen oder Zusammenbau von ANY-Pointern gehören für mich nur in Ausnahmesituationen, z.B. Compilerbau.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja, es ist tatsächlich denkbar, dass BLKMOV intern etwas schneller arbeitet als eine gut optimierte Schleife. Aber wenn schon eine optimierte Schleife fast 2x so lang braucht wie eine "normale", dann ist der Test und seine Folgerungen von begrenzter Aussagekraft.
Da hast Du irgendwas missverstanden, wenn Du die hingetrickste Schleife als "normale" Schleife betrachtest. Und selbst die hat noch ca. dreimal so lange wie BLKMOV gebraucht.

Es ging da um das Umspeichern von ca. 2800 INT. Die Schleife, welche 2x schneller als die optimierte arbeitete, hat ungeachtet des Datentyps tricky immer gleich 2 INT gleichzeitig umgespeichert, was den AWL-Code noch zusätzlich schwerverständlich machte. Dieses Vorgehen kann man nicht verallgemeinern. Stell Dir mal die nötige Trickserei vor, wenn das ein ARRAY von 39999 BOOLs gewesen wäre...


Bei Teilen von Arrays würde ich statt BLKMOV mit Bastelpointern eine FOR-Schleife nehmen. BLKMOV ist strikt langsamer als Alternativen, anders als C - memmove. Das Kopieren erfolgt nicht schneller als selbstgeschriebener Code und dazu kommt die Parameterübergabe.
Gut, sagen wir mal ich hätte ein Archiv als ARRAY von 1000 Datensätzen und ich möchte da 20 zusammenhängende Datensätze in verschiedene Sendepuffer zu anderen Maschinen herauskopieren. Ich würde dem Kopierbaustein die Nummer des ersten der 20 Datensätze geben (z.B. 140 für die Datensätze 140 bis 169) und irgendwie die variable Adresse des Ausgabe-Arrays (Sendepuffer).

Wie müsste ein selbstgeschriebener Code aussehen, der das schneller oder gleich schnell wie BLKMOV erledigt?
Code:
TYPE "Datensatz"
VERSION : 0.1

  STRUCT
   Timestamp : DATE_AND_TIME ;
   Messwert1 : REAL ;
   Messwert2 : REAL ;
   States : WORD ;
  END_STRUCT ;
END_TYPE

DATA_BLOCK "DB_Archiv"
VERSION : 0.1

  STRUCT
   Archiv : ARRAY  [0 .. 999] OF "Datensatz";
  END_STRUCT ;
BEGIN

END_DATA_BLOCK

Harald
 
Wie "tricky" das ist, ist mir egal. Der größte Verlust an Wartbarkeit tritt ein, wenn derartiger Code in AWL geschrieben wird im Vergleich zu SCL. Das DINT-weise statt BOOL-weise zu kopieren, ist im Verhältnis dazu das kleinere Problem.

Dass BLKMOV schneller sein kann als eine Schleife, glaube ich Euch, wie gesagt (unter den richtigen Bedingungen). Für das genannte Beispiel würde ich eine SCL-Schleife nehmen, die könnte aber mehrmals BLKMOV aufrufen und damit am langsamsten sein, ich glaube 18 Bytes ist gerade über der Grenze. Problem dabei: ich würde die "variable Adresse des Ausgabe-Arrays" so übergeben, dass es ohne Pointer geht, weil das sowohl die Wartbarkeit als auch die Effizienz minimiert. Wenn das nicht möglich ist, muss ich auf AWL umsteigen. Dann ist alles offen.

Bei konstanten Adressen und nicht sehr großen Datensätzen ist eine Folge von L... T... Befehlen klar schneller als BLKMOV, aber ich nehme BLKMOV, weil ich noch keine bessere Idee mit vergleichbarer Wartbarkeit umgesetzt habe.

Für den BLKMOV-Wettbewerb: einfach die schnellstmögliche DINT-Schleife erstellen. Dazu AR1, AR2, DB und DI soweit nötig sichern und benutzen. Ob, und interessanter: bis zu welcher Größe, die Schleife schneller ist als BLKMOV, kann nachmessen, wer will.

Wo BLKMOV Zeit verliert, ist bei der Parametererstellung und -übergabe. Wo BLKMOV gewinnt, ist innerhalb der Schleife.

Außerdem funktioniert BLKMOV, und damit SCL, in manchen Situationen aus unerklärlichen Gründen nicht (in FBs). Ob das an einer kaputten CPU-Firmware liegt oder einfach zum Step7-Design gehört, weiß ich nicht.
 
Zurück
Oben