# Auswahlkriterium Betriebsstunden



## rs-plc-aa (18 November 2004)

Hallo,

ich bin noch ein wenig am rätseln für eine demnächst anstehende Aufgabe...


Kurzbeschreibung:

Es geht um 7 Betriebsmittel die angefordert werden sollen.

Die Anforderung kommt über digitale Eingänge (7 Stück)

Nur ist nicht jedem Eingang ein bestimmtes Betriebsmittel zugeordnet, sondern sollen anhand der Anzahl momentan geschalteter Eingänge die Betriebsmittel herausselektiert werden mit den wenigsten Betriebsstunden.

Wenn also 3 beliebige (von diesen 7) digitaleingänge "high" sind sollen die 3 Betriebsmittel angewählt werden welche am wenigsten Stunden drauf haben.

Kommt ein weiterer hinzu - oder fällt einer weg, geht das Spielchen weiter...



Hierfür gibt es bestimmt verschiedene Lösungsmöglichkeiten - aber nicht eine (komplett verwendbare zumindest) ist mir bis jetzt eingefallen... *schäm*   



Hat jemand so was ähnliches schon mal gemacht ?


Am schlimmsten stelle ich mir das zwischenspeichern vor, da ich keine Lösung mit 300 Merkern bevorzugen würde.

Der Kniff ist ja auch, das das ganze ununterbrochen so weiterläuft.


Es muß natürlich zunächst geprüft werden ob das Betriebsmittel überhaupt bereit ist - was ja an sich kein Problem ist - nur muß man das auch mit verankern.


Man könnte "nicht bereite" von der Prüfung ausschließen oder mitprüfen und anschließend doch feststellen daß es nicht bereit ist - dann muß ja ersatzweise das nächst höhere genommen werden usw. ...



Hat hier vielleicht SCL eine Wunderlösung parat?

Damit habe ich aber noch keine Erfahrung - aber das wäre ja dann ein separater Baustein der immer nur die entsprechende Nummer ausspuckt die dann letztendlich vom Hauptprogramm an- oder abgewählt werden.

Somit könnte ich mir vielleicht schon vorstellen damit was anzuleihern




Also

besten Dank schon mal für eure Beiträge


----------



## rs-plc-aa (18 November 2004)

Hallo,

ich hab beim Stöbern in der Biliothek unter der Rubrik "IEC Function Blocks" den FC25 und FC27 ausfindig gemacht.

Das wäre eine Möglichkeit zu ermittlung des größten bzw. kleinsten Wertes.

Man könnte diesen dann markieren und vom nächsten Durchlauf ausschließen, und weitersuchen...

Aber die Bausteine können leider immer nur drei werte miteinander vergleichen - wie praktisch.

Also gerade einen mehr als ich ohnehin auch so schon vergleichen kann...


Das müßte ja dann so K.O.-Systemmäßig ablaufen - oder?

Der Gewinner wird mit dem nächsten verglichen usw.


Aber ich hatte halt gedacht daß es auch einfacher gehen müßte.



Ich gebe die Hoffnung mal noch nicht auf...


----------



## Question_mark (18 November 2004)

Hallo rs-plc-aa, 


> Am schlimmsten stelle ich mir das zwischenspeichern vor, da ich keine Lösung mit 300 Merkern bevorzugen würde.


Muss glaube ich nicht unbedingt sein. Meine Idee dazu sieht so aus :
Betriebsstundenerfassung läuft für alle 7 möglichen Betriebsmittel zyklisch durch, ist also immer aktuell (glaube aber, dass eine Toleranz von +- 1 Stunde irrelevant ist, kann also durchaus auch in einem Zeit-OB erfolgen). Dann würde ich auswerten (Flanke steigend oder fallend der Eingänge), ob sich eine Anwahl der Betriebsmittel geändert hat. In dem Fall würde ich dann einen FCxxx aufrufen. Den FCxxx solltest Du erstellen und dem sollte als Parameter die Anzahl der angewählten Betriebsmittel übergeben werden. Im Baustein FCxxx wertest Du anhand des übergebenen Parameters anhand der z.B. in einem DB abgelegten Betriebsstunden das entsprechende Betriebsmittel aus und übergibst das als Rückgabewert. War jetzt mal aus der Hüfte geschossen, aber sowas wäre mein erster Denkansatz dazu (bestimmt auch nicht der letzte), es gibt immer noch bessere Lösungen.
Gruss
Question_mark


----------



## Question_mark (18 November 2004)

Hallo rs-plc-aa, 
also ungefähr so : 
im DB mit den Betriebsstunden steht z.B. folgendes : 
Betriebsmittel 1 = 50 h 
Betriebsmittel 2 = 450 h 
Betriebsmittel 3 = 40 h 
Betriebsmittel 4 = 120 h 
Betriebsmittel 5 = 200 h 
Betriebsmittel 6 = 80 h 
Betriebsmittel 7 = 20 h 

Zur Zeit sind z.B. 3 Betriebsmittel angewählt, also BM7, BM3 und BM1. 
Jetzt wird ein viertes BM dazugeschaltet, diese 4 gibt Du als Parameter dem FCxxx mit. In dem FCxxx wertest Du dann aus, welches BM den 4-niedrigsten Betriebsstundenzähler hat. Dieses Betriebsmittel dann als Rückgabewert im FCxxx ausgeben und dann im weiteren Programm entsprechend zuschalten (b.z.w. abschalten, je nach übergebenem Parameter). Das nur als Denkanstoss, weiter ausbauen, z.B. mit Verfügbarkeit des Betriebsmittels kannst Du ja dann selber machen.
Gruss 
Question_mark


----------



## Question_mark (18 November 2004)

Hallo rs-plc-aa,


> Hat hier vielleicht SCL eine Wunderlösung parat?


Naja, siehe oben, SCL ist für sowas noch nicht nötig. Mit SCL kann wirklich sehr komplexe Berechnungen in der SPS durchführen (die man früher wirklich auf externen Rechnern in Hochsprachen durchführen musste), aber bei Deinem Problem ist das absolut noch nicht nötig. Dieses Problem lässt sich durchaus in normalen STEP7 (z.B. AWL) lösen.
Gruss
Question_mark


----------



## Zottel (18 November 2004)

Zunächst sortierst du die Betriebsmittel nach den Betriebstunden. Dazu würde ich keinen der FCs verwenden, sondern eine einfache Vergleichsoperation, die zwei Operanden vergleicht. Um mit einem solchen Vergleich eine geordnete Liste zu erzeugen, gibt es viele Sortieralgorithmen. Diese unterscheiden sich in der Effizienz und Komplexität. Ferner unterscheiden sich Algorithmen, die eine völlig chaotische Menge gleich effizient sortieren, hinsichtlich der Effizienz bei teilweise geordneten Mengen. Die Effizient mißt man, indem man vergleicht, nach welcher Funktion die Ausführungszeit mit der Zahl der Elemente steigt. Schlecht ist n*n, gut ist log2 Llogarithmus zur Basis 2). Das alles interessiert erst bei mehr als einigen hundert Elementen wirklich.

Damit man bei langen Einträgen nicht die Datenmenge der Einträge selbst "umschaufeln" muß, verwendet man einen Index. Dieser kann aus Zeigern auf die Elemente bestehen oder aus Platznummern in einer ungeordneten Liste.

Einer der einfachsten Algorithmen heißt "Bubble sort", weil bei ihm das oberste Element in der Liste aufsteigt wie eine Blase.
Buble sort funktioniert so: Wenn Nummer1 kleiner ist als Nummer 2, tausche Nummer 1 mit Nummer 2, sonst mach nix. Wenn Nummer2 kleiner ist als Nummer 3, tausche Nummer 2 mit Nummer 3, sonst mach nix. So gehts weiter bis zum Ende der Liste. Am Ende der Liste steht nun das kleinste Element. Weil man das sicher Weiß, braucht de nächste Durchgang nur noch alle vorigen Elemente zu untersuchen. Mit jedem Durchgang wird es eins weniger. Wenn im letzten Durchgang nur noch 2 Elemente verglichen wurden, ist die Liste sortiert.

Realisierung:
Du hast nun z.B. eine Liste im DB2. Jeder Eintrag ist ein DWORD, daß die Betriebsstunden (Betriebszeit) enhält. Ein DB2 enthalte deinen "Index". Er enthält jeweils ein Byte mit der Platznummer des Betriebsmittels. 


```
L DB2.DBB0	//lade 1.Eintragsnummer aus Index
L 32			//Länge eines DWORDS in bits
*I			//ergibt Adresse des eigentlichen Elements
T LD0		//zwischenspeichern

L DB2.DBB1	//lade 2.Eintragsnummer aus Index
L 32			//Länge eines DWORDS in bits
*I			//ergibt Adresse des eigentlichen Elements
T LD4		//zwischenspeichern

L DB1.DBD[LD0]	//Lade Betriebsstunden des 1. Betriebsmittels
L DB1.DBD[LD4]	//Lade Betriebsstunden des 2. Betriebsmittels
>D
SPB nixtun		//wenn das 1.größer ist, ist nichts zu tun, sonst wird jetzt getauscht:
L DB2.DBB0		//lade 1.Eintragsnummer aus Index
T LB0			// zwischenspeicher für Ringtausch
L DB2.DBB1		//lade 2.Eintragsnummer aus Index
T DB2.DBB0		//speicher als neue 1.Eintragsnummer aus Index
L LB0			//Hole Zwischenspeicher zurück
T DB2.DBB1		//speicher als neue 2.Eintragsnummer aus Index
nixtun: NOP
```
Diesen Code kannst du nun aneinanderhängen :

```
L DB2.DBB1	//lade 2.Eintragsnummer aus Index
L 32			//Länge eines DWORDS in bits
*I			//ergibt Adresse des eigentlichen Elements
T LD0		//zwischenspeichern

L DB2.DBB2	//lade 3.Eintragsnummer aus Index
L 32			//Länge eines DWORDS in bits
*I			//ergibt Adresse des eigentlichen Elements
T LD4		//zwischenspeichern

L DB1.DBD[LD0]	//Lade Betriebsstunden des 2. Betriebsmittels
L DB1.DBD[LD4]	//Lade Betriebsstunden des 3. Betriebsmittels
>D
SPB nixtun2		//wenn das 1.größer ist, ist nichts zu tun, sonst wird jetzt getauscht:
L DB2.DBB1		//lade 1.Eintragsnummer aus Index
T LB0			// zwischenspeicher für Ringtausch
L DB2.DBB2		//lade 2.Eintragsnummer aus Index
T DB2.DBB1		//speicher als neue 1.Eintragsnummer aus Index
L LB0			//Hole Zwischenspeicher zurück
T DB2.DBB2		//speicher als neue 2.Eintragsnummer aus Index
nixtun2: NOP
```
Du mußt du ihn sinngemäß für Eintrag 1-7,1-6,1-5,1-4,1-3,1-2 ausführen. Das wären  27 der oben gezeigten Code-Blöcke mit angepassten Indexnummern (für 7 Elemente kann man das wohl so machen). 

Du kannst den Code abkürzen, indem du ihn in zwei Schleifen packst: Die äußere Schleife zählt die Durchgänge. Die innere Schleife zählt die zu vergleichenden Elemente. Sie hat mit jedem Durchgang der äußeren ein Element weniger.

Am Ende enthält dein Index in DB2 eine Liste der Art
5
4
2
3
6
7
1
Das bedeutet, daß die Betriebsstunden des 5. Elementes am geringsten sind, nächst-geringer die des 4. und 2. Du kanst statt des Eintrags der reinen Zeit im DB1 auch einen UDT verwenden, der z.B. zusätzliche einen Zeiger auf den einzuschaltenden Ausgang enthält.

Wann immer sich die Betriebstunden signifikant verändern, mußt du das sortieren der Liste wiederholen. Signifikant heißt: Wenn es dir nur auf Betriebsstunden ankommt, reicht es ja die Liste alle Stunde neu zu sortieren. Wenn das Betriebsmittel nicht gewechselt wird, nur weil es eine Minute oder Sekunde mehr auf dem Buckel hat als ein anderes, brauchst du die Liste auch nur dann zu sortieren, wenn sich die Kombination der Eingänge ändert.

[/code]


----------



## rs-plc-aa (18 November 2004)

@Zottel: das Sortieren war meine Hauptsorge - aber bei derartiger Unterstützung ...


Zunächst wollte ich mich erst mal bedanken.

Das muß ich erst mal durchstudieren....

.... aber gefällt mir gut.


----------



## rs-plc-aa (22 November 2004)

Hallo,

ich hatte leider nicht die Zeit gehabt am WE mich darauf zu stürzen wie ich es eigentlich vorhatte...

Ich hab´s mir nun aber noch mal durchgesehen.

@Zottel:Meinst du in deiner Beschreibung
>> Zitat:

Du hast nun z.B. eine Liste im *DB2.* Jeder Eintrag ist ein DWORD, daß die Betriebsstunden (Betriebszeit) enhält. Ein DB2 enthalte deinen "Index". Er enthält jeweils ein Byte mit der Platznummer des Betriebsmittels. 

>> Ende Zitat...

mit DB 2 eigentlich DB1 ?

Laut dem Code müsste das so sein.


Ich hänge eigentlich nur noch ein wenig an dem Index fest...


----------



## Zottel (22 November 2004)

Ja, ich meinte, daß die Einträge in DB1 stehen. 
Man muß auch nicht zwigend einen Index verwenden, aber wenn du in der Liste nur die Betriebsstunden hast, hast du nach dem Sortieren halt nur eine geordnete Liste von Betriebsstunden und weißt nicht mehr, zu welchem Betriebsmittel si gehören. Das kann man auch mit einem UDT lösen, der die Nummer des BM enthält, aber mit Index kopierst du nur sowenige Bytes wie wirklich nötig.


----------



## rs-plc-aa (22 November 2004)

Hallo,

das mit dem Index ist schon o.k. - will ich auch so machen.

Ich habe jetzt einen Global-DB (DB 20) angelegt für die Indexierung, und einen Global-DB für die Stunden (DB 10) - (ich kopiere die Stunden in den DB, die ich über Profibus von den BM´s erhalte).


Die reihenfolge des Stunden DB´s (DB10) bleibt ja unverändert.

Die Default-Reihenfolge der Index-Bytes ist ja 1,2,3,4...., und wird durch die Vergleiche getauscht.

So weit kann ich folgen.


Jetzt haben wir ja irgendwann im Index-DB eine Reihenfolge die sortiert ist.

Aber das erste Byte trägt doch immer noch die selbe bezeichnung wie vorher - oder ?


Ich versteh also nicht ganz wie ich das anschließend zuordnen soll...

Sorry - aber ich hab was derartiges noch nicht gemacht.


----------



## Zottel (22 November 2004)

Zitiere mal mich selbst:


> Am Ende enthält dein Index in DB2 eine Liste der Art
> 5
> 4
> 2
> ...


Bzw. bei dir im DB 20.
Dies bedeutet, daß der 5. Eintrag in der (unsortierten) Liste im DB10 der kleinste (größte?, das hängt davon ab, ob du beim Sortieren auf größer oder kleiner vergleichst.) ist, der 4. Eintrag der zweitkleinste, der 2. der drittkleinste. 
Du schaltest also die Betriebsmittel 5,4, und 2 ein, weil sie noch am wenigsten gelaufen haben.
[/quote]


----------



## rs-plc-aa (22 November 2004)

Hallo,

das habe ich schon gelesen - nur stehe ich wahrscheinlich auf dem Schlauch...

Hier mal zunächst das was im FB passiert...


```
// Bubble Sort



      L     DB20.DBB    0               //lade 1.Eintragsnummer aus Index 
      L     32                          //Länge eines DWORDS in bits 
      *I                                //ergibt Adresse des eigentlichen Elements 
      T     LD     0                    //zwischenspeichern 

      L     DB20.DBB    1               //lade 2.Eintragsnummer aus Index 
      L     32                          //Länge eines DWORDS in bits 
      *I                                //ergibt Adresse des eigentlichen Elements 
      T     LD     4                    //zwischenspeichern 

      L     DB10.DBD    0               //Lade Betriebsstunden des 1. Betriebsmittels 
      L     DB10.DBD    4               //Lade Betriebsstunden des 2. Betriebsmittels 
      >D    
      SPB   nix1                        //wenn das 1.größer ist, ist nichts zu tun, sonst wird jetzt getauscht: 

      L     DB20.DBB    0               //lade 1.Eintragsnummer aus Index 
      T     LB     0                    // zwischenspeicher für Ringtausch 
      L     DB20.DBB    1               //lade 2.Eintragsnummer aus Index 
      T     DB20.DBB    0               //speicher als neue 1.Eintragsnummer aus Index 
      L     LB     0                    //Hole Zwischenspeicher zurück 
      T     DB20.DBB    1               //speicher als neue 2.Eintragsnummer aus Index 

nix1: NOP   0

      L     DB20.DBB    1               //lade 2.Eintragsnummer aus Index 
      L     32                          //Länge eines DWORDS in bits 
      *I                                //ergibt Adresse des eigentlichen Elements 
      T     LD     0                    //zwischenspeichern 

      L     DB20.DBB    2               //lade 3.Eintragsnummer aus Index 
      L     32                          //Länge eines DWORDS in bits 
      *I                                //ergibt Adresse des eigentlichen Elements 
      T     LD     4                    //zwischenspeichern 

      L     DB10.DBD    4               //Lade Betriebsstunden des 2. Betriebsmittels 
      L     DB10.DBD    8               //Lade Betriebsstunden des 3. Betriebsmittels 
      >D    

      SPB   nix2                        //wenn das 2.größer ist, ist nichts zu tun, sonst wird jetzt getauscht: 

      L     DB20.DBB    1               //lade 2.Eintragsnummer aus Index 
      T     LB     0                    // zwischenspeicher für Ringtausch 
      L     DB20.DBB    2               //lade 3.Eintragsnummer aus Index 
      T     DB20.DBB    1               //speicher als neue 2.Eintragsnummer aus Index 
      L     LB     0                    //Hole Zwischenspeicher zurück 
      T     DB20.DBB    2               //speicher als neue 3.Eintragsnummer aus Index 

nix2: NOP   0

      L     DB20.DBB    2               //lade 3.Eintragsnummer aus Index 
      L     32                          //Länge eines DWORDS in bits 
      *I                                //ergibt Adresse des eigentlichen Elements 
      T     LD     0                    //zwischenspeichern 

      L     DB20.DBB    3               //lade 4.Eintragsnummer aus Index 
      L     32                          //Länge eines DWORDS in bits 
      *I                                //ergibt Adresse des eigentlichen Elements 
      T     LD     4                    //zwischenspeichern 

      L     DB10.DBD    8               //Lade Betriebsstunden des 3. Betriebsmittels 
      L     DB10.DBD   12               //Lade Betriebsstunden des 4. Betriebsmittels 
      >D    

      SPB   nix3                        //wenn das 3.größer ist, ist nichts zu tun, sonst wird jetzt getauscht: 

      L     DB20.DBB    2               //lade 3.Eintragsnummer aus Index 
      T     LB     0                    // zwischenspeicher für Ringtausch 
      L     DB20.DBB    3               //lade 4.Eintragsnummer aus Index 
      T     DB20.DBB    2               //speicher als neue 3.Eintragsnummer aus Index 
      L     LB     0                    //Hole Zwischenspeicher zurück 
      T     DB20.DBB    3               //speicher als neue 4.Eintragsnummer aus Index 

nix3: NOP   0

      L     DB20.DBB    3
      L     32
      *I    
      T     LD     0

      L     DB20.DBB    4
      L     32
      *I    
      T     LD     4

      L     DB10.DBD   12
      L     DB10.DBD   16
      >D    

      SPB   nix4

      L     DB20.DBB    3
      T     LB     0
      L     DB20.DBB    4
      T     DB20.DBB    3
      L     LB     0
      T     DB20.DBB    4

nix4: NOP   0

      L     DB20.DBB    4
      L     32
      *I    
      T     LD     0

      L     DB20.DBB    5
      L     32
      *I    
      T     LD     4

      L     DB10.DBD   16
      L     DB10.DBD   20
      >D    

      SPB   nix5

      L     DB20.DBB    4
      T     LB     0
      L     DB20.DBB    5
      T     DB20.DBB    4
      L     LB     0
      T     DB20.DBB    5

nix5: NOP   0

      L     DB20.DBB    5
      L     32
      *I    
      T     LD     0

      L     DB20.DBB    6
      L     32
      *I    
      T     LD     4

      L     DB10.DBD   20
      L     DB10.DBD   24
      >D    

      SPB   nix6

      L     DB20.DBB    5
      T     LB     0
      L     DB20.DBB    6
      T     DB20.DBB    5
      L     LB     0
      T     DB20.DBB    6

nix6: NOP   0
```


Nun sieht ja mein Stunden-DB etwa so aus:

Stunden_M1         DWORD       DW#16#0
Stunden_M2         DWORD       ....


Und der Index-DB etwa so:

Index_M1          BYTE       B#16#0
Index_M2          BYTE       B#16#0
Index_M3          BYTE       ....


___________________________________________


Getauscht werden ja die Indexes

Aber wird da nicht nur der Wert getauscht ?

Bleibt da nicht die Reihenfolge M1,M2,M3,M4.....


Kann es sein das ich da was nicht blicke ?


Mir geht einfach nicht runter wie ich nachher erkennen soll welches Betriebsmittel welchem Byte zugeordnet ist (aber bitte nicht auslachen - und wenn dann heimlich...  :roll: )


----------



## Zottel (22 November 2004)

rs-plc-aa schrieb:
			
		

> ...
> Und der Index-DB etwa so:
> 
> Index_M1          BYTE       B#16#0
> ...



Ein sinnvoller Anfangswert für den Index-DB ist:
Index_M1          BYTE       B#16#1
Index_M2          BYTE       B#16#2
Index_M3          BYTE       B#16#3
Index_M4          BYTE       B#16#4
Index_M5          BYTE       B#16#5
Index_M6          BYTE       B#16#6
Index_M7          BYTE       B#16#7

Zwei Dinge noch:
Dein "Bubblesort" FB hat nur 6 Durchgänge (wenn ich richtig gezählt habe). Nötig sind aber 27!
Beim Index habe ich was falsch gemacht: Der 1. Eintrag im Betriebsstunden DB hat den Array-Index 0. 
Ein wirklich sinnvoller Anfangswert für den Index-DB ist:
Index_M1          BYTE       B#16#0
Index_M2          BYTE       B#16#1
Index_M3          BYTE       B#16#2
Index_M4          BYTE       B#16#3
Index_M5          BYTE       B#16#4
Index_M6          BYTE       B#16#5
Index_M7          BYTE       B#16#6


----------



## rs-plc-aa (22 November 2004)

Hallo,

jetzt habe ich auch mal das:

http://liebknecht-gymnasium.bei.t-online.de/sort/html-Seiten/Bubblesort.html

gelesen (mal ganz runterscrollen und den link "graphische Darstellung" anklicken - echt gut gemacht)

Bei den Durchläufen zähle ich bei meinen 7 Variablen aber nur 21.


Jetzt ich nix mehr wissen...


----------



## Zottel (22 November 2004)

rs-plc-aa schrieb:
			
		

> Hallo,
> Bei den Durchläufen zähle ich bei meinen 7 Variablen aber nur 21.


Sorry, 21 ist richtig, da 7 Variablen 6 Vergleiche erfordern. Habe (n*n+n)/2 gerechnet, richtig ist aber (n*n-n)/2


----------



## rs-plc-aa (22 November 2004)

Hallo,

alles klar...

Hat jemand den Link schon besucht?



Jetzt muß ich aber noch mal mit dem Index nerven.


Wenn die Sortierung fertig ist dann sind ja die Bytes, die vorher aufsteigend im DB nummeriert waren - also von 1 bis 7 und der Wert von 0 bis 6 - nun, wenn wir mal davon ausgehen daß sich nach der Sortierung eine veränderte Reihenfolge ergibt, von der Benennung ( also M1 - M7) her immer noch gleich - da dies ja an die Bausteinadresse geklammert ist.

Es ändert sich also nur der Wert - z.B.:

M1 = 5
M2 = 3
M3 = 0
M4 = 6
...


Wenn das bis hierher stimmt, dann muß ja jetzt noch von Hand oder halt eben extra noch bestimmt werden Welche BM-Nummer auch am wenigsten, am zweitwenigsten, ... usw. Stunden hat...


oder ist dies schon erledigt und ich habe immer noch nicht bemerkt wo ?


----------



## Zottel (23 November 2004)

Wenn ich da geschrieben habe:
L DB20.DBD[DB10.DBB0] oder so ähnlich: Das kann die S7 gar nicht, aber es ist ein Pseudo-Code, mit dem sich der Algorithmus übersichtlich darstellen läßt. Und Anweisungen dieser Art sind in allen höheren Computersprachen Gang un Gäbe.
Es fiel mir dann später auf, daß du in einem folgenden Posting richtigen S7-Code hineingestellt hast, der keinerlei indirekte Adressierung enthält...

Der Witz an indirekter Adressierung ist, daß nicht immer mit derselben Variable gearbeitet wird, sondern mit derjenigen, deren Positionsnummer (array index) oder Adresse (pointer) in einer anderen Variablen steht.
 Ich werde mal im Laufe von morgen Code für Bubblesort mit real existierenden S7-Befehlen posten. Er wird weniger übersichtlich aussehen.

Zuletzt wirst du noch folgendes tun müssen:
Du hast im DB10 eine Liste mit den Betriebsmitteln in absteigender Reihenfolge der Stunden.
Zunächst ermittelst du wieviele eingeschaltet werden sollen:
L 0
T MW2	//Zahl der BM, Annahme 0
UN E0.0 	//keine Anforderung da?
SPB N1
LMW2
L1 
+I
TMW2
N1: NOP 0
UN E0.1 	//keine Anforderung da?
SPB N2
LMW2
L1 
+I
TMW2
N2: NOP 0
...
Am Ende steht in MW2 die Zahl der einzuschaltenden Betriebsmittel.

nun kommt: 
Wenn mindestens 7 Betriebsmittel gefordert, alle einschalten
Wenn mindestens 6 Betriebsmittel gefordert, die Nummern 1-6 der Indexliste einschalten 
Wenn mindestens 5 Betriebsmittel gefordert, die Nummern 1-5 der Indexliste einschalten
...
Wenn mindestens 1 Betriebsmittel gefordert, die Nummer 1 der Indexliste einschalten


----------



## rs-plc-aa (23 November 2004)

Hallo,

super  :!:  danke bis jetzt...

Ich bin noch ein relativer Neuling, und habe wenig bis gar keine Erfahrung mit Arrays oder Pointern - umso interessanter lausche ich weiter.


Ich habe den Code mal geändert - jetzt fange ich als eröffnung mit:

7>6 ? - wenn ja machnix
6>5 ? - ...

2>1 ? - ...

macht 6 Vergleiche im ersten durchgang...

im zweiten lasse ich den letzten weg - usw.


Damit komme ich auf die 21.

Der letzte Durchgang wäre dann:

7>6 ? - wenn ja machnix.


Ich hoffe das passt  :?: 

So hätte ich dann den kleinsten oben usw. - wie ich ja will.


Jetzt muß ich die festen Adressen nur noch gegen die entsprechenden Variablen austauschen.


@Zottel:

Da warte ich aber noch auf deinen Vorschlag...




Ich für meinen Teil fahre jetzt los nach Nürnberg - ihr könnt euch wahrscheinlich denken wohin...



Also an alle die auch da sind:


Viel Erfolg bei den Verhandlungen, viel Spaß und alles was dazugehört.


----------



## Zottel (23 November 2004)

Ok, hier meine Lösung zum Bublesort mit S7:

```
//FC16
// Parameter
laenge  INT  Laenge der Liste -1 
indexDB  INT  Nummer des Datenbausteins, der den Index enthält 
datenDB  INT  Nummer des Datenbausteins, der die Daten enthält 
datenLaenge INT  Länge eines Daten-Elements 
AUF_AB  BOOL  Sortierrichtung 
INIT_INDEX BOOL  Index inititialisieren 
//
// lokale Variablen:
//
i WORD  //Schleifenzaehler der äußeren Schleife 
j WORD  Schleifenzaehler der inneren Schleife 
idx1 DINT  Adresse des 1.Index-Elementes 
idx2 DINT  Adresse des 2. Index-Elementes 
iw1 WORD  Wert des ersten Index-Elementes 
iw2 WORD  Wert des 2. Index-Elementes 
dix1 DINT  Adresse des 1.Daten-Elementes 
dix2 DINT  Adresse des 2.Daten-Elementes 
DDBN WORD   
IDBN WORD   
VerglErg BOOL   
//
// Parameter umladen, weil AUF DB[x] nicht mit Parametern funktioniert:
//
      L     #indexDB 
      T     #IDBN
      L     #datenDB
      T     #DDBN
//
// Index initialisieren, wenn gewünscht.
//
      UN    #INIT_INDEX
      SPB   M005
      L     #laenge
      T     #i
      AUF   DB [#IDBN]
M004: NOP   0
      L     #i
      L     8 // 8 Bit pro Eintrag im Index
      *D    
      T     #idx1
      L     #i
      T     DBB [#idx1]
      L     1
      -I    
      T     #i
      SPPZ M004
 
M005: NOP   0

// die nächsten 8 Zeilen sind nur zum Beobachten:
      AUF   DB [#IDBN]
      L     DBB    0
      L     DBB    1
      L     DBB    2
      L     DBB    3
      L     DBB    4
      L     DBB    5
      L     DBB    6


      L     #laenge
      T     #i

M003: L     #laenge
      L     #i
      -I    
      L     1
      +I    
      T     #j

M002: NOP   0
      AUF   DB [#IDBN]
      L     #j
      L     8
      *D    
      T     #idx1
      L     DBB [#idx1]
      T     #iw1

      L     #idx1
      L     8                           //Länge eines Indexelements in Bit
      -D    
      T     #idx2                       //Index des letzten Elements
      L     DBB [#idx2]
      T     #iw2                        //Index des letzten Elements

      L     #iw1
      L     #datenLaenge
      *D    
      T     #dix1

      L     #iw2
      L     #datenLaenge
      *D    
      T     #dix2

      AUF   DB [#DDBN]

      L     DBD [#dix1]
      L     DBD [#dix2]
      >D    
      =     #VerglErg
      U     #VerglErg
      U     #AUF_AB
      O(    
      UN    #VerglErg
      UN    #AUF_AB
      )     
      SPB   m001
      AUF   DB    10
```
// das muss  auch AUF   DB [#IDBN] werden! Sonst klpppt's nicht mit anderen DB-Nummern als 10.
Leider geht das rot nicht innerhalb von code. Der folgende Code gehört noch zu FC16:

```
L     #iw1
      T     DBB [#idx2]
      L     #iw2
      T     DBB [#idx1]
m001: NOP   0
      L     #j
      L     1
      -I    
      T     #j
      T     MB    22
      SPP   M002
      L     #i
      L     1
      -I    
      T     #i
      T     MB    23
      SPP   M003
      L     MB    22
      T     MW     0
// die nächsten 8 Zeilen sind nur zum Beobachten:
      AUF   DB [#IDBN]
      L     DBB    0
      L     DBB    1
      L     DBB    2
      L     DBB    3
      L     DBB    4
      L     DBB    5
      L     DBB    6
      BE
```
//
// OB1 zum Testen des FC16:
//

```
CALL  FC    16
       laenge     :=6
       indexDB    :=10
       datenDB    :=20
       datenLaenge:=32
       AUF_AB     :=FALSE
       INIT_INDEX :=TRUE
      L     DB10.DBB    0
      L     DB10.DBB    1
      L     DB10.DBB    2
      L     DB10.DBB    3
      L     DB10.DBB    4
      L     DB10.DBB    5
      L     DB10.DBB    6

      CALL  FC    16
       laenge     :=6
       indexDB    :=10
       datenDB    :=20
       datenLaenge:=32
       AUF_AB     :=TRUE
       INIT_INDEX :=TRUE
      L     DB10.DBB    0
      L     DB10.DBB    1
      L     DB10.DBB    2
      L     DB10.DBB    3
      L     DB10.DBB    4
      L     DB10.DBB    5
      L     DB10.DBB    6
      BE
```


----------



## rs-plc-aa (23 November 2004)

Hallo,

bin wieder von der Messe zurück.


@Zottel:

Die lokalen Variablen kenne ich bei FC´s nicht - nur bei FB´s unter "STAT" (Instanz-DB).

Oder meinst du damit die "Temp" bei der FC ?


----------



## Zottel (24 November 2004)

rs-plc-aa schrieb:
			
		

> Die lokalen Variablen kenne ich bei FC´s nicht - nur bei FB´s unter "STAT" (Instanz-DB).
> 
> Oder meinst du damit die "Temp" bei der FC ?


Genau die. Heißen sie bei Siemens sonst anders?
Außerdem enthält mein Code noch ein paar T MB 22, TMB 23, TMW0, die nur zur Kontrolle drin waren, weil ich nicht sicher war, welchen Schleifendurchlauf ich beimBeobacten sehe. Kannst du rausschmeißen.


----------



## rs-plc-aa (24 November 2004)

Hallo,

@ Zottel:

genau die "Stat" --> also FB   oder

genau die "Temp" --> also FC ??


----------



## Zottel (24 November 2004)

TEMP, es ist ein FC.


----------



## rs-plc-aa (25 November 2004)

Hallo,


@ Zottel:


Ich habe nun die FC erstellt, kriege sie aber nicht ans laufen (Übersetzen ist aber fehlerfrei).

Desweiteren habe ich nicht erkennen können wie der Rückgabewert auszuwerten ist.

Könntest du hierzu freundlicherweise vielleicht noch ein paar Zeilen schreiben ?


----------



## Zottel (25 November 2004)

> Ich habe nun die FC erstellt, kriege sie aber nicht ans laufen (Übersetzen ist aber fehlerfrei).


Was heißt das, nicht laufen? geht die SPS in Stop?

Sie erwartet, daß es einen DB20 gibt, der 7 DBD mit den Betriebsstunden beginnend mit DBD0 enthält. Ferner braucht es einen DB10, der mindestens sieben DBBs enthält. Mit INIT_INDEX=TRUE werden diese mit 0,1,2,3,4,5,6 beschrieben.


> Desweiteren habe ich nicht erkennen können wie der Rückgabewert auszuwerten ist.


Es gibt keinen Rückgabewert. Nach dem Aufruf des FC liegen im DB10 die Zahlen 0-6 in einer solchen Reihenfolge, daß sie die Rangfolge der Einträge im DB20 wiederspiegeln.


----------



## rs-plc-aa (25 November 2004)

Hallo,

@Zottel:

Ja - die CPU geht in Stop. (OB1 beim Versuch die FC 16 zu starten...)


Die DB´s sind vorhanden - auch der Inhalt passt.


Ich versuche es gleich noch mal, vielleicht kann ich noch was detaillierteres rausfinden...


----------



## rs-plc-aa (25 November 2004)

Hallo,

@Zottel:

an dieser Stelle bleibt er stehen:

      L     DBD [#dix2]


Der Diagnosepuffer sagt:

Ereignis 2 von 13:  Ereignis-ID 16# 4562
STOP durch  Programmierfehler (OB nicht geladen oder nicht möglich, bzw. kein FRB vorhanden ) 
Unterbrechungstelle im Anwenderprogramm:  Zyklisches Programm (OB 1)  
Prioritätsklasse:    1
FC-Nummer:    16
Bausteinadresse:    218 
Bisheriger Betriebszustand: RUN
Angeforderter Betriebszustand: STOP (intern)
interner Fehler, kommendes Ereignis
15:51:26:616   25.11.04


Ereignis 3 von 13:  Ereignis-ID 16# 2522
Bereichslängenfehler beim Lesen 
Global -DB, Doppelwortzugriff,  Zugriffsadresse:      8
FC-Nummer:    16
Bausteinadresse:    218
Angeforderter OB: Programmierfehler-OB (OB 121)
Prioritätsklasse:  1
interner Fehler, kommendes Ereignis
15:51:26:616   25.11.04


...


Bereichslängenfehler beim Lesen ?


----------



## Zottel (25 November 2004)

So, ich habe meine Code noch einmal angesehen. Einen Fehler habe ich korrigiert. Er stört aber nur, wenn du als indexDB eine andere Nummer als 10 angibst.
Ansonsten solltest du kontrollieren:
1. Wird die Zykluszeit ueberschritten?
2. Gibst du beim Aufruf des FC16 im OB1 andere Parameter an, als ich gepostet habe?
3. Im FC16, beginnend mit der letzten, mal die Rücksprungbefehle (SPP Mxxx) auskommentieren. Der Baustein sortiert dann natürlich nicht mehr vollständig! Aber vielleicht läuft er durch.
Falls das "hilft", welche Rücksprünge bringen die CPU zum Absturz?

Nebenbei: Welche CPU  nutzt du?


----------



## rs-plc-aa (25 November 2004)

Hallo,

unser Posting war wohl nur paar Sekunden auseinander...


----------



## Zottel (25 November 2004)

rs-plc-aa schrieb:
			
		

> Bausteinadresse:    218


Kan ich nichts mit anfangen, habe keine CPU hier.


> L     DBD [#dix2]


Schon besser. Welchen Wert hat #dix2 zu diesem Zeitpunkt?
Zulässige Werte sind 0 - 6*32 in Schritten von 32.


----------



## Zottel (25 November 2004)

Wie hast du den Baustein übernommen? Copy& paste? oder abgetippt?

wenn im folgenden AUF -Befehl #IDBN stat #DDBN stünde, sollte das genau den Fehler geben:


```
AUF   DB [#DDBN] 
 
       L     DBD [#dix1] 
       L     DBD [#dix2] 
       >D
```
[/code]


----------



## Zottel (25 November 2004)

Hier für alle Fälle noch mal das mit Step7 archivierte Projekt:


----------



## rs-plc-aa (25 November 2004)

Hallo,

ich habe mich vorgetastet und habe auf "Zyklusweise" umgestellt.

Der erste Zyklus (OB100) geht - weil leer, der erste OB1 Zyklus steht sofort.

Ich habe einen Screenshot angefertigt.

Der Pfeil zeigt auf eine Multiplikation die fehlschlägt.


----------



## rs-plc-aa (25 November 2004)

Hallo,

oh wie peinlich...

0 mal 32 gibt halt nur 0  :!:


----------



## Zottel (25 November 2004)

Und das ist in Ordnung. wenn dix2= 0 ist, meint DBD[dix2] das DBD0.
Wenn dix2= 32 ist, meint DBD[dix2] das DBD4 (32bit hinter dem Anfang von DBD0).
PS: Bitte keine doc-Dateien! Habe kein Microsoft!


----------



## rs-plc-aa (25 November 2004)

Hallo,

ok - schlag` mich...

Im Projekt von mir ist der Index DB20, und der Stunden DB10

--> also genau umgekehrt wie bei dir...

Irgendwie war das am Anfang mal so - na ja.


Soll heißen:

Das Projekt welches du gepostet hast läuft (wie bei dir ja auch...).


=============================================

So und nun habe ich einen Index DB mit einer sortierten Reihenfolge der Betriebsmittel.


Da mir diese Programmierweise nicht geläufig ist, frage ich nun (zwangsläufig) weiter...


Beispiel:

Es läuft im Moment kein BM.

Nun kommen 2 zeitgleiche Anforderungen.

Es sollen jetzt die 2 BM´s mit den wenigsten Stunden gestartet werden - sofern diese betriebsbereit sind.

wenn eines oder beide nicht betriebsbereit ist/sind soll automatisch das nächste genommen werden.


Betriebsbereitschaft:

- wenn keine Störung ansteht UND wenn der Schlüsselschalter auf "Automatik" steht.


Sollte die Überprüfung ob betriebsbereit besser nachher stattfinden ?


----------



## Zottel (25 November 2004)

Ich würde die Betiebsbereitschaft nachher testen.
Das ist jetzt kein getesteter Code, nur das Prinzip:

Du brauchst z.B. 2 Betriebsmittel.
Diese Information kopierts du in irgendeine Variable. Ich sag´ mal MB88.
Du gehtst die Liste in DB10 durch, beginnend mit 0. Wo du bist, merkst du dir z.B. in MB89.
Du liest aus DB10.DBB[0], daß das BM mit den wenigsten Stunden die Nummer 4 hat.
Du zählst MB89 hoch, da du auf jeden fall als nächste BM das mit nächstwenigeren Stunden einzuschalten versuchst.
Nun prüfst du die Betriebsbereitschaft von Nummer 4.
JA: Ist es bereit so schaltest du es ein und verringert MB88 um 1. Es ist nun 2-1=1. Du mußt noch 1 BM einschalten.
NEIN: Ist es NICHT bereit so schaltest du es nicht ein und läßt MB88 wie es ist. Es ist immer noch 2. Du mußt also noch 2 BM einschalten.

Du liest aus DB10[1], daß das BM mit den nächstwenigsten Stunden die Nummer 1 hat.
Du zählst MB89 hoch, da du auf jeden fall als nächstes BM das mit nächstwenigeren Stunden einzuschalten versuchst.
Nun prüfst du die Betriebsbereitschaft von Nummer 1.
Ist es bereit so schaltest du es ein und verringert MB88 um 1. 
Waren beide bereit, ist MB88 jetzt 0 und du bist fertig
Waren beide nicht bereit, ist MB88 immer noch 2 und es geht so weiter.

Hast du irgendwann eine 7 in MB89, so bist du hinter dem letzten Eintrag für ein BM. Du kannst die verbleibenden Anfordrungen nicht bedienen und löst eine Meldung oder einen Alarm aus, damit sich jemand darum kümmert.

Die gesamte Umsetzung dieser Sache läßt sich ohne indirekte Adressierung, Pointer oder Schleifen erledigen.


----------



## Zottel (25 November 2004)

rs-plc-aa schrieb:
			
		

> ...
> Im Projekt von mir ist der Index DB20, und der Stunden DB10


Ach ja: abgesehen von der nicht indizierten "AUF"-Anweisung, auf die ich hingewiesen habe, läuft der Code auch mit 10 oder sonstwas als Daten- und 20 (oder sonstwas) als Index-DB. Dazu sind die DB-Nummern als Parameter da.


----------



## Zottel (25 November 2004)

Zottel schrieb:
			
		

> Die gesamte Umsetzung dieser Sache läßt sich ohne indirekte Adressierung, Pointer oder Schleifen erledigen.


Auch das Sortieren wäre natürlich prinzipiell ohne das gegangen. Aber dann hättest du 21 ähnliche Codeblöcke mit verschiedenen Adressen. Und wenn du 9 statt 7 BMs hättest, müßtest du 15 weitere hinzufügen...
Sorry, habe die Knöpfe "edit" und "zitat" verwechselt.


----------



## rs-plc-aa (25 November 2004)

Hallo,

@Zottel:

Riesen Dankeschön erstmal.


Na klar wäre das auch mit vertauschten Nummern der DB´s gegangen - aber wenn die Nummer vertauscht ist und der Aufruf nicht sieht´s schon wieder anders aus... (sche** Copy&Paste).

Nun ist es für mich umso motivierender aus dem Vorschlag selbst den Code zu erzeugen.

Aber ganz ehrlich ... Das mit den Schleifen hätte ich allein nicht hinbekommen.



Ich melde mich wieder wenn ich ein Stück geschafft habe.


----------



## Zottel (26 November 2004)

rs-plc-aa schrieb:
			
		

> Aber ganz ehrlich ... Das mit den Schleifen hätte ich allein nicht hinbekommen.


Schleifen sind auch etwas ungewöhnlich und etwas gefährlich in SPS-Programmen: Wenn du die Anzahl der Elemente erhöhst, nimmt die Anzahl der Durchläufe der äußeren Schleife mit n zu, bei jedem Durchlauf der äußeren Schleife werden erst n, dann immer ein Durchlauf weniger der inneren Schleife ausgeführt. Insgesamt gibt es also n*(n-1)/2 oder (n*n-n)/2 Durchläufe. Für sehr große Zahlen spielt nur noch n*n eine Rolle: Bei 1 Million Einträgen in das Telefonbuch einer Metropole ist n*n 1Billion. Ein besserer Sortieralgorithmus wie Quicksort schafft das mit n*log2, also ca 100000*20 = 20 Millionen Durchläufen!
Irgendwo, vielleicht bei 50, vielleicht bei 500 Elementen geht die CPU in Stop wegen Zykluszeitüberschreitung.
Abhilfe für längere Listen, wenn nicht oft neu sortiert werden muß: Pro Zyklus nur einen Durchlauf der Schleife ausführen.


----------



## rs-plc-aa (28 November 2004)

Hallo,

so ganz auf anhieb komme ich irgendwie doch nicht weiter...

Ich dachte mir, daß ich für die Auswertungs- und Anforderungsfunktionen einen separaten FB erstelle.

Dieser stellt bis jetzt fest, wieviele BM´s momentan gefordert sind.

Die geschieht zyklisch, undzwar wird die Variable zuerst mit 0 überschrieben, und dann wieder neu ermittelt wieviele es diesmal sind (kann man bei den wenigen wohl so machen...).

Wenn diese Variable nun 0 ist liegt keine Anforderung vor.

Wenn sie aber einen Zyklus vorher >0 war ist mal anzunehmen daß irgendwas läuft was jetzt nicht mehr laufen soll. 

Also das Spiel umgekehrt...

Jetzt kommt aber hinzu daß das BM mit den meisten Stunden nicht unbedingt laufen muss (wenn z.B. nur eines kurze Zeit lief kann es ja sein, daß es immer noch das mit den wenigsten Stunden ist - oder daß welche nicht betriebsbereit waren etc. ....)


Wäre es da nicht besser zur Abwahl eine andere Vorgehensweise einzuschlagen ?

Z.B. man nimmt Bytes die in der Einschaltfolge mit der ermittelten BM-Nummer versorgt werden, und dann in umgekehrter Reihenfolge wieder ausgeschaltet werden.

Laut meiner Denkweise komme ich aber dann (und auch schon für die Anforderung) auf eine ganze menge Vergleichsoperationen auf == Gleichheit.

Weil ich ja so immer noch nicht konkret weiß welches BM sich hinter DB10.DBB0 verbirgt.

Beispiel:

DB10.DBB0 = 5 muß ja erst mal so lange verglichen werden bis das mit dem BM#5 übereinstimmt - oder nicht ?


Vielleicht mache ich mir jetzt ein wenig unnötig in die Hose - aber es war doch mal die Rede von einem Zeiger der gleich auf das jeweilige BM verweisen würde.


Das erschlägt dann zwar auch nicht das prüfen auf betriebsbereitschaft bzw. bei der Abwahl ob das betreffende überhaupt läuft - aber würde die Sache nicht noch mehr aufblasen.


Daß hier natürlich mit allen Eventualitäten berücksichtigt nicht mit 20 Zeilen auszukommen ist, ist ja schon klar, aber mich würde das mit dem Pointer auch generell interessieren - und weil´s halt gerade hier passen würde...


----------



## Zottel (29 November 2004)

Zottel schrieb:
			
		

> Ich würde die Betiebsbereitschaft nachher testen.
> Das ist jetzt kein getesteter Code, nur das Prinzip:
> 
> Du brauchst z.B. 2 Betriebsmittel.
> ...


Das nächste ist auch nicht getestet, aber eine konkrete Umsetzung:
Annahme : E1.0, E2.3, E3.4, E3.5, E4.1, E4.2, E6.3, E6.5, E6.6 fordern BMs an.
mit Absicht ungeordnet und mehr als du BMS hast...


```
L 0
UN E1.0
SPB =NB1
INC 1
NB1:UN E2.3
SPB =NB2
INC 1
NB2:UN E3.4
SPB =NB3
INC 1
NB3:UN E3.5
SPB =NB4
INC 1
NB4:UN E4.1
SPB =NB5
INC 1
NB5:UN E4.2
SPB =NB6
INC 1
NB6:UN E6.3
SPB =NB7
INC 1
NB7:UN E6.5
SPB =NB8
INC 1
NB8:UN E6.6
SPB =NB9
INC 1
T MB88
```



> Du gehtst die Liste in DB10 durch, beginnend mit 0. Wo du bist, merkst du dir z.B. in MB89.
> Du liest aus DB10.DBB[0], daß das BM mit den wenigsten Stunden die Nummer 4 hat.


L 0
T MB89
L 0
L MB88
SPZ NE			// Wenn keine BMs mehr gebraucht werden, nix tun
call fc17			// fc17 schaltet das nächste Betriebsmiitel ein
  nummer: MB89
  Anzahl: MB88	
L MB89
INC 1
T MB89	//nächste IndexNummer
L 0
L MB88
SPZ NE
call fc17			// fc17 schaltet das nächste Betriebsmiitel ein
  nummer: MB89
  Anzahl: MB88	
...
L MB89
INC 1
T MB89	//nächste IndexNummer
L 0
L MB89
SPZ NE
call fc17			// fc17 schaltet das nächste Betriebsmiitel ein
  nummer: MB89
  Anzahl: MB88	
NE: NOP0
[/code]
Öfter als 7 mal brauchst du das nicht machen, mehr BMs hast du ja nich...
Der FC17 macht die Vergleiche und das Folgende:


> Du zählst MB89 hoch, da du auf jeden fall als nächste BM das mit nächstwenigeren Stunden einzuschalten versuchst.
> Nun prüfst du die Betriebsbereitschaft von Nummer 4.
> JA: Ist es bereit so schaltest du es ein und verringert MB88 um 1. Es ist nun 2-1=1. Du mußt noch 1 BM einschalten.
> NEIN: Ist es NICHT bereit so schaltest du es nicht ein und läßt MB88 wie es ist. Es ist immer noch 2. Du mußt also noch 2 BM einschalten.




```
fc17 
in Nummer byte
inout Anzahl byte
A DB10
L #Nummer
L 8 // 8-bit-Einträge
*I
T LD0	// Temp index	
L DBB[LD0]
SPL  //Sprungverteiler, genaue Syntax aus Hilfe, es wird zu einer Marke 
// abhängig von der BM-Nummer gesprungen:
BM0,BM1;BM2,BM3,BM4,BM5,BM6

BM0:UN E14.0 // betriebsbereit BM0
BEB	// Ende, kann BM nicht einschalten
SET	//VKE 1
S A12.0	//einschalten
SPA END1	// Ende mit reduzierter Anzahl

BM1:UN E14.6 // betriebsbereit BM1
BEB	// Ende, kann BM nicht einschalten
S A22.1	//BM1 einschalten
SPA END1	// Ende mit reduzierter Anzahl

...

BM6:UN E15.6 // betriebsbereit BM6
BEB	// Ende, kann BM nicht einschalten
S  A34.6	//BM6 einschalten
SPA END1	// Ende mit reduzierter Anzahl
BEA			// fertig und Anzahl nicht verringern

END1:
L #Anzahl 
DEC 1
T #Anzahl
BE
```
Das Einschalten habe ich auf beliebige Ausgänge gelegt. Es gibt nur ein Einschalten durch den Setz-Befehl. Wie macht man nun die nicht gebrauchten BMs aus? Einfach vor dem Einschalten alle ausschalten! 

```
SET
R A 12.0
R A 22.1
...
R A34.6
```
Das muß vor dem Einschalten erfolgen. Da die geänderten Zustände der Ausgänge erst am Ende des Zyklus übertragen werden, besteht keine Gefahr, daß die Schütze "rappeln".


----------



## myozze (29 November 2004)

*bubblesort in st*

Hallo Siemensgeplagte,

wenn ich mir das so durchlese, weiss ich wieder, warum ich von AWL immer Knoten im Hirn kriege  :shock: . Hier bubblesort in ST:


PROGRAM bubblesort
VAR CONSTANT
[list:f88fb9d6a0]SORTMAX:INT:=6;
END_VAR
VAR

	i: INT;
	zw: INT;
	ok: BOOL;
	sort: ARRAY[0..SORTMAX] OF WORD;
END_VAR
WHILE NOT ok DO

    	ok:=TRUE;
    	FOR i:= 0 TO SORTMAX-1 DO
[list:f88fb9d6a0]     		IF (sort _ > sort [i + 1]) THEN
			[list:f88fb9d6a0]zw:= sort ;                  				sort := sort [i + 1];
			sort [i + 1]:= zw;
			ok:=FALSE;_
_                         	      	END_IF[/list:u:f88fb9d6a0]END_FOR[/list:u:f88fb9d6a0]END_WHILE
[/list:u:f88fb9d6a0]
Und das Schönste daran ist: Wenn ich jetzt mal 50 statt 7 Werte sortieren will, muß ich genau einen Wert (SORTMAX) ändern. Ich liebe ST   

Gruß
Andi_


----------



## Zottel (30 November 2004)

Ok, in ST sieht das wie in einer vernünftigen Programmiersprache aus. Eigentlich sieht es nach PASCAL aus... Habe aber kein ST-Werkzeug für S7 zur Verfügung und ich schätze, rs-plc-aa auch nicht... Eigentlich schade, daß Siemens beim Preis von Step7 ST nicht gleich mitliefert. 
Was mich noch interessieren würde, ist wie der mit ST generierte Baustein in AWL aussieht. Poste doch bitte.
Bei meinem Vorschlag sortierst du 50 Einträge, indem du beim FC16 den Längen-Parameter auf 49 setzt. Natürlich müssen die DBs dann auch so lang sein.


----------



## Oberchefe (30 November 2004)

Hallo rs-plc-aa, wenn ich Dich mal was Offtopic fragen darf, wo wohnst Du?


----------



## rs-plc-aa (30 November 2004)

Oberchefe schrieb:
			
		

> Hallo rs-plc-aa, wenn ich Dich mal was Offtopic fragen darf, wo wohnst Du?



>> Zu hause - und du ? <<


Hast du den Verdacht daß du mich kennst ?


----------



## rs-plc-aa (14 Dezember 2004)

Hallo,

zunächst mal will ich mich entschuldigen daß ich den Thread so kurz vor dem Ende veröden ließ...

Mir war es leider nicht möglich nur einen Handschlag daran weiter zu machen.


Einen riesen Dank will ich an Zottel aussprechen, der geduldig die Sache bis dahin mitgemacht hat.

============================================
@ Oberchefe:

Ich hoffe du bist nicht sauer wegen meiner "Gegenfrage" auf deine Frage...

Ich war irgendwie perplex, und konnte mir nicht richtig vorstellen was mein Wohnort jetzt damit zu tun haben soll...

============================================



Ich schrieb ja zu Anfangs daß ich diesen Baustein erst "demnächst" brauche...

Dieses "demnächst" wird wohl dieses Jahr eh nix mehr weswegen jetzt die ganze Zeit andere Dinge einfach Vorrang hatten...


Ich will aber den Thread auf jeden Fall wiederbeleben wenn es soweit ist.



Bis dahin...


----------



## rs-plc-aa (9 Februar 2005)

Hallo,

nun habe ich die Arbeit an dieser Aufgabe wieder aufgenommen...



Ich bin - glaube ich - auch schon ziemlich weit gekommen mit den bisher geposteten Ideeen (--> besonderer Dank an Zottel ! ) ...


Mein momentaner Stand sieht ungefähr so aus:


Die Sortierung selbst funktioniert ja bereits.

Im Index DB stehen nun in absteigender Reihenfolge die BM´s 

Die Auswertung ist quasi fertig - die Funktion die Einschaltet eigentlich auch ?? .


Hier wird ja eine Sprungleiste verwendet (was ja eigentlich eine super sache ist wenn man es mal kapiert hat...) - und genau hiermit habe ich noch ein Problem.


in dem Beispielcode von Zottel (FC 17) steht am Anfang folgendes:



```
AUF   DB 10
      L     #Nummer
      L     8                           // 8-bit-Einträge 
      *I    
      T     LD    12                    // Temp index    
      L     DBB [LD 12]

      SPL ...
```


Was ich dabei noch nicht verstanden habe ist warum #Nummer mit 8 multipliziert wird.


Ziel des Ganzen ist ja aus meiner Sicht daß anhand von der übergebenen Variable #Nummer die Sprungleiste angewiesen wird z.B. DBB 0 aus dem IndexDB zu selektieren.


Was ich dabei wieder gar nicht verstehe ist wie der Bezug von dem Byte im IndexDB zum realen BM hergestellt wird.


Wenn z.B. im IndexDB das BM 4 an erster Stelle steht ( DBB 0 ) und die Sprungleiste holt sich das DBB 0 aus dem Index DB --> woher soll sie nun wissen daß es das BM 4 ist für das der Ausgang geschaltet werden soll ???



Das ist eigentlich auch gerade meine einzige "Sorge" an dem ganzen...


Besten Dank schon mal für mein "Aha Erlebnis" auf das ich noch warte   ...


----------



## RMA (9 Februar 2005)

Das muss x8 multipliziert weil Pointers haben den Format Byte.Bit. D.h. wenn du Dein Offset eingibst wenn Du nichts weiteres machst, hast ein Offset in Bits. Es wurde vielleicht klarer aussehen wenn man stat

L Offset
L 8
*D
T LD0

einfach

L Offset
SLD 3 //shift Double Word Left 3 Bits
T LD0

aber im Prinzip ist es dasselbe, aber wenn Du den Fall Offset = 1 nimmst und Dich vorstellt wie der AKKU1 vorher und nachher aussieht, vielleicht verstehst Du es besser.


----------



## rs-plc-aa (9 Februar 2005)

Hallo,

wieso Pointer ?

... vielleicht ist es das was ich daran nicht verstehe.

Ich dachte die Variable #Nummer gibt an welches DBB im IndexDB ausgewählt werden soll.

Und genau hierbei verstehe ich dann nicht wie die IndexDB Adresse (DBB) mit dem momentanen Wert des DBB´s (BM) verknüpft werden soll.


Das muß mir bitte jemand noch ein wenig genauer erklären.


----------



## RMA (9 Februar 2005)

> Ich dachte die Variable #Nummer gibt an welches DBB im IndexDB ausgewählt werden soll.



Ja und deswegen ist dieser Variable ein "Pointer" - Englisch für Zeiger, weil der Variable "zeigt" wo Deine Daten zu finden sind. Dies nennt man indirekte Adressierung.

Du findest einiges darüber hier.


----------



## rs-plc-aa (9 Februar 2005)

Hallo,

danke.

Ich habe mal eine Weile geschmökert bei Siemens.

Aber meine eigentliche Frage:



			
				rs-plc-aa schrieb:
			
		

> Und genau hierbei verstehe ich dann nicht wie die IndexDB Adresse (DBB) mit dem momentanen Wert des DBB´s (BM) verknüpft werden soll.



kann ich nun immer noch nicht beantworten.


Ich denke wenn ich das verstanden habe, verstehe ich den Rest auch viel besser (vielleicht hänge ich mich auch deswegen zu sehr daran auf...) .


Also noch mal ganz präzise gefragt:

Beispiel --> Es soll nur ein BM eingeschaltet werden.


Dann wären die Variablen #Nummer = 0 und  #Anzahl = 1 ... vor dem Aufruf der FC17.


In der FC 17 wird dann bei der Sprungleiste festgestellt daß das BM das im IndexDB an der Adresse DBB0 liegt eingeschaltet werden soll (wir gehen mal davon aus es ist betriebsbereit...)

Wenn jetzt aber #Nummer = 0 ist wird ja an der Sprungleiste der SPA nach BM0 ausgeführt - richtig ?

Und genau dann komme ich doch beim BM0 und nirgends wo anders heraus - oder ?

Und da bin ich der meinung daß das falsch ist --> denn nach der Sortierung kann ja beispielsweise auch das BM4 als DBB0 da stehen - oder habe ich schon weiter vorne was nicht verstanden ?

Somit sollte ja auch das BM4 (weil es in dem Fall dann die wenigsten Stunden auf dem Buckel hat) als einzigstes eingeschaltet werden.


Und eben diese Erkennung welche "echte" BM - Nummer sich hinter der IndexDB Adresse verbirgt fehlt doch oder ?



So zumindest habe ich das bis jetzt verstanden.


----------



## Zottel (9 Februar 2005)

Wenn Du im Daten DB folgende Zeiten hast:

45 Stunden
20 Stunden
46 Stunden
34Stunden

heißt das, daß dein 1.Betriebsmittel 45 Stunden, dein 2. BM 20, dein 3.BM 46 und das 4.BM 34 Stunden auf dem Buckel hat. Eine Zeile im Daten DB gehört unabänderlich zu einem BM.

Nicht so im Index-DB. Der wird initialisiert mit:
0
1
2
3

Nach Sortieren steht aber drin:
1
3
0
2

Es wird die 1 aus dem 1.Wort des Index-DB geladen. Der Sprungverteiler springt zur 2.Marke. Dort wird das 2. BM eingeschaltet (weil du dessen Ausgang hinter dieser Marke ansteuerst). Das 2. BM ist das mit den wenigsten Stunden.

Soll nun noch ein BM eingeschaltet werden, so wird die 3 aus dem 2.Wort des Index-DB geladen. Der Sprungverteiler springt zur 3.Marke. Dort wird das 3. BM eingeschaltet (weil du dessen Ausgang hinter dieser Marke ansteuerst). Das 3. BM ist das mit den zweitwenigsten Stunden.


----------



## rs-plc-aa (10 Februar 2005)

Zottel schrieb:
			
		

> Es wird die 1 aus dem 1.Wort des Index-DB geladen. Der Sprungverteiler springt zur 2.Marke. Dort wird das 2. BM eingeschaltet (weil du dessen Ausgang hinter dieser Marke ansteuerst). Das 2. BM ist das mit den wenigsten Stunden.
> 
> Soll nun noch ein BM eingeschaltet werden, so wird die 3 aus dem 2.Wort des Index-DB geladen. Der Sprungverteiler springt zur 3.Marke. Dort wird das 3. BM eingeschaltet (weil du dessen Ausgang hinter dieser Marke ansteuerst). Das 3. BM ist das mit den zweitwenigsten Stunden.



Hallo,

darüber muß ich mir morgen intensiv Gedanken machen - denn das worauf die Sprungleiste zurückgreift ist für mich (noch) ein böhmisches Dorf... - obwohl ich volles Vertrauen habe in das was du sagst.

Aber gerade im Moment ist das für micht nicht greifbar da ich erst verstehen muß wie "die 1 aus dem ersten Wort des IndexDB´s geladen wird" - da hier für mich zunächst nur 7 einzelne Bytes drin sind :?


----------



## Zottel (10 Februar 2005)

rs-plc-aa schrieb:
			
		

> Aber gerade im Moment ist das für micht nicht greifbar da ich erst verstehen muß wie "die 1 aus dem ersten Wort des IndexDB´s geladen wird" - da hier für mich zunächst nur 7 einzelne Bytes drin sind :?


Sorry, ersetze "Wort" durch "Byte", habe mir das Programm nicht nochmal angesehen.


----------



## rs-plc-aa (10 Februar 2005)

Hallo,

gut ok - das nehme ich dir keinesfalls übel...


Dann komme ich schon eher hin.

Ich hab das Programm jetzt zwar auch nicht vor mir aber ich versuch´s mal so:

Die Sprungleiste ist ja so aufgebaut:


```
L "Zahl" // Bitte beschriften...
SPL over // Die Zahl ist größer als die Anzahl der Elemente
SPA BM0 // Zahl = 0
SPA BM1 // = 1
SPA BM2 // = 2
SPA BM3 // = 3
SPA BM4 // ...
SPA BM5
SPA BM6

over: nop 0
S Störung // Zum Beispiel
SPA ENDE

BM0: // hier gleich prüfen ob das BM Bereit ist UND ob es schon läuft...
// Wenn Bereit=1 UND Läuft=0 dann
Einschalten_BM0
SPA EN1

BM1: ....

....
```

Ist das soweit korrekt ?


----------



## Zottel (10 Februar 2005)

Im Prinzip ist das korrekt.
Nach Einschalten eines BMs musste dann noch die Zahl der benötigen BMs verringert werden und die Position der Nummer des nächsten BMs im IndexDB hochgezählt, so daß als nächstes BM das mit den nächstwenigstens Stunden genommen wird.

Es sind doch schon alle Teillösungen hier aufgetaucht (außer vielleicht die Betriebsstunden im DatenDB genau dann hochzuzählen, wenn das BM eingeschaltet ist. Dabei muß natürlich die gleiche Zuordnung zwischen BM-Nummern und Ausgängen verwendet werden. Soll heißen, wenn im Sprungverteiler BM-Nummer 0 zum Einschalten des A12.0 führt, so muß, wann immer A12.0 ein ist, die Zeit im Eintrag 0 des DatenDB hochgezählt werden.).


Warum packst du es nicht auf eine CPU oder einen Simulator und probierst den ganzen Ablauf, bis du es verstehst?


----------



## rs-plc-aa (10 Februar 2005)

Zottel schrieb:
			
		

> Warum packst du es nicht auf eine CPU oder einen Simulator und probierst den ganzen Ablauf, bis du es verstehst?



Hallo,

da bin ich gerade dabei...

Jetzt war´s aber so daß im Auswertungsbaustein der die FC 17 aufruft nichts passiert ist --> kein Aufruf der FC.

Der Fehler lag an der SPZ anweisung die eigentlich nur ausgeführt werden sollte wenn keine weitere Anforderung ansteht.

Sie wurde aber komischerweise immer ausgeführt, und verhinderte das Starten der FC.


Ich hab dann mal


```
//... Das erste Modul holen...

      L     0
      L     "Module_soll"
      SPZ   nene                        // ... oder auch nicht ...

      CALL  "Index_Ausw"
       Nummer :="Index_Pos"
       indexDB:=10
       Anzahl :="Module_soll"
```


gegen


```
//... Das erste Modul holen...

      L     0
      L     "Module_soll"
      ==I   
      SPB   nene                        // ... oder auch nicht ...

      CALL  "Index_Ausw"
       Nummer :="Index_Pos"
       indexDB:=10
       Anzahl :="Module_soll"
```

getauscht - und siehe da es geht...

Was ich jetzt zwar sehe aber nicht verstehe ist das:



```
AUF   DB [#idbn]
      L     #Nummer
      L     8                           // 8-bit-Einträge 
      *I    
      T     LD    12                    // Temp index    
      L     DBB [LD 12]

      SPL   tbig                        // wenn Nummer größer als Anzahl Sprungziele ist
      SPA   BM00
      SPA   BM01
      SPA   BM02
      SPA   BM03
      SPA   BM04
      SPA   BM05
      SPA   BM06

tbig: NOP   0
// hier kann eine Störmeldung o.Ä. erzeugt werden...
      SPA   ende

BM00: NOP   0
      UN    "M1_Bereit"                 // betriebsbereit BM0 
....
```

Wenn jetzt z.B. #Nummer = 6 ist, dann wird ja mit 8 multipliziert und in LD 12 kopiert (habe es von LD0 auf LD12 geändert...).

Hier steht dann 48 drin...

Nach der Anweisung

     L     DBB [LD 12]

steht 4 im Akku 1... warum ???

mir ist klar daß in meinem Beispiel das BM 4 (Sprungziel ist allerdings BM3 weil von 0 an gezählt) in der Indexliste an sechster stelle steht --> also eigentlich richtig gedeutet.

Laut Programmstatus wird aber an der Marke BM 5 (=Modul 6) weitergemacht...

In wirklichkeit wird aber das reale Modul 4 (Marke BM3) eingeschaltet.


Das verwirrt mich wieder komplett   

Vielleicht liegt´s aber auch am Simulator --> und wenn es so ist dann kann der einen manchmal gewaltig nerven   :!:


----------



## Zottel (10 Februar 2005)

rs-plc-aa schrieb:
			
		

> Hallo,
> 
> da bin ich gerade dabei...
> 
> ...


So ist es richtiger. War das andere von mir?



> Was ich jetzt zwar sehe aber nicht verstehe ist das:
> 
> ```
> AUF   DB [#idbn]
> ...


Wohl deshalb weil im 7 Byte des IndexDB die Nummer 4 stand. Das kann ich aber nur aus dem Ergebnis schließen.
Nummer =6 bedeutet: 7.Eintrag im IndexDB = DBB6
Nummer =0 bedeutet: 1.Eintrag im IndexDB = DBB0
Die Byte-Nummer (hier 6) ist mit 8 zu multiplizieren. Das ist einfach eine Vorraussetzung damit der Befehl

```
L     DBB [LD 12]
```
funktioniert.
 Es haben ja schon Leute versucht, "pointer" zu erklären. Eigentlich finde ich das keine gute Erklärung, weil:
1. Step7 auch noch "typisierte" Pointer kennt, z.B. P#DB20.DBX0.0, P#E60.0, die eine Information über den Speicherbereich beinhalten.
2. Die hier verwendeten Adressen im Gegensatz zu pointern anderer Programmiersprachen stehen: Im Gegenstatz zu Pascal ist Rechnen mit "pointern" erlaubt.  Im Gegenstatz zu C wird bei den Berechnungen aber eben nicht die Größe des Zielobjekts automatisch berücksichtigt.

Man könnte meinen, der Befehl

```
L     DBB [LD 12]
```
behandele den Speicher als ein "array of bits". Nur: dann sollte es möglich sein, mittels eines Ausdrucks wie      L     DBB [5] ein byte zu lesen des erste 3 bits aus DBB0 und die anderen 5 aus DBB1 stammen. Geht aber nicht.

Fazit: der Befehl

```
L     DBB [LD 12]
```
braucht immer die 8-fache Bytenummer, was zufällig auch die Bit-Nummer ist. Das ist weder vernünftig, noch dem Wesen nach durch den Begriff "Pointer" zu erklären, sondern schlicht eine "Schrulle" der Siemens-Entwickler, mit der man jetzt leben muß.



> mir ist klar daß in meinem Beispiel das BM 4 (Sprungziel ist allerdings BM3 weil von 0 an gezählt) in der Indexliste an sechster stelle steht --> also eigentlich richtig gedeutet.


Ja, genau.


> Laut Programmstatus wird aber an der Marke BM 5 (=Modul 6) weitergemacht...


Kann ich nicht nachvollziehen, eventuell siehst du einen Durchlauf in einem anderen Zyklus?
Kan der Simulator Einzelschritt?


> In wirklichkeit wird aber das reale Modul 4 (Marke BM3) eingeschaltet.


Das soll es ja auch.


----------



## rs-plc-aa (10 Februar 2005)

Zottel schrieb:
			
		

> rs-plc-aa schrieb:
> 
> 
> 
> ...



Ja... (Hätte theoretisch auch funktionieren müssen nur praktisch halt nicht)




> Wohl deshalb weil im 7 Byte des IndexDB die Nummer 4 stand. Das kann ich aber nur aus dem Ergebnis schließen.
> Nummer =6 bedeutet: 7.Eintrag im IndexDB = DBB6
> Nummer =0 bedeutet: 1.Eintrag im IndexDB = DBB0
> Die Byte-Nummer (hier 6) ist mit 8 zu multiplizieren. Das ist einfach eine Vorraussetzung damit der Befehl
> ...



Hiermit schon gut genug erklärt...




> 1. Step7 auch noch "typisierte" Pointer kennt, z.B. P#DB20.DBX0.0, P#E60.0, die eine Information über den Speicherbereich beinhalten.



Ich kannte bisher nur die...



> Fazit: der Befehl
> 
> ```
> L     DBB [LD 12]
> ...



man muß es eben nur wissen...



> Kan der Simulator Einzelschritt?



Ja - werde ich jetzt noch ausprobieren...


Um hier alles gleichzeitig im Auge zu haben sollte man eine Kinoleinwand als Monitor haben...


----------



## RMA (10 Februar 2005)

> Es haben ja schon Leute versucht, "pointer" zu erklären. Eigentlich finde ich das keine gute Erklärung, weil:
> 1. Step7 auch noch "typisierte" Pointer kennt, z.B. P#DB20.DBX0.0, P#E60.0, die eine Information über den Speicherbereich beinhalten.
> 2. Die hier verwendeten Adressen im Gegensatz zu pointern anderer Programmiersprachen stehen: Im Gegenstatz zu Pascal ist Rechnen mit "pointern" erlaubt. Im Gegenstatz zu C wird bei den Berechnungen aber eben nicht die Größe des Zielobjekts automatisch berücksichtigt.



Ich wollte eigentlich gar nicht groß den Begriff "Pointer" erklären, viel mehr ein bischen Licht darauf werfen, weswegen es nötig ist um 8 zu multiplizieren. Das ganze ist ganz gut in Berger erklärt und wenn man das Diagramm auf Seite 338 vor Augen hat, wo die Struktur der Zeiger dargestellt wird, dann kann man klar sehen weswegen es einfacher zu verstehen ist wenn man SLD 3 benutzt (was natürlich funktional dasselbe ist).


----------



## Zottel (10 Februar 2005)

Kenne leider den Berger nicht.
Kannst Du die Struktur mal eben widergeben?


----------



## rs-plc-aa (10 Februar 2005)

RMA schrieb:
			
		

> Ich wollte eigentlich gar nicht groß den Begriff "Pointer" erklären, viel mehr ein bischen Licht darauf werfen, weswegen es nötig ist um 8 zu multiplizieren. Das ganze ist ganz gut in Berger erklärt und wenn man das Diagramm auf Seite 338 vor Augen hat, wo die Struktur der Zeiger dargestellt wird, dann kann man klar sehen weswegen es einfacher zu verstehen ist wenn man SLD 3 benutzt (was natürlich funktional dasselbe ist).



Da hab ich doch gleich mal den Berger (3. Auflage, 2002 ) aufgeschlagen...

Da kommt bei mir aber auf S. 338 etwas von Alarmbehandlung.


Wie heißt denn das Kapitel genau ?


----------



## rs-plc-aa (10 Februar 2005)

Zottel schrieb:
			
		

> Kenne leider den Berger nicht.
> Kannst Du die Struktur mal eben widergeben?



Wenn RMA so freundlich ist und das Kapitel beschreibt, schmeiße ich es auf den Scanner und poste es dann....


----------



## RMA (10 Februar 2005)

Oops,   war gerade auf dem Weg zurück zu sagen im KOP / FUP Buch, Kap. 24 - Ergänzung zur grafischen Programmierung.

Das AWL Buch hab' ich leider nicht, aber vielleicht findest Du es im Stichwortverzeichniss unter "Zeiger" (mindestens, so ist es im KOP / FUP Buch zu finden).


----------



## Zottel (10 Februar 2005)

Zottel schrieb:
			
		

> Kenne leider den Berger nicht.
> Kannst Du die Struktur mal eben widergeben?


Ach ja, fand sich ja wahrscheinlich schon im Thread:
Byte.Bit, wobei die hinteren drei Bits für die Bitnummer reseviert sind.
SLD 3 heißt dann "schiebe die Bytenummer in die Bits fürs Byte".

Es ist jedoch recht sinnlos, den Index von L DBB[x] so zu codieren, ohne auch den Zugriff auf ein Byte ab einer beliebigen Bitposition zu implementieren.


----------



## RMA (10 Februar 2005)

Hier ist die Seite, hoffentlich ist es gut lesbar.


----------



## rs-plc-aa (10 Februar 2005)

Hallo,

jetzt habe ich es glaube ich schon kapiert...

Ich füge hier mal einen Auschnitt vom Code an an dem ich das nun "extra ausführlich" kommentiert habe.

Wenn die Kommentare stimmen dann müsste ich das kapiert haben.


```
L     #indexDB                    // Index DB Nr. zuweisen
      T     #idbn

      AUF   DB [#idbn]                  // IndexDB aufschlagen
      L     #Nummer                     // Offset laden (DBB in dem das gewünschte Modul steht)
      L     8                           // 8-bit-Einträge 
      *I    
      T     LD    12                    // Inhalt in Temp index kopieren
      L     DBB [LD 12]                 // Modul-Nummer des gewählten DBB aus dem Index lesen

      SPL   tbig                        // wenn Nummer größer als Anzahl Sprungziele ist
      SPA   BM00                        // Sprung nach BM00 wenn Modul-Nummer = 0 war => real #1
      SPA   BM01                        // ...wenn = 1 war => real #2
      SPA   BM02                        // ...wenn = 2 war => real #3
      SPA   BM03                        // ...wenn = 3 war => real #4
      SPA   BM04                        // ...wenn = 4 war => real #5
      SPA   BM05                        // ...wenn = 5 war => real #6
      SPA   BM06                        // ...wenn = 6 war => real #7

tbig: NOP   0
// hier kann eine Störmeldung o.Ä. erzeugt werden...
      SPA   ende

BM00: NOP   0
      UN    "M1_Bereit"                 // betriebsbereit BM0 
      BEB                               // Ende ohne reduzierte Anzahl, kann BM nicht einschalten 
      S     "Modul1_Ein"                // Modul 1 einschalten 
      SPA   END1                        // Ende mit reduzierter Anzahl 

..........

END1: NOP   0           
      L     #Anzahl  
      DEC   1
      T     #Anzahl  // wenn das Modul bereit war und eingeschaltet wurde wird die Anzahl der benötigten um 1 verringert

      BE
```

Das ganze ist ja nun auch ziemlich komplett.

Angenommen es wird ein Modul eingeschaltet das aber daraufhin nicht gestartet werden kann...

Das einzige was es dann tun muß ist das Bit "Betriebsbereit" zurücksetzen, dann wird beim nächsten durchlauf erkannt daß es nicht mehr verfügbar ist und automatisch das nächst höhere (Stunden) genommen - genial.



Eine Sache überlege ich aber gerade noch:

Um zu vermeiden daß ein eingeschaltetes das gerade einwandfrei läuft abgewählt wird - nur weil es ein anderes (das gerade steht) gerade mit den Stunden überholt hat könnte man noch eine Verriegelung einbauen.

Diese muß dann aber an der Stelle platziert werden bevor alle ausgeschaltet werden.


Ich dachte da mal an folgendes:

Wenn ich mir merke wieviele Module vorher liefen, und dann vergleiche mit der Anzahl was nun laufen soll, und feststelle daß es gleich viele sind -> nichts machen....


Somit wäre zumindest gewährleistet daß wenn gerade 4 Stück laufen sollen - es die selben 4 bleiben - egal was die Stunden sagen.


Wenn dann eine Änderung eintritt wird´s schon schwieriger...

Wenn es weniger sein sollen als vorher wird ja das mit den meisten Stunden weggelassen - dabei kann aber auch schon passieren daß eines das bisher stand auch wieder weniger hat als eines das bisher lief - also Tausch.

Umgekehrt genauso.



Aber zumindest wenn sich nix ändert sollte man auch nix ändern - das geht ja... - oder etwa nicht ?

... da fällt mir doch während ich hier schreibe noch der worst case ein...


Ich zitiere mich mal:



> Angenommen es wird ein Modul eingeschaltet das aber daraufhin nicht gestartet werden kann...
> 
> Das einzige was es dann tun muß ist das Bit "Betriebsbereit" zurücksetzen, dann wird beim nächsten durchlauf erkannt daß es nicht mehr verfügbar ist und automatisch das nächst höhere (Stunden) genommen - genial.



geht dann aber auch nicht - weil dann davon ausgegangen wird daß das bloße Einschalten ausreichte - aber der Fall daß das Einschalten quasi umsonst war wird dann gar nicht berücksichtigt...


Ich glaube es sollte so bleiben - dann kann eigentlich nix (oder am wenigsten) schief gehen.


----------



## Zottel (10 Februar 2005)

Müßte jetzt selbst diesen Thread gründlichst lesen, um alles wieder ins Bewußtsein zu holen...
Aber, wenn ich es richtig weiß, war meine Vorstellung:
1. Die Zahl der benötigten BMs ermitteln.
2. Nur wenn sich diese geändert hat, neu sortieren und neu schalten.

Soweit wäre es egal wenn ein E kommt, einer geht und die Zahl gleich bleibt.

Aber 2 Fälle sind doof:

1. Ein E geht, eine Sekunde später kommt wieder einer, es wird 2x sortiert und geschaltet.

2. Es bleiben über sehr lange Zeit drei Eingänge anstehen; aus Gründen der Gerechtigkeit sollen aber mal andere BMs drankommen.

Fall 1 Läßt sich durch einen Zeitverzoegerung lösen: Wenn die neue Zahl der benötigten BMs ungleich der alten Anzahl ist, eine Zeit starten, erst bei Ablauf der Zeit neu sortieren, schalten und benötigte Anzahl als alte speichern. 

Fall 2 ließe sich lösen, indem auch bei unveränderter Anzahl der BMs nach Ablauf einer Zeit X die BMs sortiert und geschaltet werden.


> Angenommen es wird ein Modul eingeschaltet das aber daraufhin nicht gestartet werden kann...
> Das einzige was es dann tun muß ist das Bit "Betriebsbereit" zurücksetzen, dann wird beim nächsten durchlauf erkannt daß es nicht mehr verfügbar ist und automatisch das nächst höhere (Stunden) genommen - genial.


 
Das mit der Bereitschaft: So wie der Code bis jetzt ist, wird vor Einschalten des BMs die Bereitschaft überprüft. Daß das Einschalten selbst schiefgeht, ist eigentlich durch die allgemeinere Bedingung "Betriebsbereitschaft eines eingeschalteten BMs fällt weg" mit zu erledigen. Diese wird bis jetzt nicht behandelt.


Am Einfachsten dürfte es sein, dann ein Sortieren und Neuverteilen zu erzwingen. Dabei wird dann das nicht bereite BM übergangen.
[/quote]


----------



## rs-plc-aa (10 Februar 2005)

Hallo,

ich habe gerade auch wie verrückt überlegt - jedoch in eine etwas andere Richtung...


Das was jetzt kommt ist definitiv für meinen Fall anzuwenden:


"Fall 2" bräuchte ich genau umgekehrt.


Es sollen die BM´s die schon mal laufen auf jeden Fall weiterlaufen - egal wie lange.


So lange sich die Anzahl vorher - nachher nicht ändert braucht ja nur überwacht zu werden daß die welche mal angefordert wurden auch immer noch laufen.

Dann kommt der Fall Änderung der Anzahl:

Hier sollen ebenfalls vorrangig die weiterlaufen die vorher schon liefen.


Es soll also generell darauf geachtet werden die Ein-Ausschaltvorgänge zu minimieren.


So nun wann ist aber der richtige Moment neu zu sortieren ??

Oder vielleicht nur einen Teil der Liste (ausgenommen von den laufenden) neu zu sortieren...


Das macht mir gerade einen ziemlichen Kopf .


----------



## Zottel (10 Februar 2005)

Du kannst es so machen: 
Bei Änderungen unterscheiden,  ob mehr oder weniger BMs verlangt werden.

Werden es mehr, sortierst du aufsteigend, schaltest nix aus und ein BM ein. Dabei prüfst du auf "betriebsbereit und noch nicht ein".

Werden es weniger, sortierst du absteigend, schaltest nix ein und ein BM aus.
Dabei prüfst du auf "eingeschaltet". Du schaltest also das BM aus, daß die meiste Zeit auf dem Buckel hat und ein ist.

Statt die Sortierrichtung zu wechsel, kannst du auch beim Ausschalten mit dem letzten Element des Index beginnen und rückwärts gehen.


----------



## rs-plc-aa (11 Februar 2005)

Hallo,

ich bin gerade noch feste am tüfteln...

Eines ist aber klar - das letzte Vorhaben hier zu implementieren ist ganz schön knifflig...


Ich habe es nun mal so gemacht (funktioniert allerdings noch nicht richtig):


Bubble Sort geklont, und geändert in aufsteigend - so kann dann bei Bedarf der jeweilige aufgerufen werden...

Dann die An-Abwahl dahingehend geändert daß sie unterscheidet zwischen An- und Abwahl.

Einen weiteren Baustein hinzugefügt der überwacht so lange sich nix ändert ob auch die laufen die laufen sollen (mit Ret-VAL anhand derer dann reagiert werden kann).



Aber irgendwie spielen die Bits gerade ein wenig verrückt, und es tut nicht so wie es soll.


Meine befürchtung ist ein wenig daß der bis dato noch sehr kompakte Code zum aufgeblasenen Monster mutiert  :shock:


----------



## Zottel (11 Februar 2005)

rs-plc-aa schrieb:
			
		

> Bubble Sort geklont, und geändert in aufsteigend - so kann dann bei Bedarf der jeweilige aufgerufen werden...


Wieso klonen? Ich meine, es ist schon ein Parameter dafür drin!


> Meine befürchtung ist ein wenig daß der bis dato noch sehr kompakte Code zum aufgeblasenen Monster mutiert  :shock:


Ja eben draum nicht klonen. Mein Vorschlag von gestern vergrößert den Code um weniger als 10 %.


----------



## rs-plc-aa (11 Februar 2005)

Zottel schrieb:
			
		

> Wieso klonen? Ich meine, es ist schon ein Parameter dafür drin!



Oooops...

jetzt hab ich das doch glatt mißverstanden mit dem Aufruf.

Ich habe Bubble Sort also zwei mal hintereinander gestartet, und die Sortierrichtung vom zweiten Aufruf erhalten....




			
				Zottel schrieb:
			
		

> //
> // OB1 zum Testen des FC16:
> //
> 
> ...



wie peinlich...

Darauf habe ich jetzt gar nicht mehr geachtet

wird sofort geändert...

===============================================




> Du kannst es so machen:
> Bei Änderungen unterscheiden, ob mehr oder weniger BMs verlangt werden.
> 
> Werden es mehr, sortierst du aufsteigend, schaltest nix aus und ein BM ein. Dabei prüfst du auf "betriebsbereit und noch nicht ein".
> ...




Zitat vom Zitat:


> Bei Änderungen unterscheiden, ob mehr oder weniger BMs verlangt werden.



Das habe ich versucht mit einem FC zu lösen der abfrägt wieviele BM´s gerade laufen und mit der Zahl der Anforderungen vergleicht.

Bei gleichheit ist der Ret_Val 0 , sind es mehr = 1 und weniger = 2...

Im aufrufenden Baustein werte ich dann den Ret_Val aus...

Bei 0 nichts machen

bei 1 Schalter "Aufsteigend" = 1

bei 2 Schalter "Aufsteigend" = 0


Dann den Index sortieren (entsprechend der Schalterstellung).

Und dann wird´s problematisch.

Schalte ich nun alle aus (wie vorher) habe ich nachher das Problem daß ich die richtigen wieder erwische (die die laufen und weiterlaufen sollen - egal wieviel Stunden...)

Schalte ich keine aus ist´s noch schwieriger...




> Werden es mehr, sortierst du aufsteigend, schaltest nix aus und ein BM ein. Dabei prüfst du auf "betriebsbereit und noch nicht ein".




und 



> Werden es weniger, sortierst du absteigend, schaltest nix ein und ein BM aus.
> Dabei prüfst du auf "eingeschaltet". Du schaltest also das BM aus, daß die meiste Zeit auf dem Buckel hat und ein ist.




Das muß ja beides in den An-Abwahl Baustein rein - oder ?

Er muß dann zusätzlich entscheiden (unterscheiden) ob An - oder Abgewählt wird - richtig ?


Ich glaube irgendwie habe ich das Ganze minimal unterschätzt - und das gewaltig


----------



## Schibi (12 Februar 2005)

Hallo,

ich hab so ein änliches Programm vor kurzem geschrieben, dabei geht es um 5 Kompressoren, die den Druck in einem System innerhalb eines bestimmten Wertebereiches halten sollen. Ist der Druck zu gering wird der Kompressor mit den geringsten Betriebstunden zugeschaltet. Ist der Druck zu hoch wird der Kompressor mit den meisten Betriebstunden abgeschaltet. Wenn du willst kann ich es dir mailen, vielleicht hilft dir das weiter??? Kannst mir ja deine emailadresse senden.


Gruß Schibi


----------



## rs-plc-aa (14 Februar 2005)

Hallo,

am Wochenende hatte ich (eigentlich aus der Verzweiflung heraus) eine Idee, die ich hier mal gerne vortragen wollte.


Ich habe mir überlegt ob es nicht einfach ausreichen würde die realen Betribsstundenstände der einzelnen BM´s (die ja über die MS-Kommunikation eingelesen werden) nur dann zu aktualisieren wenn das entsprechende BM nicht läuft.

Das Ergebnis wäre ja dann daß die Stunden der BM´s die laufen, zur Laufzeit nicht "mehr" werden (im Stunden DB zumindest) und die von denen die stehen ja sowieso nicht...


Somit wäre doch gewährleistet daß immer die selben angefordert werden - da die Stunden im DB eingefroren sind.

Wird eines oder mehrere dann abgewählt, werden die Stunden aktualisiert, und wenn diese dann höher sind als die die seither nicht liefen, rutschen diese ja dann im DB (wenn dann) nach hinten (auf keinen Fall nach vorne).

Die, die aber immer noch laufen, bleiben vorne (mit am wenigsten Stunden).

Die Umsetzung war eigentlich schon vorhanden - musste nur ein wenig erweitert werden.


```
FC 1 "Stunden DB versorgen":

      SET   
      U     "M1_Laeuft"
      SPB   a001

      L     "BH_Modul_1"
      T     "Stunden".Stunden_Modul1

a001: NOP   0
      U     "M2_Laeuft"
      SPB   a002

      L     "BH_Modul_2"
      T     "Stunden".Stunden_Modul2

a002: NOP   0
      U     "M3_Laeuft"
      SPB   a003

      L     "BH_Modul_3"
      T     "Stunden".Stunden_Modul3

a003: NOP   0
      U     "M4_Laeuft"
      SPB   a004

      L     "BH_Modul_4"
      T     "Stunden".Stunden_Modul4

a004: NOP   0
      U     "M5_Laeuft"
      SPB   a005

      L     "BH_Modul_5"
      T     "Stunden".Stunden_Modul5

a005: NOP   0
      U     "M6_Laeuft"
      SPB   a006

      L     "BH_Modul_6"
      T     "Stunden".Stunden_Modul6

a006: NOP   0
      U     "M7_Laeuft"
      SPB   a007

      L     "BH_Modul_7"
      T     "Stunden".Stunden_Modul7

a007: NOP   0

      BE
```


Mir ist bis jetzt noch nichts eingefallen was dagegen spricht.


Was meint ihr dazu ?


----------

