Zugriff auf einen UDT / Array mit Variablen?

MSP

Level-1
Beiträge
210
Reaktionspunkte
21
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

für unser Regallager speichern wir alle Daten in einem Array innerhalb eines UDT's ab.

Array[1..3,1..5] zB
Belegt bool
Frei bool

Dadurch können wir jedes Fach im Regal eindeutig definieren im Array.

Soweit so gut.

Nur wie prüfe ich jetzt am besten ab das ein Fach belegt ist?

Der Bediener soll ein Fach auswählen, zB Fach 1.2
Das bedeutet das das Array [1,2] abgefragt werden soll auf Belegt oder Frei.

Nur wie kann ich es jetzt in Step7 programmieren, das diese beiden Variablen X und Y an eine Vergleichsfunktion übergeben werden?

Am liebsten wäre mir natürlich wie aus C etc bekannt, das ganze so aufzurufen:

U "Fach".Fach[x,y].Belegt
= #Frei

Das ich also die beiden Variablen X und Y mit den Werten 'füttern' kann die der Benutzer durch seine Fachauswahl bestimmt hat.

Wenn das so nicht geht, wie dann? Muss man dann jedes Fach in einer Schleife einzeln prüfen? Und wie zählt man dann in der Schleife hoch bzw Runter?

In C / C++ geht das ganz einfach, nur in Step7 ist das irgendwie ein Buch mit 7 Siegeln :cry:

Gruss,
Michael
 
1. mir ist nicht verständlich warum du frei und belegt als 2 variablen benutzt. wenn das fach nicht frei ist, ist es belegt.

2. du kannst das array folgendermassen ansprechen
rechte maustaste, symbol einfügen, bei dem db das + anklicken und das array wählen.
in deinen code wird dann eingefügt DB1.fach[..] .. ersetzt du z.b. durch 1,2. s7 macht dann daraus die absolute adresse.

du kannst natürlich auch direkt u db1.fach[1,2] schreiben.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Volker,

das mit dem Ansprechen schaffe ich ja, aber nur wenn ich die Koordinaten direkt vorgebe.

Ich möchte aber anstatt fester Werte in der Abfrage Variablen haben, in welche ich dann meine Werte lade und die dann dort genommen werden.

Nur leider will das nicht klappen wenn ich zB sage:

"Fach".Fach[#Variable1,#Variable2].Belegt

Ich möchte halt eine einfache Abfrage haben ob das entsprechende Fach belegt oder frei ist, und dafür am besten nur einen Befehl nutzen, den obigen.
Im Moment müsste ich jedes Fach einzeln abfragen, was ich mir nicht vorstellen kann das dies so gemacht wird in der Praxis, denn ein Lager mit mehreren Tausend Fächern so abzufragen ist alles andere als schnell und logisch :)

Michael
 
da muss ich dich leider entäuschen.

der index ist ein fester wert und kann zur laufzeit nicht verändert werden (keine variable indizierung möglich).

die einzige möglichkeit ist, dass du mit einem eindimensionalen array arbeitest.

also
fach oben = 1-3
fach mitte = 4-6
usw.

dann könntest du die indirket ansprechen.
 
Hallo,

hmm schade eigendlich das das nicht möglich ist :(
Wie wird denn in 'realen' Regallägern die Fachbestimmung getätigt?
Irgendwie muss das RBG ja wissen wohin es fahren muss.. und das in einer schnellen und speichersparenden Art?

Gruss,
Michael
 
hi,

wenn ich das richtig verstanden habe, dann brauchst du nur 2 EA-Felder im Visu-System und n Bit.

1. EA-Feld: Regal Nr.
2. EA-Feld: Fach Nr.
Bit: Anfrage starten

D.h. der Bediener wählt Regal und Fach-Nummer vor und bestätigt die Anfrage. Das Bit wird gespeichert, und von deinem S7-FB nach dem Bearbeiten der Anfrage rückgesetzt.

Mit Hilfe der 2 Werte, die du bei gestarteter Anfrage auswertest ist es relativ einfach die Werte im ARRAY indirekt auszuwerten.

Schöne WE

Micha
 
Re: Regal

sps-concept schrieb:
Hallo,

mit indirekter Adressierung.

MfG
André Räppel

klar, aber ich kann das fach nicht direkt über zeile, spalte ansprechen, da es sich um ein mehrdimensionales array handelt.

ich denke ich würde das so machen.
ich sehe 100 spalten und 10 zeilen vor.
mein db würde dann von dw 1-100 die spalten der 1sten zeile enthalten. 101-200 die spalten der 2ten zeile, usw.
evtl auch mehr als ein int je fach. kommt eben drauf an wieviel daten ich ablegen will.

dann kann ich ohne probleme die adresse des faches ermitteln.
 
ich kenne mich mit scl nicht so gut aus.

schreib sowas mal in scl. (aber nur ein paar anweisungen) und poste den code mal hier.

ich würde mir das dann gerne mal in awl ansehen wie das übersetzt worden ist.
 
SCL wäre wirklich besser !

Hallo MSP,

Andre hat leider recht: mit indirekter Adressierung,
weil beim Design von S7 die indizierte Adressierung
leider verschlafen wurde!

Nur: indirekte Adressierung heist: Arbeiten mit den
Adressregistern und Zeigern.

Wenn du dein Programm in 2 Wochen noch verstehen
möchtest, bist du mit SCL wirklich besser beraten, da
kannst du genauso arbeiten wie in C/C++.

Kleines Beispiel (quick und dirty!) für den Einstieg
(noch unbedingt Symbolik ergänzen!):

//============================================
TYPE UDT99
STRUCT
Lager : ARRAY [1..20,1..20] OF BOOL;
END_STRUCT
END_TYPE

//============================================
DATA_BLOCK DB99 UDT99
BEGIN
END_DATA_BLOCK

//============================================
FUNCTION_BLOCK FB99

VAR_TEMP
iRow : INT; //Zeile
iCol : INT; //Spalte

END_VAR

VAR_IN_OUT
Hochregal : UDT99; // Durchgangsparameter !
END_VAR

// ein paar Teile einlagern ...
FOR iCol := 5 TO 10 DO
FOR iRow := 11 TO 15 DO
Hochregal.Lager[iCol,iRow] := TRUE;
END_FOR;
END_FOR;

END_FUNCTION_BLOCK

//============================================

Ach ja: man kann natürlich auch Arrays Of UDTs erstellen,
so kannst du z.B. nicht nur leer / belegt (dafür braucht man
übrigens wirklich nur EIN Bit) festhalten, sondern auch eine
Teilenummer oder den Zeitpunkt der Einlagerung.

Gruß G.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nachtrag zu SCL !

Hallo zusammen,

grade sind mir noch Zweifel gekommen, ob ich
nicht Zeile und Spalte vertauscht habe:

Evtl. auch mal so herum testen:

Hochregal.Lager[iRow,iCol] := TRUE;

Gruß G.
 
Hallo G.,

das mit SCl klingt soweit gut und für uns recht naheliegend, nur SCL ist doch nach dem kompilieren ein wenig zu groß und langsam gegenüber den anderen Varianten, oder?

Gruss und schönes Wochenende allen,
Michael
 
grösse kommt immer auf den code an.
im endefekt liegt sowieso alles als awl (MC5) vor. beim übersetzen wird aber viel mit den ar's gearbeitet.

und über die geschwindigkeit braucht man sich nicht allzuviel gedanken machen. die s7 ist schon schnell.

ich werde ogigen code am montag mal testen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
SCL und Geschwindigkeit

MSP schrieb:
Hallo G.,

das mit SCl klingt soweit gut und für uns recht naheliegend, nur SCL ist doch nach dem kompilieren ein wenig zu groß und langsam gegenüber den anderen Varianten, oder?

Gruss und schönes Wochenende allen,
Michael

Hallo Michael,

da es in S7 (AWL) keine indizierte Adressierung gibt,
müsstest du auch in AWL relativ komplizeirten Code
schreiben!

Du kannst auch auf dem PC Assembler-Programme
schreiben, wenn du das letzte aus deinem Code
herausholen willst, aber das geht natürlich auch auf
Kosten der Wartungsfreundlichkeit.

Wie bei jedem Compiler gibt es übrigens auch
in SCL Compilerschalter, mit dem man auf den
erzeugten Code Einfluss nehmen kann. Z.B. ist
es bei Arrayoperationen hilfreich, die Eingangs-
parameter EINMAL auf Bereichsgrenzen zu prüfen
und die Bereichsüberprüfung des Compilers auszu-
schalten, denn das erzeugt Unmengen von Code.

Gleiches gilt für das ENO-Flag. Wenn dein Programm
getestet ist, kannst du auch die Debug-Infos ab-
schalten, dann kannst du den SCL-Code nicht mehr
Online testen, aber er wird DEUTLICH schneller.

Gruß G.
 
so hab hier mal ein wenig getestet. klappt nicht wirklich richtig.

für folgendes gilt:

hochregal: 10 zeilen, 10 spalten.

belegt werden soll fach: zeile 2, spalte 4

Code:
//============================================ 
TYPE UDT80 
STRUCT 
Lager : ARRAY [1..10,1..10] OF BOOL; 
END_STRUCT 
END_TYPE 

//============================================ 
FUNCTION_BLOCK FB80

VAR_INPUT
zeile : INT;  
spalte : INT; 
END_VAR 

VAR_IN_OUT
Hochregal : UDT80; // Durchgangsparameter ! 
END_VAR 

// ein paar Teile einlagern ... 
Hochregal.Lager[zeile,spalte] := TRUE; 

END_FUNCTION_BLOCK 
//============================================


daraus erzeugt s7 diesen code
Code:
      SET   
      SAVE  
      =     L      0.1
      L     #zeile
      ITD   
      L     L#1
      -D    
      L     L#16                        //16 da für jede zeile 16 bit bereitgestellt werden
      *D    
      L     #spalte
      ITD   
      TAK   
      T     LD     2
      TAK   
      L     L#1
      -D    
      L     LD     2
      +D    
      L     DIW [AR2,P#4.0]
      T     LW     2
      TAK   
      AUF   DB [LW     2]
      L     DID [AR2,P#6.0]
      +D    
      LAR1  
      =      [AR1,P#0.0]
      SAVE  
      BE

ein bisschen entzerrt sieht das so aus
Code:
      L     #zeile
      ITD   
      L     L#1                         // -1 da zeile 1 bei byte 0 beginnt
      -D    
      L     L#16                        // 16 da für jede zeile 16 bit bereitgestellt werden
      *D    
      T     LD     2

      L     #spalte
      ITD   
      L     L#1                         // -1 da spalte bei bit 0 beginnt
      -D    
      L     LD     2
      +D    
      L     DIW [AR2,P#4.0]
      T     LW     2
      TAK   
      AUF   DB [LW     2]
      L     DID [AR2,P#6.0]
      +D    
      LAR1  
      =      [AR1,P#0.0]                //erzeugt stop
      SAVE  
      BE

wenn ich den baustein beobachten will, bekomme ich folgenden fehler.

(D05F) Kodierungsfehler: Fehler im Datenteil (z.B. Reservebyte ungleich NULL, ...).

nun füge ich diese zeile ein, übertrage den fb und lösche diese zeilen wieder.
L 2
T #zeile
L 4
T #spalte
jetzt kann ich beobachten und die im ob1 übergebenen parameter werden im fb übernommen.


cpu geht ohne ob121 in stop bis ich dieses ändere.
= [AR1,P#0.0] ==> = DIX [AR1,P#0.0]


an dieser stelle ist das AR1 = 2.3 (was auch korrekt wäre)


beobachte ich nun db83
0 in zeile INT 0 2
2 in spalte INT 0 4
4 in_out hochregal struct P#P 0.0 (sollte hier jetzt nicht eigentlich 2.3 stehen? )

die einzelnen bits lassen sich so nicht betrachten.

erzeuge ich mit dem udt80 einen gobal-db, so belegt jede zeile 2byte, von denen bit 0-9 gebraucht werden.
letztes dbx ist also 19.1

schaue ich mir nun db83 in einer vat an so ist dort dbx 1.1 = true (zeile 1,spalte 10) und dbx 3.2 = true (zeile 2,spalte 11)
alle anderen bits sind false.
??????????????

ausserdem ist das letzte bit welches sich beobachten lässt dbx9.7


also mir ist das alles ein bisschen rätselhaft.
 
ok der korrekte dix wurde nicht gesetzt weil ein set fehlt

SET
= DIX [AR1,P#0.0]

dann wird schon mal das richtige bit gesetzt.
aber warum kommen auch noch andere bits ?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi,

ich hab das mal in AWL programmiert. Ist nicht viel.

Hier der Quellcode für ein kleines S7-Programm:
Code:
DATA_BLOCK "DB_Regaldaten"
TITLE =
AUTHOR : MICHA
VERSION : 1.0


  STRUCT 	
   Belegung : ARRAY  [1 .. 3, 1 .. 5 ] OF //Belegung der Regalfächer
   STRUCT 	
    FREI : BOOL ;	//Fach ist Frei
    BELEGT : BOOL ;	//Fach ist Belegt
   END_STRUCT ;	
  END_STRUCT ;	
BEGIN
   Belegung[1, 1].FREI := FALSE; 
   Belegung[1, 1].BELEGT := FALSE; 
   Belegung[1, 2].FREI := FALSE; 
   Belegung[1, 2].BELEGT := FALSE; 
   Belegung[1, 3].FREI := FALSE; 
   Belegung[1, 3].BELEGT := FALSE; 
   Belegung[1, 4].FREI := FALSE; 
   Belegung[1, 4].BELEGT := FALSE; 
   Belegung[1, 5].FREI := FALSE; 
   Belegung[1, 5].BELEGT := FALSE; 
   Belegung[2, 1].FREI := FALSE; 
   Belegung[2, 1].BELEGT := FALSE; 
   Belegung[2, 2].FREI := FALSE; 
   Belegung[2, 2].BELEGT := FALSE; 
   Belegung[2, 3].FREI := FALSE; 
   Belegung[2, 3].BELEGT := FALSE; 
   Belegung[2, 4].FREI := FALSE; 
   Belegung[2, 4].BELEGT := FALSE; 
   Belegung[2, 5].FREI := FALSE; 
   Belegung[2, 5].BELEGT := FALSE; 
   Belegung[3, 1].FREI := FALSE; 
   Belegung[3, 1].BELEGT := FALSE; 
   Belegung[3, 2].FREI := FALSE; 
   Belegung[3, 2].BELEGT := FALSE; 
   Belegung[3, 3].FREI := FALSE; 
   Belegung[3, 3].BELEGT := FALSE; 
   Belegung[3, 4].FREI := FALSE; 
   Belegung[3, 4].BELEGT := FALSE; 
   Belegung[3, 5].FREI := FALSE; 
   Belegung[3, 5].BELEGT := FALSE; 
END_DATA_BLOCK

FUNCTION_BLOCK "Regalprüfung"
TITLE =Status der Fächer in den Regalen
AUTHOR : MICHA
VERSION : 1.0


VAR_INPUT
  DB_NR : BLOCK_DB ;	//DB-Nr. Regaldaten
  OFFSET : INT ;	//Offset [BYTE] des Arrays im Regaldaten-DB
END_VAR
VAR_OUTPUT
  QFREI : BOOL ;	//Ausgewähltes Fach ist Frei
  QBELEGT : BOOL ;	//Ausgewähltes Fach ist Belegt
END_VAR
VAR
  siREGAL_NR : INT ;	//Gewünschte Regal-Nr.
  siFACH_NR : INT ;	//Gewünschte Fach-Nr.
  sbANFRAGE : BOOL ; //=1: Auswertung starten	
END_VAR
VAR_TEMP
  tiSPEICHER : INT ;	//Zwischenspeicher
END_VAR
BEGIN
NETWORK
TITLE =Anfrage?

      UN    #sbANFRAGE; 
//     R     #QFREI
//   R     #QBELEGT
      BEB   ; 
      R     #sbANFRAGE; 
NETWORK
TITLE =Pointer setzen

      L     #siREGAL_NR; 
      L     10; 
      *I    ; 
      L     10; 
      -I    ; 
      T     #tiSPEICHER; 

      L     #siFACH_NR; 
      L     2; 
      *I    ; 
      L     2; 
      -I    ; 
      L     #OFFSET; 
      +I    ; 
      L     #tiSPEICHER; 
      +I    ; 
      SLW   3; 
      TAR2  ; 
      +D    ; 
      LAR1  ; 

      AUF   #DB_NR; 
      U     DBX [AR1,P#0.0]; 
      =     #QFREI; 
      U     DBX [AR1,P#0.1]; 
      =     #QBELEGT; 
END_FUNCTION_BLOCK

DATA_BLOCK "INDB_Regalprüfung"
TITLE =
AUTHOR : MICHA
VERSION : 1.0

"Regalprüfung"
BEGIN
   DB_NR := DB 1; 
   OFFSET := 0; 
   QFREI := FALSE; 
   QBELEGT := FALSE; 
   siREGAL_NR := 0; 
   siFACH_NR := 0; 
   sbANFRAGE := FALSE; 
END_DATA_BLOCK

ORGANIZATION_BLOCK OB 1
TITLE = "Main Program Sweep (Cycle)"
VERSION : 0.1


VAR_TEMP
  OB1_EV_CLASS : BYTE ;	//Bits 0-3 = 1 (Coming event), Bits 4-7 = 1 (Event class 1)
  OB1_SCAN_1 : BYTE ;	//1 (Cold restart scan 1 of OB 1), 3 (Scan 2-n of OB 1)
  OB1_PRIORITY : BYTE ;	//Priority of OB Execution
  OB1_OB_NUMBR : BYTE ;	//1 (Organization block 1, OB1)
  OB1_RESERVED_1 : BYTE ;	//Reserved for system
  OB1_RESERVED_2 : BYTE ;	//Reserved for system
  OB1_PREV_CYCLE : INT ;	//Cycle time of previous OB1 scan (milliseconds)
  OB1_MIN_CYCLE : INT ;	//Minimum cycle time of OB1 (milliseconds)
  OB1_MAX_CYCLE : INT ;	//Maximum cycle time of OB1 (milliseconds)
  OB1_DATE_TIME : DATE_AND_TIME ;	//Date and time OB1 started
END_VAR
BEGIN
NETWORK
TITLE =

      CALL "Regalprüfung" , "INDB_Regalprüfung" (
           DB_NR                    := "DB_Regaldaten",
           OFFSET                   := 0,
           QFREI                    := M    100.0,
           QBELEGT                  := M    100.1);

END_ORGANIZATION_BLOCK

Bedienung wie in meinem anderen Posting. Alles in den Instanz DB schreiben.
Momentan wird der FB bei jeder Anfrage einmal abgearbeitet.
Soll die Auswertung zyklisch erfolgen, dann einfach NW1 im FB1 löschen...

Es fehlt noch eine Plausibilitätskontrolle der Auswahl.

Schöne Grüße

Micha
 
FC: 2-dimensionales Array über Zeile / Spalte ansprechen

Hallo

Ich habe mal eine FC geschrieben.


  • 2D-Array V1.0 --- August 2005 von: www.Lischis-Home.de
    Mit diesem Baustein ist es möglich ein 2-dimensionales Array über Zeile / Spalte anzusprechen.
    Die Zelle kann gelesen und beschrieben werden.
    Der Typ der Zelle darf folgendes Format haben: Bool, Byte, Word(INT), DWord(DINT,Real)
    Das Array MUSS am Anfang des benutzten DB's liegen (also ab DBX0.0)

Findet ihr auf meiner Homepage unter S7 / 2d-array.zip
 
Noch kurz ein Wort zu SCL:

Der Code den SCL erzeugt ist ziemlich kompakt (habs mir mal angesehen).
Per Hand kann man das manchmal etwas optimaler machen, aber mehr als 10% sind wohl nicht drin (Spezialfälle mit 1 Mill. Schleifendurchläufen mal weggelassen :lol: ).
Ich würde für solche Dinge in jedem Fall SCL verwenden, da man so die Übersicht behält und sich nicht zu tief in "indirekter Adressierung" verstrickt, die Fehler nicht so leicht verzeiht. In einem Baustein (wie von Volker gezeigt) untergebracht geht es aber auch ganz gut, aber bei einem Regallager fällt sicher noch mehr solcher "Verwaltungskram" an der mehr "Datenbank-Funktionalität" als reine SPS-Steuerung verlangt.
 
Zurück
Oben