Bearbeitung einer While bedingung oder was läuft hier falsch?

vollmi

Level-3
Beiträge
5.436
Reaktionspunkte
1.410
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe hier mal einen Auszug eines Case Abteils. Alle sehen ähnlich aus.
Die ersten vier Zeilen nehme ich um die Boundaries zu prüfen und für die While schleife den Start neu zu stellen.
Aber irgendwie scheint das nicht zu klappen. die While Schleife zählt bis zur oberen Grenze also 5 danach wird nicht mehr erhöht und darum natürlich die obere Grenze nicht überschritten also kein Indizies.SetSymbol := 0;
durchgeführt.

Und ich habe jetzt das Problem rausgefunden. Aber ich sehe nicht wo ich den Fehler mache.

Code:
        3:[COLOR=#ff0000] // dies ist der Casezweig[/COLOR]
            (* Setsymbol *)
                IF NOT ((Indizies.SetSymbol >= 0) AND (Indizies.SetSymbol <= obereGrenze)) THEN
                    Indizies.SetSymbol := 0;
                END_IF;


SendZaehler[Indizies.SetSymbol].SetSymbol := SendZaehler[Indizies.SetSymbol].SetSymbol + 1; [COLOR=#ff0000]// das hab ich eingefügt um zu sehen ob er durch alle Indizies.SetSymbol durchgeht[/COLOR]
                IF NOT Fut_Tel_Koppel.Send_Koppel.Req AND Telegramstarten THEN
                    WHILE Indizies.SetSymbol >= 0 AND Indizies.SetSymbol <= obereGrenze DO


                        IF Signale[Indizies.SetSymbol].setsymbolbits.Req AND Signale[Indizies.SetSymbol].Act THEN
                            IF NOT Signale[Indizies.SetSymbol].Dim_driver THEN (* Wenn Dimmen über Treiber eingeschaltet werden soll in ELSE Zweig Bit 32 mitsenden *)
                                MOVE_BLK(IN    := ADR(Signale[Indizies.SetSymbol].Act_Signalstatus.Soll[0]),
                                         COUNT := 7,
                                         OUT   := ADR(Signale[Indizies.SetSymbol].setsymbolbits.Telegram[1]));
                            ELSE
                                MOVE_BLK(IN    := ADR(Signale[Indizies.SetSymbol].Act_Signalstatus.Soll[0]),
                                         COUNT := 3,
                                         OUT   := ADR(Signale[Indizies.SetSymbol].setsymbolbits.Telegram[1]));
                                Signale[Indizies.SetSymbol].setsymbolbits.Telegram[4] := 16#80;
                                MOVE_BLK(IN    := ADR(Signale[Indizies.SetSymbol].Act_Signalstatus.Soll[4]),
                                         COUNT := 4,
                                         OUT   := ADR(Signale[Indizies.SetSymbol].setsymbolbits.Telegram[5]));
                            END_IF;


                            Data_Len := Len_SetSymbol;
                            Signale[Indizies.SetSymbol].TagCmd := FC_Fut_TAG_Gen(Signale[Indizies.SetSymbol].TagCmd);
                            FC_Fut_SendTelCompose(Addr      := Signale[Indizies.SetSymbol].sid,
                                                    Count     := Data_Len,
                                                    TagCmd    := Signale[Indizies.SetSymbol].TagCmd,
                                                    Data      := ADR(Signale[Indizies.SetSymbol].setsymbolbits.Telegram),
                                                    Command   := Cmd_SetSymbol,
                                                    SenderTel := ADR(Fut_Tel_Koppel.Send_Koppel.Tel));
                            Fut_Tel_Koppel.Send_Koppel.LEN := SendTelHeadLen + Chk1 + Data_Len + Chk2;
                            Signale[Indizies.SetSymbol].setsymbolbits.Req := FALSE;
                            Fut_Tel_Koppel.Send_Koppel.Req := TRUE;


                            Indizies.SetSymbol :=  Indizies.SetSymbol + 1; [COLOR=#ff0000]// wenn Req und Act index eins hochzählen und while verlassen.[/COLOR]
                            EXIT;
                        ELSE
                            Indizies.SetSymbol :=  Indizies.SetSymbol + 1; [COLOR=#ff0000]// wenn kein Req und Act index eins hochzählen und mit while weitermachen[/COLOR]
                        END_IF;


                    END_WHILE;
                END_IF;
            IF Indizies.SetSymbol >= obereGrenze THEN
                ComCase := ComCase + 1; [COLOR=#ff0000]// nächsten Case Zweig auswählen[/COLOR]
            END_IF;

SendZaehler[Indizies.SetSymbol].SetSymbol habe ich eingefügt um die durchgänge an jderem While index zu zählen. Zählen tut er nur auf eintrag 4. als ob er durch die Zeile mit Indizies.SetSymbol := Indizies.SetSymbol + 1; nie durchkommt.

Hab ich da irgendwo n massiven Denkfehler?
 
Zuletzt bearbeitet:
Was soll das ganze eigentlich machen? Wo auch immer das Problem liegt, das was du mit "WHILE" machst, sieht mir sehr stark nach einem Fall für "FOR" aus.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das ginge grundsätzlich auch mit FOR. Aber ich möchte die Schleife verlassen und selbst wenn das REQ im nächsten zyklus wieder an denselbem Eintrag wieder ansteht möchte ich nicht dass wieder dasselbe Telegram abgefüllt wird, sondern trotzdem erstmal die nächsten einträge abgearbeitet wird.

mit dem While will ich verhindern dass derselbe Teilnehmer immerwieder dran kommt nur weil er zuoberst im Array steht. Ansonsten müsste ich verhindern das REQ direkt wieder gesetzt werden kann.

es soll durch den Case und durch die jeweiligen While Schleifen gegangen werden und ein Telegram nach dem anderen abgefüllt und versendet werden.

Auf der der S7-300 bzw 1500 Funktioniert das Konstrukt seit jahren. Ich wollte es jetzt mal so huschhusch auf einer codesys 2.3 steuerung zum laufen bringen. Und grundsätzlich läufts auch, aber irgendwie scheint sich das zeug ab und zu zu verhängen.
 
Hallo Vollmi

Ist deine Bedingung
Code:
[LEFT][COLOR=#333333][FONT=Courier] IF Signale[Indizies.SetSymbol].setsymbolbits.Req AND Signale[Indizies.SetSymbol].Act THEN[/FONT][/COLOR][/LEFT]
TRUE endet dein Indizies Zähler nach der While Schleife mit 5. Ist sie jedoch FALSE endet der
Indizies Zähler mit 6.
In beiden Fällen gehst du zum nächsten Case
Bei der Prüfung
Code:
[LEFT][COLOR=#333333][FONT=Courier]IF NOT ((Indizies.SetSymbol >= 0) AND (Indizies.SetSymbol <= obereGrenze)) THEN
                    Indizies.SetSymbol := 0;
                END_IF;[/FONT][/COLOR][/LEFT]

ist das Ergebnis für Indizies Zähler = 5 FALSE. Somit erfolgt kein Rücksetzen. Die nachfolgende While Schleife wird also genau 1 mal durchlaufen.

Holger

 
ist das Ergebnis für Indizies Zähler = 5 FALSE. Somit erfolgt kein Rücksetzen. Die nachfolgende While Schleife wird also genau 1 mal durchlaufen.

Oh Kac*

Jetzt ist mir auch klar wieso mir das nie aufgefallen ist. Den hab ich vor Jahren für 100 Slaves designet. Das hat aber bestimmt nie jemand ausgenützt weil dann die Serielle Linie vermutlich zusammenbrechen würde ^^
Dies ist das erste mal dass ich alle Plätze belege weil die alte Steuerung etwas knapp an Speicher ist.

Und jetzt starre ich seit Stunden dadrauf und habs nicht gesehen.
Danke dir du hast mir die Woche gerettet.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Vollmi

Ist deine Bedingung
Code:
[LEFT][COLOR=#333333][FONT=Courier] IF Signale[Indizies.SetSymbol].setsymbolbits.Req AND Signale[Indizies.SetSymbol].Act THEN[/FONT][/COLOR][/LEFT]
TRUE endet dein Indizies Zähler nach der While Schleife mit 5. Ist sie jedoch FALSE endet der
Indizies Zähler mit 6.

:confused:
Einverstanden, im Falle FALSE wird die Schleife immer mit dem Wert 6 im Index verlassen.
Aber im Falle TRUE wird die Schleife mit dem Wert 1 oder 2 oder 3 oder 4 oder 5 oder 6 im Index (vorzeitig) verlassen, je nach dem, bei welchem Index (0..5) die Abfrage zuerst TRUE liefert.
Welchen Knackpunkt habe ich übersehen?​
 

:confused:
Einverstanden, im Falle FALSE wird die Schleife immer mit dem Wert 6 im Index verlassen.
Aber im Falle TRUE wird die Schleife mit dem Wert 1 oder 2 oder 3 oder 4 oder 5 oder 6 im Index (vorzeitig) verlassen, je nach dem, bei welchem Index (0..5) die Abfrage zuerst TRUE liefert.
Welchen Knackpunkt habe ich übersehen?​

Wenn bei 4 ein true ist dann erreiche ich die 5 beim ende und durch die case hochzählung bei 5 komme ich gar nicht mehr zum Teilnehmer an platz 5.

ich hab das etwas kompliziert gemacht. War noch aus meiner st anfangszeit aber alles umwerfen? Dazu fehlt mir grad noch die motivation.
 
Code:
IF Indizies.SetSymbol >= obereGrenze THEN
Aus der Zeile das "=" zu löschen ist doch nicht "alles umwerfen". Oder mache ich es mir jetzt zu einfach?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
IF Indizies.SetSymbol >= obereGrenze THEN
Aus der Zeile das "=" zu löschen ist doch nicht "alles umwerfen". Oder mache ich es mir jetzt zu einfach?

nene das meinte ich nicht. Aber ich hab da mittlerweile 7 Abzweigungen in dem Case ich hätte das Telegrammzusammenbasteln auch etwas stärker kapseln können und das dann mit nem Fifo lösen können. Aber es ist so wie es jetzt ist dafür recht einfach zu verstehen (jaja wenn man die Zählung richtig macht ;)
 
Wenn bei 4 ein true ist dann erreiche ich die 5 beim ende und durch die case hochzählung bei 5 komme ich gar nicht mehr zum Teilnehmer an platz 5.
Durch die fehlende CASE-Hochzählung beim Index <= 5 bleibst Du dann im selben CASE, steigst dann aber mit dem Index=5 (statt vorher 4) in die Schleife ein, so dass diesmal dann auf jeden Fall die Schleife mit Index=6 verlassen wird.
Das Aufhängen (Stehenbleiben bei Index=5) verstehe ich insofern nicht. Es resultiert doch nur eine Verzögerung um 1 PLC-Zyklus?
Welchen Einfluss die Obergrenze (5 oder 100) auf das Prinzip haben soll, leuchtet mir auch nicht ein.
Mir fehlt einfach der Durchblick, welches Verhalten des Index beabsichtigt ist.

Ich vermute, dass das Weiterschalten des Index per
Index := (Index + 1) MOD (Obergrenze +1)
kombiniert einem eigenen SchleifenZähler für die While-Schleife (oder stattdessen eben doch eine FOR-Schleife) für die Anzahl Durchläufe = Obergrenze passender sein könnte.

Ist Dein Index statisch, sodass am Beginn der CASE-Selektion mit dem letzten Zustand von Index im vorherigen Zyklus fortgesetzt wird oder temporär, sodass immer mit Index = 0 oder mit einem undefinierten (und ggfs auf 0 "korrigierten") Zustand von Index begonnen wird?
 
Zuletzt bearbeitet:
Durch die fehlende CASE-Hochzählung beim Index <= 5 bleibst Du dann im selben CASE, steigst dann aber mit dem Index=5 (statt vorher 4) in die Schleife ein, so dass diesmal dann auf jeden Fall die Schleife mit Index=6 verlassen wird.
Das Aufhängen (Stehenbleiben bei Index=5) verstehe ich insofern nicht. Es resultiert doch nur eine Verzögerung um 1 PLC-Zyklus?

Das stimmt nun auch wieder. Ich habe jetzt Testweise einfach nur das Array um eins verlängert und obergrenze um eins erhöht. Jetzt scheints zu funktionieren, allerdings hoffe ich dass dies nicht nur zufall (weil die speicher neu belegt wurden) ist.

Die Indizies und Case Variable ist statisch. ich möchte ja das Case und die whiles zur Suche des ersten anstehenden REQ nutzen. Dann diesen Ausführen Req auf false setzen und mit dem sende Req die weitere Suche blockieren, bis Fut_Tel_Koppel.Send_Koppel.Req vom Sendebaustein wieder zurückgesetzt wurde (done oder fehler)

danach soll die Suche exakt da weitermachen wo sie unterbrochen wurde. also nicht wieder von vorne weitermachen. FOR würde immer den ERsten REQ finden. ich möchte aber den nächsten REQ finden (falls der letzte REQ ausserhalb des Suchzyklus von extern wieder gesetzt wurde möchte ich nicht dasselbe telegramm nochmal schicken)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
1. Die Indizies und Case Variable ist statisch.
2. ich möchte ja das Case und die whiles zur Suche des ersten anstehenden REQ nutzen. Dann diesen Ausführen Req auf false setzen und mit dem sende Req die weitere Suche blockieren, bis Fut_Tel_Koppel.Send_Koppel.Req vom Sendebaustein wieder zurückgesetzt wurde (done oder fehler)

3. danach soll die Suche exakt da weitermachen wo sie unterbrochen wurde. also nicht wieder von vorne weitermachen. FOR würde immer den ERsten REQ finden. ich möchte aber den nächsten REQ finden (falls der letzte REQ ausserhalb des Suchzyklus von extern wieder gesetzt wurde möchte ich nicht dasselbe telegramm nochmal schicken)
Zu 1.:
Dass Index und Case-Variable statisch sein sollen, war mir schon klar. Aber sind sie es tatsächlich immer noch - trotz der Umstellung auf CodeSys?

Zu 2.:
Weitere Suche blockieren? Warum wird dann auch im Fall TRUE der Index vor dem EXIT erhöht?

Zu 3.:
Die Idee mit der FOR-Schleife hatte ich nur für den Fall aufgegriffen, dass der Index nicht identisch mit der ZählVariable der Schleife ist. Die ZählVariable der Schleife soll lediglich die maximale Anzahl der Durchläufe begrenzen und so eine EndlosSchleife verhindern. Der Index für den Zugriff auf die Kriterien würde dadurch nicht verfälscht.
 
Zu 1.:
Dass Index und Case-Variable statisch sein sollen, war mir schon klar. Aber sind sie es tatsächlich immer noch - trotz der Umstellung auf CodeSys?

Ich habe die Variablen in VAR / VAR_end des FB deklariert. Die FB Instanz habe ich in VAR / VAR_End des aufrufenden PRG deklariert.

Zu 2.:
Weitere Suche blockieren? Warum wird dann auch im Fall TRUE der Index vor dem EXIT erhöht?

Da ich das Telegramm vor Exit abgefüllt und im Sendebuffer abgelegt habe kann ich die Indizies schon hochzählen das beim nächsten eintritt ins While der Index schon auf dem nächsten Suchplatz startet.

Zu 3.:
Die Idee mit der FOR-Schleife hatte ich nur für den Fall aufgegriffen, dass der Index nicht identisch mit der ZählVariable der Schleife ist. Die ZählVariable der Schleife soll lediglich die maximale Anzahl der Durchläufe begrenzen und so eine EndlosSchleife verhindern. Der Index für den Zugriff auf die Kriterien würde dadurch nicht verfälscht.

Achso. Du würdest im If trotzdem eine statische Variable hochzählen aber als FOR Schleife mit eigenem Index starten. Das wäre natürlich möglich.
wäre einfach eine andere Herangehensweise.
Ich versteh aber noch nicht so recht wie man dass dann zusammenbauen soll.
 
Zuletzt bearbeitet:
Ah ja, innerhalb der aktiven Schleife soll das WeiterSuchen blockiert werden.

Mit der vorab festgelegten maximalen Anzahl der Durchläufe wäre es auch eine abgewandelte SuchStrategie, sodass immer einmal "rundherum" alle anderen Plätze eine Chance haben, abgesucht zu werden. Nicht nur die paar, die bis zur Obergrenze noch in Frage kommen. Ob das allerdings so gewünscht wäre? Keine Ahnung.

Noch sehe ich nicht, dass Dein Problem wirklich gelöst ist. Scheint es nur zufällig (Daten-abhängig) so, dass es überhaupt ein Problem gibt bzw. dass es gelöst sein könnte?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Heinileini; schrieb:
Noch sehe ich nicht, dass Dein Problem wirklich gelöst ist. Scheint es nur zufällig (Daten-abhängig) so, dass es überhaupt ein Problem gibt bzw. dass es gelöst sein könnte?

Pho. Ich werd’s heute Nacht sehen. Problem ist, das der Weg doch recht weit ist. Und wenn’s nicht funktioniert kann man sich bis um halb fünf morgens dran probieren danach is vorbei.


Gesendet von eyePhone
 
So interessanterweise funktioniert die sache einwandfrei auf allen vier stationen. Ich begreifs trotzdem noch nicht wieso überhaupt. Ich muss mir jetzt mal n antwortdummy basteln, um das nachstellen zu können.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Was ist daraus geworden? War's ne sehr informative und spassige Stunde vor Feierabend? ;)

Es funktioniert jetzt seit nem Monat einwandfrei nachdem ich den zusätzlichen Arrayplatz angelegt habe, den es eigentlich nicht braucht, wieso es so funktioniert kann ich immer noch nicht sagen.
Die Nacht war aber Kurz. Um 22 Uhr angefangen, um 23:30 war alles getestet und es funktionierte auch auf den Uraltsteuerungen so wie ich es gewohnt bin auf den 1500ern. Das downloaden der änderungen ist hier aber noch Zeitaufwändiger als bei der 1500er. Vor allem da jedesmal noch irgendwelche html dateien der VISU geladen werden auf die wartet man ne gefühlte Ewigkeit.

Ich hab jetzt n neues Projekt am Start indem ich den Treiber auf S7-1500 Basis wieder verwende und da nochmal bis ans ende des deklarierten Arrays gehen werde. Hier sind die Debuggingfunktionen etwas komfortabler. Dann geht mir vielleicht ein Licht auf.
 
Zurück
Oben