Step 7 SCL Zuweisungen, indirekter Vergleich

lexxoe

Level-1
Beiträge
4
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Tag,

Ich habe zwei Fragen:

die 1. ist schnell beantwortet:
Ich möchte Variabel auf ein DB zugreifen z.B. Var1 := MyDB.DX[Var_Byte,VarBit]. Soweit so gut.
Nun möchte ich aber die adresse vorher mathematisch berechnen. ich habe z.B 2 bytes (0.0 - 0.7 und 1.0 und 1.7) in dem DB hinterlegt.
ich habe dann zum beispiel eine Formel: Var_Byte_And_Bit := 2*x .... für x = 6 hätte man ein Wert von 12. 12 entspricht normalerweise dem Bit 1.3. also hätte ich stehen:
mit Variable: Var := MyDB.DX[Var_Byte_And_Bit] und mit zahlen ersetzt für x = 6 MyDB.DX[12]
und jetzt meine eigentliche frage ist dieses DX[12] = DX[1.3] bzw für Var_Byte = 1 und Varbit = 3 ??? ist das das gleiche ?

die zweite Frage:
ich habe 2 Datenbausteine DB1 und DB2. Nun möchte ich ein Datenfeld von 10 Byte oder 80 bit vom DB1 mit dem Datenfeld aus DB2 vergleichen. wenn die gleich sind soll einfach ein Boolscher ausgang geschaltet werden.

ich habs mal so versucht:

Repeat
If DB1.DX[Var_Byte_And_Bit] = DB2.DX[Var_Byte_And_Bit] Then
Var_Byte_And_Bit := Var_Byte_And_Bit +1 ;
End_IF;
Until Var_Byte_And_Bit = 80;
End_Repeat;

If Var_Byte_And_Bit = 80 then
Ergebnis := 1 ;
End_if;

oder

For Var_Byte_And_Bit := 0 To 80 Do
If DB1.DX[Var_Byte_And_Bit] = DB2.DX[Var_Byte_And_Bit] Then

ja und jetzt weiss ich nicht weiter, weil ja nur jedes einzelne bit abgefragt wird. ich will aber dass alle 80 bits abgefragt werden und wenn die alle richtig sind soll das Ergebnis := 1 gesetzt werden


Hoffe das war nicht zu umständlich erklärt. Die aufgabe im im allgemeinen lautet so:
Man hat eine Variable Anzahl an Spannern. diese Spanner sollen für eine Variable Anzahl an Schritten je nach schritt in 2 Stellungen gefahren werden.
Es soll z.b in Schritt 1: spanner 1 in Arbeitsstellung sein, Sp2 ind Grundstellung, Sp3 in AS, Sp4 in AS, Sp5 in GS usw.
in Schritt 2: Sp1 in Gs, Sp2 in AS, Sp3 in AS, Sp4 in Gs usw.

ich hab dazu mittels UDT's 2 DB's angelegt die mit max 20 Schritten und 100 Spannern vorbelegt sind. In dem DB1 sind die Sollwerte im DB2 die Istwerte.
Dazu sollen die max 100 Spanner schritt für schritt verglichen werden. Und erst in den nächsten Schritt gehen wenn der erste Schritt erfüllt ist.


Danke schonmal
 
ich habs mal so versucht:

Repeat
If DB1.DX[Var_Byte_And_Bit] = DB2.DX[Var_Byte_And_Bit] Then
Var_Byte_And_Bit := Var_Byte_And_Bit +1 ;
End_IF;
Until Var_Byte_And_Bit = 80;
End_Repeat;

If Var_Byte_And_Bit = 80 then
Ergebnis := 1 ;
End_if;

oder

For Var_Byte_And_Bit := 0 To 80 Do
If DB1.DX[Var_Byte_And_Bit] = DB2.DX[Var_Byte_And_Bit] Then

ja und jetzt weiss ich nicht weiter, weil ja nur jedes einzelne bit abgefragt wird. ich will aber dass alle 80 bits abgefragt werden und wenn die alle richtig sind soll das Ergebnis := 1 gesetzt werden


Hoffe das war nicht zu umständlich erklärt. Die aufgabe im im allgemeinen lautet so:
Man hat eine Variable Anzahl an Spannern. diese Spanner sollen für eine Variable Anzahl an Schritten je nach schritt in 2 Stellungen gefahren werden.
Es soll z.b in Schritt 1: spanner 1 in Arbeitsstellung sein, Sp2 ind Grundstellung, Sp3 in AS, Sp4 in AS, Sp5 in GS usw.
in Schritt 2: Sp1 in Gs, Sp2 in AS, Sp3 in AS, Sp4 in Gs usw.

das erste ist böse, da es eine Endlosschleife wird wenn zwei Bits nicht gleich sind.

die For-Schleife ist gut, ich würde es spontan so machen:

tmpErgebnis := 1;
For Var_Byte_And_Bit := 0 To 80 Do
If DB1.DX[Var_Byte_And_Bit] != DB2.DX[Var_Byte_And_Bit] Then
tmpErgebnis := 0;
END_IF;
END_FOR;
Ergebnis := tmpErgebnis;
!= soll ungleich sein.

Wenn nun ein Bit nicht stimmt wird dein Ergebnis falsch.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
zu Frage 1, ich vermute das ist an sich richtig, aber wie beschrieben off by one

Bit 0.0 = Index 0
Bit 0.7 = Index 7
Bit 1.0 = Index 8
Bit 1.3 = Index 11

Das Beispiel mit 2*x erscheint mir aber völlig praxisfremd, weil alles 1 oder 8 oder 16 ... Bits hat und nicht 2. Also Zugriff auf Bit 4.5: 4*8+5. Zugriff auf Bit 4.5 des Elements an Index 7 eines Arrays [0..20] einer 12 Byte-Struktur, Startadresse des Arrays ist (Byte) 100: 100*8+7*12*8+4*8+5

ja und jetzt weiss ich nicht weiter, weil ja nur jedes einzelne bit abgefragt wird. ich will aber dass alle 80 bits abgefragt werden

Die Aussage klingt lustig. "jedes einzelne" impliziert doch "alle", selbst in Endlosschleifen (vollständige Induktion) ;) Aber tommy0014's Lösung sieht schon richtig aus, aber die FOR Schleife muss von 0 bis anz_bits-1, also 79 gehen.

Allerdings erscheint mir der ganze Lösungsansatz nicht ganz passend zur Aufgabe. Deine Lösung ist ein generischer Vergleicher, nur dass die Anfangsadressen und Länge festgelegt sind, so dass er gar nicht generisch nutzbar ist. Außerdem ist es assemblerähnlich oder eher noch ein Level tiefer (Umgang mit Adressen) und ineffizient (Vergleich bitweise).

Mögliche Verbesserungen sehe ich also in 2 Richtungen: einen tatsächlich generischen Vergleicher "memcmp" in AWL, aber das führt zu ANY-Pointern ... "down that path lies madness" ... der hässliche Code existiert dann nur einmal. Oder einfach anwendungsspezifisch ein Array aus 100 Spanner-Bits oder als Erweiterung Spanner-UDTs anlegen und als solches benutzen, vergleichen etc. Das könnte flexibler sein, besonders wenn mal nicht ein 1:1-Vergleich gefordert ist.
 
und jetzt meine eigentliche frage ist dieses DX[12] = DX[1.3] bzw für Var_Byte = 1 und Varbit = 3 ??? ist das das gleiche ?
Step7 erwartet m.W.n. DBx.DX[ Byte , Bit]. Deine Variante DBx.DX[ Var_Byte_And_Bit ] dürfte einen Fehler bei der Ausführung ergeben.
Die Angabe des Index funktioniert m.W.n. nur beim symbolischen Zugriff auf ein Array.



Bevor ich zur 2. Frage komme:
Warum programmierst Du nicht symbolisch?
Wie sind denn die ganzen boolschen Werte symbolisiert (wenn überhaupt)? Einzeln oder als Array oder als Struct?

die zweite Frage:
ich habe 2 Datenbausteine DB1 und DB2. Nun möchte ich ein Datenfeld von 10 Byte oder 80 bit vom DB1 mit dem Datenfeld aus DB2 vergleichen. wenn die gleich sind soll einfach ein Boolscher ausgang geschaltet werden.
Hängt auch ein wenig davon ab, wie Du alles an den Baustein übergeben willst.


Wenn's denn unbedingt unsymbolisch bzw. absolut sein soll, dann mal dies als Anregung:
Code:
[FONT=Courier New]FUNCTION "Bitvergleich" : BOOL

VAR_INPUT
    DB_1: Block_DB;
    StartByte1: INT;
    StartBit1: INT;
    DB_2: Block_DB;
    StartByte2: INT;
    StartBit2: INT;
    Anzahl: INT;
END_VAR

VAR_TEMP
    i: INT;
END_VAR


    "Bitvergleich" := true;
    FOR i:= 1 TO Anzahl BY 1 DO
        IF DB_1.DX[ StartByte1 + ( StartBit1 + i - 1 ) / 8 , ( StartBit1 + i - 1 ) MOD 8 ] <>
           DB_2.DX[ StartByte2 + ( StartBit2 + i - 1 ) / 8 , ( StartBit2 + i - 1 ) MOD 8 ] THEN
            "Bitvergleich":= false;
        END_IF;
    END_FOR;
    

END_FUNCTION
[/FONT]
Ich würde aber eine Variante vorziehen, bei der die Bytes/Bits symbolisch übergeben werden.
 
Zuletzt bearbeitet:
*dummfrag*
Wenn die Datensätze nur auf Ungleicheit geprüft werden sollen, warum dann nicht byte- bzw. wortweise? Solange ich nicht das ungleiche Bit ermitteln will ist es doch Banane was da wo ungleich ist. Durchrennen bis bis was ungleich ist und dann raus aus der Schleife.
*/dummfrag*
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,
Danke schonmal für die antworten !

Die Aufgabe ist noch etwas komplizierter... also die vorher beschriebenen Spanner bleiben. Genauso wie die einzelnen Schritte. Es sollen aber hinzu noch unterschiedliche Programme laufen. D.h Programme 0-128, Schritte 0-10, Spanner 0-100. Die jeweil verschachtelt sind. ich habe das mit UDt's gemacht

z.B UDT1:
Code:
Sp1_GS    
Sp1_AS    
Sp2_GS   
Sp2_AS

bis 

Sp100_AS

im UDT2:
Code:
Schritt    ARRAY[1..10]   
    "Spanner"

im DB1:
Code:
PRG    ARRAY[0..128]           
    "HMI_Sollwerte"

Also steht im DB1 in der Datenansicht:
Code:
PRG[0].Schritt[1].Sp1_GS    
PRG[0].Schritt[1].Sp1_AS  
...
PRG[128].Schritt[10].Sp100_AS

es Soll jetzt je nachdem welches Programm gerade läuft die Schritte mit den Spannern vom DB1 (Sollwerte) mit dem DB2 (Istwerte) verglichen werden?

Zitat von Drutbluck

Allerdings erscheint mir der ganze Lösungsansatz nicht ganz passend zur Aufgabe.
wie hättest du es denn gemacht ?
 
Hallo,

sorry ich bin nicht so oft im Forum und habe nicht so oft Zeit zu schreiben.

Ein Vergleicher ist wahrscheinlich am besten eine separate Funktion, diese ist entweder vollkommen generisch oder typ(UDT)-spezifisch.

Der UDT-spezifische Vergleicher ist am Anfang am einfachsten und vielleucht auch flexibler. Dazu einen FC erstellen, in SCL oder AWL oder ..., mit 2 INPUT-Parametern des UDT-Typs. Diese Parameter lassen sich sowohl einfach übergeben als auch einfach abfragen. Symbolisch, und mit beliebigen Instanzen des UDT.

Arrayzugriffe sind ohnehin ineffizient, ich denke Zugriff via Parameter ist nur wenig ineffizienter.

Ein generischer Vergleicher geht mit ANY-Pointern, dabei ist die Parameterübergabe einfach, den Vergleicher selbst zu schreiben ist nicht so einfach aber dafür geht es so effizient wie eben möglich.

Dein Beispielcode zum Vergleichen könnte auch mit einem Präprozessor generiert werden, der so etwas ähnliches wie C-Makros in SCL implementiert. Das ist effizienter als ein Vergleicher-FC und hat noch andere Vorteile, aber die höchste Effizienz erfordert möglichst DINT-Vergleiche statt BOOL. Dann muss zunächst mal der Präprozessor entwickelt werden.

Nur das direkte manuelle "absolute" "Programmieren" ohne rein symbolischen Quellcode würde ich möglichst vermeiden.
 
Zurück
Oben