Step 7 Verständniss zu Pointern

Bekanor

Level-1
Beiträge
11
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Mahlzeit,

ich habe mir schon des öfteren hier Hilfen und Lösungen angelesen, komme aber nun bei Pointern an meine Grenze und muss daher einfach mal nachfragen. Ich bin in der Instandhaltung tätig und denke das ich mit der S7 soweit schon gut zurechtkomme. Letztes Projekt war eine S7 Erweiterung mit Schrittmotorsteuerung über Profibus, dabei konnte ich alle Fragen und Probleme durch Selbststudium lösen [hier war in der tat das Lesen der PB-Daten das kniffligste wenn man es noch nie gemacht hatte]. Bevorzugt nutze ich den KOP, AWL meide ich gerne wenn das Programm es zulässt.

Was möchte ich nun:
Ich will/muss eine Anlagenerweiterung aufbauen mit S7-300 für eine Teileerkennung. Dabei werte ich eine Kamera von oben und Sensorik von unten aus. Am Ende möchte ich für das erkennte Teil (ca 150 verschiedene) eine definierte Nummer haben mit der ich dann weiterarbeiten kann. Das ganze mit Step7 5.5

Hier mal umrandet als Beispiel:
Kamera gibt mir Typ A vor -> Wert 10 (Typen-Werte steigen in 10er Schritten -> 10, 20, 30...)
Sensoren geben mir Form 2 -> Wert 2 (Form-Werte sind 0-9)
-> ergibt Variante 12. Zu dieser Variante steht im DB 1 an 12. Stelle ein DBD -> DB1.DBD48 = 456789 -> Diese Zahl möchte ich als Ergebnis. (andere Varianten haben andere Zahlen)

Also brauche ich ja "nur" einen Pointer auf das DBD48. Leider finde ich das Thema schwer zu verstehen weil da zuviele Zeichenkombinationen zusammenkommen.

aber hier mal mein Stand wie ich glaube das es gehen müsste.
Code:
[FONT=arial]L DB2.DBD0                         -> da lege ich die Variante ab (direkt x4 gerechnet wegen DINT)[/FONT]
[FONT=arial]SLD 3                                    -> Wenn ich es richtig verstanden habe schiebt es hier im Speicher etwas umher, das muss einfach so sein!??
LAR1                                     -> schreibt das AR1, also eigendlich ist das schon der Pointer bzw die Adresse für den Pointer?

AUF DB1                             -> DB erst aufrufen, muss so sein
L DBD [AR1, P#0.0]            -> er lädt nun das DBD
T DB2.DBD4                        -> da habe ich nun mein Ergebniss[/FONT]

Fragen:
Funktioniert das wirklich so einfach? Ich habe leider noch keine Hardware hier zum testen
Geht es kürzer? Also kann ich in normalen DB-Aufrufen DB1.DBD[AR1,P#0.0] verwenden oder ists da tatsächlich das sauberste einen DB als Zwischenspeicher zu nehmen um von dort "normal" aufzurufen?
kann ich, zur Verkleinerung auch Lokalworte dafür nutzen? (Also statt den DB2 einfach LDW0 und LDW4 nutzen)
[zum verstehen]der P#0.0 (weiterschieben, eher in Verbindung mit Schleife/Zähler?) muss immer dabei sein? Und muss immer zum Typ passen? (DBD P#0.3 -> Stopp, DBB p#0.3 -> Stopp, ...)
wenn ich den DB auchnoch Variabel machen möchte.. wäre es any-Zeiger? Da ist ja gar nicht mehr zu erkennen warum da was passiert..

Ich hoffe das ist soweit verständlich

mfg Beka
 
Ich kenne ja deine Rahmenbedingungen nicht, aber ich denke ich würde so vorgehen:

Zieldaten dint
Kamera int
Sensor int
Add int (als Zwischenergebnis)

//DB enthält die Daten
Data Array [0..149] of Dint

//Deine Sensoren geben dir
Add:=Sensor+Kamera

Zieldaten:=DB.Data[Add]

Wäre das nicht einfacher?

[Muss dazu sagen: ich bin ne Niete in AWL :( ]
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Fragen:
Funktioniert das wirklich so einfach? Ich habe leider noch keine Hardware hier zum testen
Sollte so funktionieren. Obwohl ich nicht weiß was beim "direkt x4 gerechnet" DB2.DBD0 gemeint ist.
In DB2.DBD0 muss einfach die Byte-Adresse stehen auf die du zugreifen willst.
Geht es kürzer? Also kann ich in normalen DB-Aufrufen DB1.DBD[AR1,P#0.0] verwenden oder ists da tatsächlich das sauberste einen DB als Zwischenspeicher zu nehmen um von dort "normal" aufzurufen?
Möglich wäre...
Code:
L   P#30.0    //Pointer direkt laden
T   LD0        //hier keine DB-Variable verwenden

AUF DB1
L   DBD[LD0]

//------------------------------------------------------------

L   L#30    //gleichen Pointer selbst erstellen
SLD 3
T   LD0        //hier keine DB-Variable verwenden

AUF DB1
L   DBD[LD0]
kann ich, zur Verkleinerung auch Lokalworte dafür nutzen? (Also statt den DB2 einfach LDW0 und LDW4 nutzen)
Das hat sogar Vorteile weil...
Code:
L   L#30
SLD 3
LAR1

AUF DB1
L   DBD[AR1,P#0.0]    //lädt DB1.DBD30
T   DB2.DBD30
L   DBD[AR1,P#0.0]    //lädt jetzt DB2.DB30 weil wir inzwischen auf DB2 zugegriffen haben.
                                //verwendet man Lokaldaten wird das DB-Register nicht verändert
[zum verstehen]der P#0.0 (weiterschieben, eher in Verbindung mit Schleife/Zähler?) muss immer dabei sein? Und muss immer zum Typ passen? (DBD P#0.3 -> Stopp, DBB p#0.3 -> Stopp, ...)
Wenn du einen Pointer hast der hinten noch einen Wert bei der Bitadresse hat, also z.B.: P#30.3 und du versuchst damit ein Byte zu laden, dann wäre dass das selbe als würde man L DB2.DBB30.3 schreiben -> geht nicht.

Schau dir mal das FAQ zum Thema Pointer von Volker an. Da steht vieles (auch das SLD3) erklärt.
http://www.sps-forum.de/faq/8887-pointer-zeiger-fifo-lifo.html
wenn ich den DB auchnoch Variabel machen möchte.. wäre es any-Zeiger? Da ist ja gar nicht mehr zu erkennen warum da was passiert..
Geht...
Code:
L   10
T   LW0
AUF [LW0]    //Das geht aber nur mit einem wort aus den Lokaldaten oder Merkern.

In SCL geht manches, sofern man z.B. ein Array verwenden kann, oft um einiges leichter. Wie wild irgendwo in DBs herumzufuchteln bleibt aber AWL vorbehalten.
 
Zuletzt bearbeitet:
Du hast ein ARRAY OF DINT und willst auf ein bestimmtes Element des Arrays zugreifen, dessen Position im Array variabel berechnet werden soll.

Berechne zunächst, auf welches Element des Arrays Du zugreifen mußt, wenn ich richtig verstanden habe dann ungefähr so:
Index := (Kamerawert * 10) + Sensorwert ; (wenn Kamerawert 0, 1, 2, 3, ...)
oder
Index := Kamerawert + Sensorwert ; (wenn Kamerawert 0, 10, 20, 30, ...)

Nun greife auf das Element ARRAY[Index] zu. Das geht bei der S7-300 aber leider nur in SCL so übersichtlich.

In AWL muß man selber die Adresse ausrechnen, an der das Element liegt:
Adresse := Index * 4 * 8 + Arrayanfang ;
"* 4" weil die Elemente 4 Bytes (= 1 DINT) groß sind
"* 8" weil eine Bitadresse P#Byte.0 angegeben werden muß
"+ Arrayanfang" falls das Array im DB nicht bei DBX0.0 beginnt, dann z.B. P#100.0 addieren für Array ab DBX100.0

"*4" und "*8" kann man zusammenfassen zu "*32" was einem Bit-Schieben um 5 Stellen nach links entspricht, wofür man "SLD 5" schreiben kann.
("SLD 1" = *2 | "SLD 2" = *4 | "SLD 3" = *8 | "SLD 2" + "SLD 3" = "SLD 5" = *32)

Dadurch kann Dein AWL-Programm z.B. so aussehen:
Code:
L #index            //(TEMP, INT)
SLD 5               //Array-Index --> Adresse P#
L P#0.0             //Anfangsadresse des Array im DB
+D                  //dazu
LAR1                //berechnete Adresse in AR1 laden

AUF "DB1"
L DBD [AR1, P#0.0]  //DINT aus "DB1".MyArray[#index] lesen
T "DB2".MeinWert

Oder etwas besser lesbar so:
Code:
L #index            //(TEMP, INT)
SLD 5               //Array-Index --> Adresse P#
L P#0.0             //Anfangsadresse des Array im DB
+D                  //dazu
T #tmpAdresse       //berechnete Adresse in TEMP-DWORD speichern

AUF "DB1"
L DBD [#tmpAdresse] //DINT aus "DB1".MyArray[#index] lesen
T "DB2".MeinWert


"L DBD [#tmpAdresse]" = speicherindirekte Adressierung, weil der Pointer (die Adresse) im Speicher liegt (Speicher kann L, M, DB sein)

"L DBD [AR1, P#0.0]" = registerindirekte Adressierung, weil der Pointer (die Adresse) in einem Adressregister ARx liegt
Statt dem P#0.0 kann noch ein zusätzlicher Versatz/Offset angegeben werden. Nützlich wenn man in AR1 die Anfangsadresse einer Struktur hält und nacheinander auf mehrere Elemente dieser Struktur zugreifen will.

Harald
 
Soo, vor so etwas hatte ich Angst, da glaubt man es verstanden zu haben, und dann wird's doch nochmal kompliziert.. :)


"* 8" weil eine Bitadresse P#Byte.0 angegeben werden muß
da hatte ich schon den ersten Aufhänger. Verstehe nicht wieso *8 wenn ich garnicht bis auf die Bit-Ebene runter will?

Code:
 L #index            //(TEMP, INT)
 SLD 5               //Array-Index --> Adresse P#
 L P#0.0             //Anfangsadresse des Array im DB
 +D                  //dazu
 LAR1                //berechnete Adresse in AR1 laden

 AUF "DB1"
 L DBD [AR1, P#0.0]  //DINT aus "DB1".MyArray[#index] lesen
 T "DB2".MeinWert
nächster Treffer. Da dachte ich SLD3 muss sein, okay.. Muss nicht, kann auch noch Variieren. Das Ganze liegt nun am Speicheraufbau? SLD5 weil hier nur noch ein INT geladen wird?
Lade ich nun ein Int, schreibt er es in Byte 0+1. Damit sie für den Pointer an der richtigen Stelle liegen (was Byte 4+5 sein sollten?) müssen sie um 32 Bits geschoben werden. (Das "5 Stellen" ist also eigendlich nur 4 Bytes?)
Soweit richtig verstanden?
Wieso schiebt er nun abernicht in die Bitadresse rein (Wenn ich das Bild Pointer-Aufbau so sehen..? http://www.sps-forum.de/faq/8887-pointer-zeiger-fifo-lifo.html), also in die letzten 3 Bits?


Ich möchte ja schon gern das mein Programm später läuft, vor allem aber möchte ich verstehen warum :)
Da raucht ja echt nur der Schädel.

gutes Nächtle
Beka
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Soo, vor so etwas hatte ich Angst, da glaubt man es verstanden zu haben, und dann wird's doch nochmal kompliziert.. :)



da hatte ich schon den ersten Aufhänger. Verstehe nicht wieso *8 wenn ich garnicht bis auf die Bit-Ebene runter will?


nächster Treffer. Da dachte ich SLD3 muss sein, okay.. Muss nicht, kann auch noch Variieren. Das Ganze liegt nun am Speicheraufbau? SLD5 weil hier nur noch ein INT geladen wird?
Lade ich nun ein Int, schreibt er es in Byte 0+1. Damit sie für den Pointer an der richtigen Stelle liegen (was Byte 4+5 sein sollten?) müssen sie um 32 Bits geschoben werden. (Das "5 Stellen" ist also eigendlich nur 4 Bytes?)
Soweit richtig verstanden?
Wieso schiebt er nun abernicht in die Bitadresse rein (Wenn ich das Bild Pointer-Aufbau so sehen..? http://www.sps-forum.de/faq/8887-pointer-zeiger-fifo-lifo.html), also in die letzten 3 Bits?


Ich möchte ja schon gern das mein Programm später läuft, vor allem aber möchte ich verstehen warum :)
Da raucht ja echt nur der Schädel.

gutes Nächtle
Beka

Wenn Sie ein pointer adresse berechne von ZB DBD40 muste Sie das anzahl bits zahlen ab DBX0.0 fur DBD 40 ist das 40(Byte) * 8 = 320 Ein pointeradresse ist immer ein DWord
Wenn Sie z.b. LD0 die name Adresse gibt format DWORD.

Wenn Ihre index = 10 und Sie muste Das artikel nr aus ein DWord laden muste Sie fur Jede artikel die index mit 32(bit) multiplizieren
die Code wurde dann
Code:
L Index       //=10
SLD5         //= *32
T Adresse   //  = 320  
AUF DB1
L DBD[Adresse]     // L DBD40
 
Nu hab ich es verstanden.

Ich hatte es mir wohl zu Bildlich vorgestellt.
*falsch* Wenn ich "L DBD [AR1, p#0.0]" habe soll halt in der Klammer nicht "40" rauskommen.
*richtig* DBD gibt die Länge der Daten an die gelesen wird, der Pointer zeigt das erste Bit. Hmm.. eigentlich dann doch gar nicht so schwer.

Ich konnte es gerade auch mal an einer Anlage testen, werde wohl auch den DB variabel aufrufen. Kamera ruft den DB auf, Sensoren zeigen die entsprechende Zeile. Wird übersichtlicher, und wenn es später weitere Typen gibt, ist eine Erweiterung leichter.

vielen Dank für die Hilfe :)

mfg Beka
 
Wenn du die DB indirekt aufrufen wolh mussen Sie das DB nr in ein int kopiëren z.b. lokal variabele DB_nr. Und die DB machen Sie actief mit AUF DB [DB_nr]


Verstuurd vanaf mijn GT-I9301I met Tapatalk
 
Zuletzt bearbeitet:
Zurück
Oben