Reihenfolge per Zufallsgenerator bestimmen

Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Heinileini,

vielen Dank für Deine Geduld.

Damit nicht immer wieder Zwischenfragen nötig sind sind schreibe ich jetzt mal einen Roman.

Zur Aufgabe
Ich möchte die Rolladen in täglich unterschiedlicher Reihenfolge öffnen und schließen. Der Start ist die Uhrzeit, die aus dem Thema "Startzeit an die Jahreszeit anpassen" stammt. Da Du konkret danach fragst, die Pausen zwischen den Aufgaben sollten zwischen 60 und 300 Sekunden sein. Immer unterschiedlich wäre super.

Nun zum Rest
Sicherlich ist das alles nicht unbedingt nötig, und über sinnvoll oder nicht kann man unterschiedliche Ansichten haben. Wie ich schon geschrieben habe, dient die neue Steuerung als Ersatz, für eine alte Micro, die nicht mehr mit mir kommunizieren wollte. (Nur am Rande, jetzt wo sie abgebaut ist, hat sie es sich anders überlegt, und ich kann sie wieder aufrufen.)
Dort hatte ich damals einen Wust integriert, der ein paar Lampen einschaltete und die Rolladen in unterschiedlicher Reihenfolge herunterfuhr. Das hat, wenn wir nicht zuhause waren immer den Eindruck erweckt, das das Haus nicht unbewohnt war. (Unser Haus war mal sieben Jahre gänzlich unbewohnt)
Da ich damals statt strukturierter Programmierung eher nach dem Motto "ein Genie beherscht das Chaos" etwas zusammengezimmert habe, blicke ich da eh nicht mehr durch.

Da ich die neue Steuerung innerhalb kurzer Zeit in Betrieb genommen habe, möchte ich, nachdem die Grundfunktionen laufen, diese um solche Annehmlichkeiten erweitern.

Dabei versuche ich zuerst eine eigene Lösung zu finden und probiere vieles aus. Leider werden mir meistens schnell meine Grenzen aufgezeigt. Durch meine ungenauen Fragen läuft es dann oft in die falsche Richtung.

Die Aufgabe habe ich oben nochmal konkret beschrieben.
Nun gibt es immer viele Wege, die zum Ziel führen. Wenn ich das richtig sehe, sind es zwei unterschiedliche Dinge, einmal die Reihenfolge, die täglich durcheinander gebracht werden müsste, und einmal die Werte für die Pausen erzeugen.

Wenn es zwei unterschiedliche Dinge sind habe ich eine Bitte. Ich möchte mit der Reihenfolge beginnen, die mit der Variablen Start=True beginnt und die Aufgaben mit A ... G in eine beliebige Reihenfolge bringt. Wenn es geschickter ist, beides zu kombinieren, dann bitte zusammen.

Danke für Euer Verständnis
 
Zuletzt bearbeitet:
Die einfachsten Zufallsgeneratoren sind absolut simpel von der Berechnung her und benötigen nur eine Variable als Speicher, ...
Ja, genau, Thomas. Woher dann die riesen Aufregung?
"Mein" (wie bereits gesagt: von hewlett-packard "geklauter") ZufallsZahlenGenerator ist doch absolut simpel und benötigt nur 1 (i.W.: eine) Variable als Speicher!
In der VBA-Schreiweise:
Code:
    xG# = xG# * 977
    xG# = xG# - Int(xG#)
Und eine mögliche Initialisierung ("randomize") dazu, ebenfalls in VBA:
Code:
    xG# = 2 ^ 0.5
    xG# = xG# - Int(xG#)
Wobei der Anteil 'xG# = xG# - Int(xG#)' durchaus verzichtbar ist und mehr der "Schönheit" dient. Verzichtbar, weil folgende ZufallsZahlenBildungen trotzdem funktionieren. Schönheit insofern, als bereits hier das ZahlenFormat "ohne VorkommaStellen" produziert wird, wie es nach dem Durchlaufen einer ZufallsZahlenBildung auch vorliegt.

Dass meine Workaround-Verwurstelung der in CodeSys von mir nicht gefundenen INT-Funktion recht unschön aussieht, bitte ich zu verzeihen - in CodeSys bin ich wahrscheinlich nicht einmal Erstklässler. ;)

Sooo, nun zurück zum eigentlichen Thema.
Wir wollen nicht vordergründig eine möglichst zufällige Folge der Ziffern 1 .. 7 bilden, sondern Kombinationen aus den Ziffern 1 .. 7.
Diese Kombinationen sollen jede dieser Ziffern genau 1-mal enthalten und die gefundenen Kombinationen sollen sich von Mal zu Mal unterscheiden und uns nach Möglichkeit mit Wiederholungen verschonen. Allerdings können Wiederholungen trotz und wegen aller Zufälligkeit dennoch auftreten. Das ist nicht per se ein Makel.
Mein Ansatz war, ein Array mit 7 Elementen vorzugeben (und ja, dieses ganze Array zu speichern) und zu "shufflen", wofür ich eine Rotation der Elemente um jeweils 1 Platz vorgesehen habe und
ein Tauschen von zwei Elementen. Hier kommen die ZufallsZahlen wieder ins Spiel: sie bestimmen, welches der Elemente gegen welches andere Element getauscht wird.

Um Wolfgang ein wenig Abwechslung zu gönnen, habe ich bei der Vorgabe des Startwertes für den ZufallsZahlenGenerator ein wenig Luxus eingebaut (und nur für diesen Zweck eine weitere Variable spendiert, die gespeichert werden muss). Mit dieser Mimik werden der Initialisierung ("Randomize") wechselnde PrimZahlen (2 .. 32749) vorgegeben, aus der sie die QuadratWurzel zieht ...

Gruss, Heinileini
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Zur Aufgabe
Ich möchte die Rolladen in täglich unterschiedlicher Reihenfolge öffnen und schließen. Der Start ist die Uhrzeit, die aus dem Thema "Startzeit an die Jahreszeit anpassen" stammt. Da Du konkret danach fragst, die Pausen zwischen den Aufgaben sollten zwischen 60 und 300 Sekunden sein. Immer unterschiedlich wäre super.
Sooo, jetzt wieder zu Dir, Wolfgang!

Vor lauter Zufallerei bin ich ja gar nicht mehr dazu gekommen, auf Dich einzugehen. :oops:
Wie wär's, wenn wir die Aktivierung eines Rollladen und die Wartezeit gleichzeitig starten? Die Wartezeit (60..300 s) dürfte dürfte wohl lang genug sein, so dass der Rolladen mit seiner Aktion längst fertig ist, bevor die Zeit abgelaufen ist. Notfalls verlängern wir die Wartezeiten, die wir jetzt nicht mehr als Wartezeit nach dem vollendeten Schliessen bzw. Öffnen interpretieren, sondern als Wartezeit nach dem Starten des Schliessens oder Öffnens, um z.B. 30 s.
Dann müssen wir gar keine Rückmeldungen von 7 Rollläden haben, sondern nur die Rückmeldung von 1 Timer - wir benutzen für die 6 (oder 7) Wartezeiten einfach immer denselben Timer.
Ja, beschlossen und verkündet. Gefällt mir.
Auf dieser Basis werde ich mal weiterknobeln ...

Gruss, Heinileini
 
Hallo,

ich bin garnicht glücklich über das von mir verursachte Durcheinander.

Dann müssen wir gar keine Rückmeldungen von 7 Rollläden haben, sondern nur die Rückmeldung von 1 Timer - wir benutzen für die 6 (oder 7) Wartezeiten einfach immer denselben Timer.
Ja, beschlossen und verkündet. Gefällt mir.
Auf dieser Basis werde ich mal weiterknobeln ...

Na ja, dann werde ich das mal wohlwollend Abnicken :-)

Das sind genau die Kleinigkeiten, die mir, wenn überhaupt, erst zum Ende hin auffallen und den benötigten Aufwand reduzieren.

Danke im Voraus und noch einen schönen Abend
 
Wie immer, absolut ungetestet:
Code:
FUNCTION_BLOCK UpsAndDowns

    Pause         : TOF  ; // TOF-Instanz deklarieren - ist das so richtig?

VAR_INPUT
    itMax         : TIME ; // OberGrenze  für Wartezeit [ms] (inklusive Ausführungszeit)
    itMin         : TIME ; // UnterGrenze für Wartezeit [ms] (inklusive Ausführungszeit)
END_VAR

VAR_IN_OUT
    iobBlindsDown : BOOL ; // Startet Sequenz "Rollläden in zufälliger Reihenfolge schliessen"
    iobBlindsUp   : BOOL ; // Startet Sequenz "Rollläden in zufälliger Reihenfolge öffnen"
END_VAR

VAR_OUTPUT
    obBlind1Down  : BOOL ; // schliesst Rollladen 1
    obBlind1Up    : BOOL ; // öffnet    Rollladen 1
    obBlind2Down  : BOOL ; // schliesst Rollladen 2
    obBlind2Up    : BOOL ; // öffnet    Rollladen 2
    obBlind3Down  : BOOL ; // schliesst Rollladen 3
    obBlind3Up    : BOOL ; // öffnet    Rollladen 3
    obBlind4Down  : BOOL ; // schliesst Rollladen 4
    obBlind4Up    : BOOL ; // öffnet    Rollladen 4
    obBlind5Down  : BOOL ; // schliesst Rollladen 5
    obBlind5Up    : BOOL ; // öffnet    Rollladen 5
    obBlind6Down  : BOOL ; // schliesst Rollladen 6
    obBlind6Up    : BOOL ; // öffnet    Rollladen 6
    obBlind7Down  : BOOL ; // schliesst Rollladen 7
    obBlind7Up    : BOOL ; // öffnet    Rollladen 7
END_VAR

VAR
//  giA[0..6]     : INT  ; // (Globales?!) Array mit 7 zufällig angeordneten Zahlen 1..7
//  grR           : REAL ; // (Globale?!)  0.0 < ZufallsZahl < 1.0
    iAct          : INT := 8 ; // 0..6: Index für giA[]; 7: letzte Aufgabe der Sequenz; 8: Sequenz beendet
    bTimerIN      : BOOL ; // StartImpuls für Pausen-TOF 
    tTimerPT      : TIME ; // Dauer für Pausen-TOF im Bereich laut itMin .. itMax (z.B. 60..300 s)
END_VAR

    iobBlindsUp := iobBlindsUp AND NOT iobBlindsDown ; // BlindsUp rücksetzen, wenn BlindsDown
    IF iAct > 7 THEN // Sequenz inaktiv
        IF iobBlindsUp OR iobBlindsDown THEN
            iAct := 0 ; // Sequenz inaktiv und neue Aufgabe, dann Sequenz auf Anfang setzen
        END_IF ;
    ELSIF NOT Pause.Q THEN // Sequenz aktiv, warten auf PausenEnde, dann Aufgabe beenden und ggfs nächste starten
        obBlind1Up   := FALSE ; obBlind1Down := FALSE ;
        obBlind2Up   := FALSE ; obBlind2Down := FALSE ;
        obBlind3Up   := FALSE ; obBlind3Down := FALSE ;
        obBlind4Up   := FALSE ; obBlind4Down := FALSE ;
        obBlind5Up   := FALSE ; obBlind5Down := FALSE ;
        obBlind6Up   := FALSE ; obBlind6Down := FALSE ;
        obBlind7Up   := FALSE ; obBlind7Down := FALSE ;
        IF iAct < 7 THEN // AuftragsGenerierung aktiv
            CASE giA[iAct] OF // Rollladen-Nr
            1:  // Rollladen 1
                obBlind1Up := iobBlindsUp ; obBlind1Down := iobBlindsDown ;
            2:  // Rollladen 2
                obBlind2Up := iobBlindsUp ; obBlind2Down := iobBlindsDown ;
            3:  // Rollladen 3
                obBlind3Up := iobBlindsUp ; obBlind3Down := iobBlindsDown ;
            4:  // Rollladen 4
                obBlind4Up := iobBlindsUp ; obBlind4Down := iobBlindsDown ;
            5:  // Rollladen 5
                obBlind5Up := iobBlindsUp ; obBlind5Down := iobBlindsDown ;
            6:  // Rollladen 6
                obBlind6Up := iobBlindsUp ; obBlind6Down := iobBlindsDown ;
            ELSE // Rollladen 7
                obBlind7Up := iobBlindsUp ; obBlind7Down := iobBlindsDown ;
            END_CASE ; 
            bTimerIN := iobBlindsUp OR iobBlindsDown ; // TimerStart vorbereiten ...
            IF bTimerIN THEN // falls Aufgabe, dann Pausenzeit (Zufall!) festlegen 
                grR := grR * 997.0 - INT_TO_REAL (REAL_TO_INT (grR * 997.0)) ; // neue ZufallsZahl
                tTimerPT := REAL_TO_TIME((grR * TIME_TO_REAL(itMax - itMin)) + TIME_TO_REAL(itMin)) ; // Wartezeit in ms
            END_IF ;
        END_IF ;
        iAct := iAct + 1 ; // ... und Vorlage der nächsten Aufgabe vorbereiten
    END_IF ;
    Pause(bTimerIN, tTimerPT) ; // ? ? ?
    bTimerIN := FALSE ; // TimerStart rücksetzen
    IF iAct > 7 THEN // wenn Sequenz komplett durchlaufen, dann AuftragsMerker rücksetzen ;
        iobBlindsUp := FALSE ; iobBlindsDown := FALSE ;
    END_IF ;
END_FUNCTION_BLOCK
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Heinileini,

vielen Dank.

Der Zu-fall ist gefallen und hat mich fast erschlagen.

Ein paar rot markierte Stellen gab es im Code, die sind nun weg. Ich habe es auch geschafft, das Ding ans Laufen zu bekommen. Was dann noch fehlte war die zufällige Reihenfolge im Array.

Dafür habe ich den Code aus dem Beitrag#3 eingefügt. Leider nicht so ganz mit dem gewünschten Erfolg. Ich erhalten lediglich einen anderen Startpunkt der Sequenz von 1 bis 7.

Nun habe ich soviel hin und her geschoben und ausprobiert, bis es im Chaos geendet ist. Ich werde alles nochmal neu machen. Das bringt ein wenig Übung :-)

Nur eine Frage
Der Code aus Beitrag #3 erzeugt eine beliebige Zahlenfolge von 7 Zahlen?

Dann werde ich nochmal versuchen den Code zur Erzeugen des Arrays einzubauen.
 
1. Ein paar rot markierte Stellen gab es im Code, die sind nun weg. Ich habe es auch geschafft, das Ding ans Laufen zu bekommen.
2. Was dann noch fehlte war die zufällige Reihenfolge im Array.
Dafür habe ich den Code aus dem Beitrag#3 eingefügt. Leider nicht so ganz mit dem gewünschten Erfolg. Ich erhalten lediglich einen anderen Startpunkt der Sequenz von 1 bis 7.
3.Der Code aus Beitrag #3 erzeugt eine beliebige Zahlenfolge von 7 Zahlen?
Zu 1.:
Worum ging es im einzelnen? Was wurde bemeckert? Was hast Du getan, dass es jetzt weg ist? An's Laufen bekommen heisst was? Keine FehlerMeldungen mehr oder der FB gibt schon erste "Lebenzeichen" von sich? Welche? Es ist für mich schwierig, mitzudenken, wenn ich nicht ein Bisschen mehr über die aufgetretenen Probleme und deren Beseitigungen erfahre.
Zu 2.:
Der Code aus #3 besteht aus 2 Teilen:
a) die Initialisierung des Array giA[]. Die Elemente giA[0]..giA[6] werden mit Zahlen 1..7 gefüllt - jede der Zahlen nur 1-mal) und
der Speicher für die ZufallsZahl bzw. den ZufallsZahlenGenerator grR (REAL Zahl >0.0 und < 1.0).
Die InitialisierungsRoutine hinterlässt in giP ausserdem eine Primzahl im Bereich 2..32749, die sie benutzt hat, um daraus den AnfangsWert für grR zu bilden.
Wird die InitialisierungsRoutine wieder durchlaufen, so wird die nächste Primzahl ermittelt und in giP gespeichert und daraus der Wert in grR gebildet.
Normalerweise genügt es, diese Prozedur 1-mal zu Anfang zu durchlaufen. Darf aber auch "gelegentlich" zwischendurch aufgerufen werden.
b) das DurcheinanderWürfeln des Array mit zweimaliger Benutzung des ZufallsZahlenGenerators.
Hier werden die Inhalte von giA[0]..giA[6] rotiert, d.h. giA[0] erhält den Wert von giA[1], giA[1] den von giA[2] u.s.w. bis giA[5] den von giA[6] und schliesslich giA[6] den zu Anfang geretteten Wert von giA[0]. Jetzt werden noch zwei der Elemente untereinander getauscht. Die beiden TauschKandidaten werden durch ZufallsZahlen (aus grR durch Skalieren in den Bereich 0..6 gebracht) festgelegt.
Den Teil b musst Du immer dann aufrufen/durchlaufen, wenn Du die Belegung des Array giA[] ändern willst! Z.B. täglich oder vor jeder "alle-Rollläden-in-zufälliger-Reihenfolge-öffnen-Aktion" und/oder der "alle-Rollläden-in-zufälliger-Reihenfolge-schliessen-Aktion".
Die Inhalte des Array giA[] und des ZufallsWerts grR und des PrimzahlSpeichers giP sollen erhalten bleiben, bis das Programm "irgendwann" wieder darauf zurückgreift.
Darum habe ich vorgesehen, dass Du sie global deklarierst.
Wenn mit der Bildung der ZufallsZahlen oder der Veränderung der Array-Belegung etwas nicht mehr zu klappen scheint, bitte nachsehen, was in giA[0]..giA[6], in giP und in grR drinsteht.
giP und grR dürfen nicht 0 sein und in giA[0]..giA[6] darf jede der Zahlen 1..7 nur 1-mal vorkommen, sonst kann die Mimik nicht so funktionieren, wie beabsichtigt.
Ggfs Teil a (die Initialisierung) wiederholen, dann werden brauchbare Inhalte vorbesetzt. Das sollte aber normalerweise nicht nötig sein.
Zu 3.:
Siehe "zu 2", also JAIN.
Teil a erzeugt eine kaum bis gar nicht zufallsabhängige, aber "brauchbare" Belegung des Array.
Teil b ändert die Belegung "zufallsabhängig", setzt aber voraus, dass das Array bereits einen "brauchbaren" Inhalt hat.

Ähnlich ist es mit der ZufallsZahl grR.
Es muss schon etwas "Brauchbares" drin stehen, dann kann man die nächste ZufallsZahl damit bilden. Siehe z.B. im Code von #45 in der Zeile
Code:
    [COLOR=#333333][FONT=Courier]grR := grR * 997.0 - INT_TO_REAL (REAL_TO_INT (grR * 997.0)) ; // neue ZufallsZahl[/FONT][/COLOR]
 
Hallo Heinileini,

vielen Dank für die ausführliche Beschreibung.

Bemeckert wurden hauptsächlich ein paar Dinge um den Timer für die Pause, aber darauf hattest Du ja schon hingewiesen. Was da noch so war? Wenn es Dich interessiert kopiere ich den Code nochmal in einen neuen POU und schau nach. Mache ich morgen und poste das was bemängelt wird, und was ich gemacht habe.

Es wurmt mich schon ein wenig, dass ich es nicht hinbekomme. Ich werde es mit der obigen Beschreibung nochmal versuchen.

Vielen Dank, noch einen schönen Abend und bis morgen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Heinileini,

so, jetzt alles was rot war

Code:
    //Von mir zugefügt bzw geändert
    giA: ARRAY[0..6] OF INT;
    grR: REAL;    
    //Pause         : TOF  ; // TOF-Instanz deklarieren - ist das so richtig?
    TOF_Pause         : TOF  ; // TOF-Instanz deklarieren - ist das so richtig?
    A_Down : BOOL;     //zum Start Down
    A_Up : BOOL;         //zum Start Up

   // Pause(bTimerIN, tTimerPT) ; // ? ? ?
   TOF_Pause (IN := bTimerIN, PT := tTimerPT) ;

   //ELSIF NOT Pause.Q THEN // Sequenz aktiv, warten auf PausenEnde, dann Aufgabe beenden und ggfs nächste starten
    ELSIF NOT TOF_Pause.Q THEN

Wie schon geschrieben ging es um die Deklaration von TOF, auf die Du schon hingewiesen hast, und auf die beiden Variablen, die aber schon im Code aus Beitrag #3 deklariert wurden.

Weiter habe ich für die Ausgänge Up_1 ... Up_7 und Down_1 ... Down_7 zugefügt. Und A_Down und A_Up für den Start.

Nun den Code aus Beitrag#3
Dauert etwas, bin nicht der Schnellste.
 
Zuletzt bearbeitet:
Hallo Heinileini,

zwischenzeitlich wähnte ich mich auf der Zielgerade, aber dann bin ich mal wieder falsch abgebogen.

Nach dem Start wird das Array laufend mit Zahlen gefüllt. Ich habe versucht, das nur einmal anzustossen und wenn das Array gefüllt ist Rolladen zu schließen. Irgendwann ging es mal, aber nur einmal nach dem Start (Warum auch immer). Dann viel mir auf, dass es manchmal gleiche Zahlen im Array gab. Vermutlich habe ich an der falschen Stelle gestoppt. Meine Versuche habe ich alle wieder verworfen und dann total den Faden verloren.

Ich poste mal den Code. Könntest Du dort bitte Start und Stop für das einmalige Füllen des Arrays einfügen? An dem nächsten Schritt (Start der Rolladen) würde ich mir dann gerne selbst nochmal die Zähne ausbeissen.

Code:
FUNCTION_BLOCK UpsAndDowns

VAR_INPUT
    itMax         : TIME := T#8S ; // OberGrenze  für Wartezeit [ms] (inklusive Ausführungszeit)
    itMin         : TIME := T#2S ; // UnterGrenze für Wartezeit [ms] (inklusive Ausführungszeit)
END_VAR

VAR_IN_OUT
    iobBlindsDown : BOOL ; // Startet Sequenz "Rollläden in zufälliger Reihenfolge schliessen"
    iobBlindsUp   : BOOL ; // Startet Sequenz "Rollläden in zufälliger Reihenfolge öffnen"
END_VAR

VAR_OUTPUT
    obBlind1Down  : BOOL ; // schliesst Rollladen 1
    obBlind1Up    : BOOL ; // öffnet    Rollladen 1
    obBlind2Down  : BOOL ; // schliesst Rollladen 2
    obBlind2Up    : BOOL ; // öffnet    Rollladen 2
    obBlind3Down  : BOOL ; // schliesst Rollladen 3
    obBlind3Up    : BOOL ; // öffnet    Rollladen 3
    obBlind4Down  : BOOL ; // schliesst Rollladen 4
    obBlind4Up    : BOOL ; // öffnet    Rollladen 4
    obBlind5Down  : BOOL ; // schliesst Rollladen 5
    obBlind5Up    : BOOL ; // öffnet    Rollladen 5
    obBlind6Down  : BOOL ; // schliesst Rollladen 6
    obBlind6Up    : BOOL ; // öffnet    Rollladen 6
    obBlind7Down  : BOOL ; // schliesst Rollladen 7
    obBlind7Up    : BOOL ; // öffnet    Rollladen 7
END_VAR

VAR
//  giA[0..6]     : INT  ; // (Globales?!) Array mit 7 zufällig angeordneten Zahlen 1..7
//  grR           : REAL ; // (Globale?!)  0.0 < ZufallsZahl < 1.0
    iAct          : INT := 8 ; // 0..6: Index für giA[]; 7: letzte Aufgabe der Sequenz; 8: Sequenz beendet
    bTimerIN      : BOOL ; // StartImpuls für Pausen-TOF 
    tTimerPT      : TIME ; // Dauer für Pausen-TOF im Bereich laut itMin .. itMax (z.B. 60..300 s)
    //Von mir zugefügt
    giA: ARRAY[0..6] OF INT;
    grR: REAL;    
    //Pause         : TOF  ; // TOF-Instanz deklarieren - ist das so richtig?
    TOF_Pause         : TOF  ; // TOF-Instanz deklarieren - ist das so richtig?
    // zum Starten AB
    A_Down : BOOL;
    // zum Starten AUF
    A_Up : BOOL;
END_VAR
//Betrag#3
VAR
giP : INT;    
tbEnd : BOOL;    
tiBis : INT;
tiIdx1 : INT;
tiIdx2 : INT;
tiTmp : INT;    
trR : REAL;
    RTrig_Start: R_TRIG;
    ArrayBerechnen: BOOL;
END_VAR

Code:
   Merker.Start_AB := A_Down;
    Merker.Start_AUF :=A_Up;
    
    //Ab hier Beitrag#3
    // = = = = = < Init: "im Hochlauf der PLC" > = = = = =
// - - - < Array 0..6 initialisieren mit 1..7 > - - -
tiTmp := giA[0] ;
For tiIdx1 := 0 To 6 Do
    giA[tiIdx1] := (tiIdx1 + tiTmp) Mod 7 + 1 ;
END_FOR ;

// - - - < Startwert für grR bilden > - - -
If giP < 2 OR  giP > 32740 Then
    giP := 2 ;
Else
    Repeat
        //giP = giP + 1 + giP MOD 2 ;
        giP := giP + 1 + giP MOD 2 ;
        tiBis := Real_To_Int(Sqrt(Int_To_Real(giP))) ;
        tbEnd := True ;
        For tiIdx1 := 3 To tiBis By 2 Do
            If giP Mod tiIdx1 = 0 Then 
                tbEnd := False ;
                Exit ;
            End_If ;     
        End_For ;
    Until tbEnd
    End_Repeat ;
End_If ;
trR := Sqrt(Int_To_Real(giP)) ;
grR := trR - INT_TO_REAL(REAL_TO_INT(trR)) ;

// = = = = = < Next: "Verwirbeln des Array" > = = = = =

// - - - < Array rotieren > - - -
tiTmp:= giA[0] ;
For tiIdx1 := 0 To 5 Do
    giA[tiIdx1] := giA[tiIdx1 + 1] ;
End_For ;
giA[6] := tiTmp ;

// - - - < Idx1 bilden > - - -
trR := grR * 997.0 ;
grR := trR - Int_To_Real(Real_To_Int(trR)) ;
tiIdx1 := Real_To_Int(grR * 7.0) ;

// - - - < Idx2 bilden > - - -
trR := grR * 997.0 ;
grR := trR - Int_To_Real(Real_To_Int(trR)) ;
tiIdx2 := Real_To_Int(grR * 7.0) ;

// - - - < ggfs Idx2 korrigieren > - - -
If tiIdx1 = tiIdx2 Then 
    tiIdx2 := (tiIdx2 + 3) Mod 7 ;
End_If ;

// - - - < 2 Elemente tauschen > - - -
tiTmp:= giA[tiIdx1] ; 
giA[tiIdx1] := giA[tiIdx2] ;
giA[tiIdx2] := tiTmp ;
//Bis hier Beitrag#3

 iobBlindsUp := iobBlindsUp AND NOT iobBlindsDown ; // BlindsUp rücksetzen, wenn BlindsDown
    IF iAct > 7 THEN // Sequenz inaktiv
        IF iobBlindsUp OR iobBlindsDown THEN
            iAct := 0 ; // Sequenz inaktiv und neue Aufgabe, dann Sequenz auf Anfang setzen
        END_IF ;
    //ELSIF NOT Pause.Q THEN // Sequenz aktiv, warten auf PausenEnde, dann Aufgabe beenden und ggfs nächste starten
    ELSIF NOT TOF_Pause.Q THEN 
        obBlind1Up   := FALSE ; obBlind1Down := FALSE ;
        obBlind2Up   := FALSE ; obBlind2Down := FALSE ;
        obBlind3Up   := FALSE ; obBlind3Down := FALSE ;
        obBlind4Up   := FALSE ; obBlind4Down := FALSE ;
        obBlind5Up   := FALSE ; obBlind5Down := FALSE ;
        obBlind6Up   := FALSE ; obBlind6Down := FALSE ;
        obBlind7Up   := FALSE ; obBlind7Down := FALSE ;
        IF iAct < 7 THEN // AuftragsGenerierung aktiv
            CASE giA[iAct] OF // Rollladen-Nr
            1:  // Rollladen 1
                obBlind1Up := iobBlindsUp ; obBlind1Down := iobBlindsDown ;
            2:  // Rollladen 2
                obBlind2Up := iobBlindsUp ; obBlind2Down := iobBlindsDown ;
            3:  // Rollladen 3
                obBlind3Up := iobBlindsUp ; obBlind3Down := iobBlindsDown ;
            4:  // Rollladen 4
                obBlind4Up := iobBlindsUp ; obBlind4Down := iobBlindsDown ;
            5:  // Rollladen 5
                obBlind5Up := iobBlindsUp ; obBlind5Down := iobBlindsDown ;
            6:  // Rollladen 6
                obBlind6Up := iobBlindsUp ; obBlind6Down := iobBlindsDown ;
            ELSE // Rollladen 7
                obBlind7Up := iobBlindsUp ; obBlind7Down := iobBlindsDown ;
            END_CASE ; 
            bTimerIN := iobBlindsUp OR iobBlindsDown ; // TimerStart vorbereiten ...
            IF bTimerIN THEN // falls Aufgabe, dann Pausenzeit (Zufall!) festlegen 
                grR := grR * 997.0 - INT_TO_REAL (REAL_TO_INT (grR * 997.0)) ; // neue ZufallsZahl
                tTimerPT := REAL_TO_TIME((grR * TIME_TO_REAL(itMax - itMin)) + TIME_TO_REAL(itMin)) ; // Wartezeit in ms
            END_IF ;
        END_IF ;
        iAct := iAct + 1 ; // ... und Vorlage der nächsten Aufgabe vorbereiten
    END_IF ;
   // Pause(bTimerIN, tTimerPT) ; // ? ? ?
   TOF_Pause (IN := bTimerIN, PT := tTimerPT) ;
    bTimerIN := FALSE ; // TimerStart rücksetzen
    IF iAct > 7 THEN // wenn Sequenz komplett durchlaufen, dann AuftragsMerker rücksetzen ;
        iobBlindsUp := FALSE ; iobBlindsDown := FALSE ;
    END_IF ;

Und nur der Vollständigkeithalber und weil Du danach gefragt hast - Zeile 17 und 18 war noch etwas :-)
 
Und nur der Vollständigkeithalber und weil Du danach gefragt hast - Zeile 17 und 18 war noch etwas :-)
Ich nehme an, Du meinst ...
Code:
        //giP = giP + 1 + giP MOD 2 ;
        giP := giP + 1 + giP MOD 2 ;
Was war damit? Meckert der Compiler oder fehlt Dir mein Kommentar?
Hier soll der Inhalt von giP ...
- um 1 erhöht werden, wenn giP gerade ist (der DivisionsRest ist dann 0) bzw.
- um 2 erhöht werden, wenn giP ungerade ist (der DivisionsRest ist dann 1).

Ansonsten ... diesmal muss ich Deine Geduld strapazieren - ich bin auch nicht sooo schnell. :cry:
Wo es lang gehen soll, ist zwar klar, aber wie sage ich's dem CodeSys?

Versuch Du bitte alldieweil zu ergründen, wie und wo im Projekt man die globalen Variablen giA[], giP und grR deklarieren muss. Irgendwo ganz zu Anfang und ausserhalb von allen FBs - unterstelle ich mal.

Gruss, Heinileini

PS:
Der von Dir eingeschlagene Weg ist wahrscheinlich gar nicht so schlecht.
Ich werde, denke ich, auf diesem Wege weiter überlegen, dann brauchen wir die globalen Dinger nicht.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Kurz auf die Schnelle,

Du wolltest wissen, wo der Compiler gemeckert hat. Daher habe ich alles vermerkt.

Ich glaube, dass ich alles deklariert habe. Damit scheint es keine Probleme zu geben, oder ich habe da noch etwas nicht richtig verstanden.

Irgendwie habe ich Probleme das Array einmal richtig zu füllen und dann zu stoppen. Wenn Du mir sagst: "hier starten und wenn alles gefüllt ist hier wieder beenden. Array = True und am Ende False", das würde mir helfen.

Ich hatte teilweise Zahlen doppelt oder mit Minus, oder immer gleiche Reihenfolge. Wenn ich trotz dem richtigen Start- und Endpunkt nicht weiter komme melde ich mich noch einmal.

Danke und noch einen schönen Abend.
 
Hab da schnell mal was reingeflickt (hoffentlich nicht zu schnell):
Code:
   Merker.Start_AB := A_Down;
    Merker.Start_AUF :=A_Up;

VAR_INPUT              //    < < < < < eingefügt > > > > >
    ibInit    : BOOL ; //    < < < < < eingefügt > > > > >
    ibNext    : BOOL ; //    < < < < < eingefügt > > > > >
END_VAR                //    < < < < < eingefügt > > > > >

VAR                    //    < < < < < eingefügt > > > > >
    sbInitPre : BOOL ; //    < < < < < eingefügt > > > > >
    sbNextPre : BOOL ; //    < < < < < eingefügt > > > > >
END_VAR                //    < < < < < eingefügt > > > > >
    
    // = = = = = < Init: "im Hochlauf der PLC" > = = = = =
IF ibInit AND NOT sbInitPre THEN //    < < < < < eingefügt > > > > >
    //Ab hier Beitrag#3
    // - - - < Array 0..6 initialisieren mit 1..7 > - - -
    tiTmp := giA[0] ;
    For tiIdx1 := 0 To 6 Do
        giA[tiIdx1] := (tiIdx1 + tiTmp) Mod 7 + 1 ;
    END_FOR ;
    
    // - - - < Startwert für grR bilden > - - -
    If giP < 2 OR  giP > 32740 Then
        giP := 2 ;
    Else
        Repeat
            //giP = giP + 1 + giP MOD 2 ;
            giP := giP + 1 + giP MOD 2 ;
            tiBis := Real_To_Int(Sqrt(Int_To_Real(giP))) ;
            tbEnd := True ;
            For tiIdx1 := 3 To tiBis By 2 Do
                If giP Mod tiIdx1 = 0 Then 
                    tbEnd := False ;
                    Exit ;
                End_If ;     
            End_For ;
        Until tbEnd
        End_Repeat ;
    End_If ;
    trR := Sqrt(Int_To_Real(giP)) ;
    grR := trR - INT_TO_REAL(REAL_TO_INT(trR)) ;
END_IF ;              //    < < < < < eingefügt > > > > >
sbInitPre := ibInit ; //    < < < < < eingefügt > > > > >

// = = = = = < Next: "Verwirbeln des Array" > = = = = =

IF ibNext AND NOT sbNextPre THEN //    < < < < < eingefügt > > > > >
    // - - - < Array rotieren > - - -
    tiTmp:= giA[0] ;
    For tiIdx1 := 0 To 5 Do
        giA[tiIdx1] := giA[tiIdx1 + 1] ;
    End_For ;
    giA[6] := tiTmp ;
    
    // - - - < Idx1 bilden > - - -
    trR := grR * 997.0 ;
    grR := trR - Int_To_Real(Real_To_Int(trR)) ;
    tiIdx1 := Real_To_Int(grR * 7.0) ;
    
    // - - - < Idx2 bilden > - - -
    trR := grR * 997.0 ;
    grR := trR - Int_To_Real(Real_To_Int(trR)) ;
    tiIdx2 := Real_To_Int(grR * 7.0) ;
    
    // - - - < ggfs Idx2 korrigieren > - - -
    If tiIdx1 = tiIdx2 Then 
        tiIdx2 := (tiIdx2 + 3) Mod 7 ;
    End_If ;
    
    // - - - < 2 Elemente tauschen > - - -
    tiTmp:= giA[tiIdx1] ; 
    giA[tiIdx1] := giA[tiIdx2] ;
    giA[tiIdx2] := tiTmp ;
//Bis hier Beitrag#3
END_IF ;             //    < < < < < eingefügt > > > > >
sbNextPre := ibNex ; //    < < < < < eingefügt > > > > >

    iobBlindsUp := iobBlindsUp AND NOT iobBlindsDown ; // BlindsUp rücksetzen, wenn BlindsDown
    IF iAct > 7 THEN // Sequenz inaktiv
        IF iobBlindsUp OR iobBlindsDown THEN
            iAct := 0 ; // Sequenz inaktiv und neue Aufgabe, dann Sequenz auf Anfang setzen
        END_IF ;
    //ELSIF NOT Pause.Q THEN // Sequenz aktiv, warten auf PausenEnde, dann Aufgabe beenden und ggfs nächste starten
    ELSIF NOT TOF_Pause.Q THEN 
        obBlind1Up   := FALSE ; obBlind1Down := FALSE ;
        obBlind2Up   := FALSE ; obBlind2Down := FALSE ;
        obBlind3Up   := FALSE ; obBlind3Down := FALSE ;
        obBlind4Up   := FALSE ; obBlind4Down := FALSE ;
        obBlind5Up   := FALSE ; obBlind5Down := FALSE ;
        obBlind6Up   := FALSE ; obBlind6Down := FALSE ;
        obBlind7Up   := FALSE ; obBlind7Down := FALSE ;
        IF iAct < 7 THEN // AuftragsGenerierung aktiv
            CASE giA[iAct] OF // Rollladen-Nr
            1:  // Rollladen 1
                obBlind1Up := iobBlindsUp ; obBlind1Down := iobBlindsDown ;
            2:  // Rollladen 2
                obBlind2Up := iobBlindsUp ; obBlind2Down := iobBlindsDown ;
            3:  // Rollladen 3
                obBlind3Up := iobBlindsUp ; obBlind3Down := iobBlindsDown ;
            4:  // Rollladen 4
                obBlind4Up := iobBlindsUp ; obBlind4Down := iobBlindsDown ;
            5:  // Rollladen 5
                obBlind5Up := iobBlindsUp ; obBlind5Down := iobBlindsDown ;
            6:  // Rollladen 6
                obBlind6Up := iobBlindsUp ; obBlind6Down := iobBlindsDown ;
            ELSE // Rollladen 7
                obBlind7Up := iobBlindsUp ; obBlind7Down := iobBlindsDown ;
            END_CASE ; 
            bTimerIN := iobBlindsUp OR iobBlindsDown ; // TimerStart vorbereiten ...
            IF bTimerIN THEN // falls Aufgabe, dann Pausenzeit (Zufall!) festlegen 
                grR := grR * 997.0 - INT_TO_REAL (REAL_TO_INT (grR * 997.0)) ; // neue ZufallsZahl
                tTimerPT := REAL_TO_TIME((grR * TIME_TO_REAL(itMax - itMin)) + TIME_TO_REAL(itMin)) ; // Wartezeit in ms
            END_IF ;
        END_IF ;
        iAct := iAct + 1 ; // ... und Vorlage der nächsten Aufgabe vorbereiten
    END_IF ;
    // Pause(bTimerIN, tTimerPT) ; // ? ? ?
    TOF_Pause (IN := bTimerIN, PT := tTimerPT) ;
    bTimerIN := FALSE ; // TimerStart rücksetzen
    IF iAct > 7 THEN // wenn Sequenz komplett durchlaufen, dann AuftragsMerker rücksetzen ;
        iobBlindsUp := FALSE ; iobBlindsDown := FALSE ;
    END_IF ;
 
Hallo Heinileini,

vielen Dank.

Mach Dir bitte im Moment keine weitere Mühe, außer Daumen drücken. Wenn ich Glück habe, dann ist bei mir soeben der Groschen (wenn auch in Pfennigen) gefallen.

Allen ein schönes Wochenende
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Heinileini,

zurück aus der Versenkung Leider ist der Groschen nur in Pfennigen gefallen, und ein paar sind irgendwo hängen geblieben :-)

Nochmal ein paar Grundgedanken
Muss man einen Funktionsbaustein bauen? Habe doch eh schon keine Ahnung. Eigentlich möchte ich die Routine zweimal am Tag aufrufen - Rolladen AUF und AB.

Das Array ist vom letzten Aufruf noch gefüllt und müsste nur noch in eine andere Reihenfolge gebracht werden. Einmal Rotieren und dann ein- oder zweimal mit Zufallszahlen Plätze tauschen sollte vollkommen ausreichen.
Nun noch die Routine starten und mit zufälligen Pausenzeiten ausführen.
Feierabend bis zum nächsten Aufruf.

Leider gibt es da so einige Verständnisprobleme, was wann und wofür gemacht wird. Daher habe ich die Variablen so deklariert, dass es (für mich) aussagefähigere Namen sind. Somit jetzt die einzelnen Teile
Code:
// - - - < Array 0..6 initialisieren mit 1..7 > - - -
tiTmp := giA[0] ;
For Zahl_1 := 0 To 6 Do
    giA[Zahl_1] := (Zahl_1 + tiTmp) Mod 7 + 1 ;
END_FOR

Füllen des Array, funktioniert. Könnte aber entfallen, wenn man für den ersten Start einen Initialisierungswert vorgibt. Im weiteren Verlauf bleibt das Array mit der letzten Reihenfolge gefüllt.

Code:
// - - - < Array rotieren > - - -
tiTmp:= giA[0] ;
For Zahl_1 := 0 To 5 Do
    giA[Zahl_1] := giA[Zahl_1 + 1] ;
End_For ;
giA[6] := tiTmp ;

Funktioniert. Müsste im geeigneten Moment einmal gestartet werden.

Code:
// - - - < Startwert für X_Zuf bilden > - - -
If X_Prim < 2 OR  X_Prim > 32740 Then
    X_Prim := 2 ;
Else
    Repeat
        X_Prim := X_Prim + 1 + X_Prim MOD 2 ;
        tiBis := Real_To_Int(Sqrt(Int_To_Real(X_Prim))) ;
        tbEnd := True ;
        FOR tiIdx1 := 3 TO tiBis BY 2 DO
            IF X_Prim MOD tiIdx1 = 0 THEN
                tbEnd := False ;
                Exit ;
            End_If ;    
        End_For ;
    Until tbEnd
    End_Repeat ;
End_If ;
trR := Sqrt(Int_To_Real(X_Prim)) ;
X_Zuf := trR - INT_TO_REAL(REAL_TO_INT(trR)) ;

Funktioniert. Wenn es benötigt wird, müsste es für eine Weile Laufen um einen x-beliebigen Startwert zu erzeugen.
Hier erkenne ich die Funktion von tiBis und tbEnd nicht. Was hat es damit auf sich?

Code:
// - - - < Zufallszahl 1 zum Verschieben bilden > - - -
trR := X_Zuf * 997.0 ;
X_Zuf := trR - Int_To_Real(Real_To_Int(trR)) ;
Zahl_1 := REAL_TO_INT(X_Zuf * 7.0) ;
IF Zahl_1 < 0 THEN
    Zahl_1 := Zahl_1 *(-1);
END_IF
// - - - < Zufallszahl 2 bilden > - - -
trR := X_Zuf * 997.0 ;
X_Zuf := trR - Int_To_Real(Real_To_Int(trR)) ;
Zahl_2 := REAL_TO_INT(X_Zuf * 7.0) ;
IF Zahl_2 < 0 THEN
    Zahl_2 := Zahl_2 *(-1);
END_IF
// - - - < ggfs Zufallszahl 2 korrigieren > - - -
IF Zahl_1 = Zahl_2 THEN
    Zahl_2 := (Zahl_2 + 3) Mod 7 ;
END_IF ;

Wenn ich es richtig sehe, sollen hier 2 unterschiedliche Zufallszahlen zum Tauschen von 2 Plätzen im Array erzeugt werden?
Hierbei werden manchmal negative Zahlen erzeugt, für den Fall habe ich die Multiplikation mit -1 eingefügt.

Zum Beginn habe ich versucht, den Start nur für die Funktion AUF und mit fester Wartezeit auszuführen.

Code:
   TP_Pause (IN := PauseIN, PT := PauseMax) ;                        //PT noch mit zufälliger Zeit füllen
   Pause := TP_Pause.Q;
   
IF AUF_Start = TRUE THEN
    IF Y_WR = FALSE THEN                                                        // noch ändern um einmalig iAct auf 0 zu setzen
        iAct := 0;
        PauseIN := TRUE;
        Y_WR := TRUE;    
    END_IF                                                                        //
END_IF

IF iAct < 8 THEN
    CASE giA[iAct] OF
        1: Auf_1 := TRUE;
            PauseIN := TRUE;
        2: Auf_2 := TRUE;
            PauseIN := TRUE;
        3: Auf_3 := TRUE;
            PauseIN := TRUE;
        4: Auf_4 := TRUE;
            PauseIN := TRUE;
        5: Auf_5 := TRUE;
            PauseIN := TRUE;
        6: Auf_6 := TRUE;
            PauseIN := TRUE;
        7: Auf_7 := TRUE;
            PauseIN := TRUE;
    END_CASE
    PauseIN := FALSE;
    IF Pause = FALSE THEN
        iAct:= iAct + 1;
        PauseIN := TRUE;
    END_IF
ELSE 
    PauseIN := FALSE;
        AUF_1 :=FALSE;
        AUF_2 :=FALSE;
        AUF_3 :=FALSE;
        AUF_4 :=FALSE;
        AUF_5 :=FALSE;
        AUF_6 :=FALSE;
        AUF_7 :=FALSE;
    AUF_Start := FALSE;
    Y_WR := FALSE;
END_IF

Problem: zu Beginn werden 2 Aufgaben ohne Wartezeit dazwischen gestartet.
Sicherlich gibt es eine elegantere Lösung?

Wenn dieser Teil okay ist, würde ich gerne versuchen als nächsten Schritt die variable Pausenzeit einzubauen.

Einen guten Start in die neue Woche - Wolfgang
 
Zuletzt bearbeitet:
1) Die negativen Zahlen wurmen mich. Versuch bitte zunächst mal mit 2 Funktionen (ABS und TRUNC) aus der Standard-Lib:
Code:
// - - - < Zufallszahl für Index 1 zum Tauschen bilden > - - -
X_Zuf := ABS(X_Zuf * 997.0 - Int_To_Real(TRUNC(X_Zuf * 997.0))) ; // nächste ZufallsZahl
Zahl_1 := REAL_TO_INT(X_Zuf * 7.0) ;             // > 0.0 .. < 1.0 skalieren auf 0..6
// - - - < Zufallszahl für Index 2 zum Tauschen bilden > - - -
X_Zuf := ABS(X_Zuf * 997.0 - Int_To_Real(TRUNC(X_Zuf * 997.0))) ; // nächste ZufalssZahl
Zahl_2 := REAL_TO_INT(X_Zuf * 7.0) ;             // > 0.0 .. < 1.0 skalieren auf 0..6
// - - - < ggfs Zufallszahl 2 korrigieren > - - -
IF Zahl_1 = Zahl_2 THEN
    Zahl_2 := (Zahl_2 + 3) Mod 7 ;
END_IF ;
Die ZufallsZahlenBildung habe ich jetzt in einen EinZeiler geändert, ohne die temporäre ZwischenVariable - ist wahrscheinlich übersichtlicher.
TRUNC schneidet die NachKommaStellen ab. Der ErgebnisTyp soll INT sein laut Beschreibung - ich nehme es mal so hin.
ABS bildet den Betrag, d.h. eliminiert das negative Vorzeichen. Sollte für mein Verständnis überflüssig sein, aber Du hast ja schon die Erfahrung gemacht, dass das VorZeichen plötzlich negativ werden kann.
Habe eben gesehen, dass die Funktion SQRT (die Du schon verwendest) ebenfalls aus der Standard-Lib ist.

2) Nachtrag 1:
Code:
// - - - < Startwert für X_Zuf bilden > - - -
If X_Prim < 2 OR  X_Prim > 32740 Then // wenn nötig, PrimZahl 2 vorbesetzen
    X_Prim := 2 ;
Else // sonst nächstgrössere PrimZahl suchen
    Repeat
        X_Prim := X_Prim + 1 + X_Prim MOD 2 ; // +1, wenn gerade Zahl, sonst +2
        tiBis := Real_To_Int(SQRT(Int_To_Real(X_Prim))) ; // Obergrenze für zu testende Divisoren
        tbEnd := True ; // Merker: Zahl nicht restlos teilbar
        FOR tiIdx1 := 3 TO tiBis BY 2 DO
            IF X_Prim MOD tiIdx1 = 0 THEN
                tbEnd := False ; // SchleifenbAbbruch, wenn restlos teilbar
                Exit ;
            End_If ;    
        End_For ;
    Until tbEnd
    End_Repeat ;
End_If ;
trR := SQRT(Int_To_Real(X_Prim)) ; // QuadratWurzel aus PrimZahl -> NachkommaStellen!
X_Zuf := ABS(trR - Int_To_Real(TRUNC(trR))) ; // VorkommaStellen löschen
Letzte Zeile geändert - in Anlehnung an 1)! Ansonsten nur Kommentare ergänzt.

3) Nachtrag 2:
Nochmal ein paar Grundgedanken
Muss man einen Funktionsbaustein bauen? Habe doch eh schon keine Ahnung. Eigentlich möchte ich die Routine zweimal am Tag aufrufen - Rolladen AUF und AB.
So ist der Plan, FB bauen.
Ob nötig oder nicht, das wirst Du eines Tages besser beurteilen können als ich. ;)

Jetzt haben wir es so, dass die Kapitel

- Rollläden in zufälliger Reihenfolge schliessen
- Rollläden in zufälliger Reihenfolge öffnen
- die dazu erforderliche Bildung der zufälligen Reihenfolge
- die Bildung der zufälligen PausenZeiten
unter einem Hut im FB zusammengefasst sind.
Der FB wird zyklisch aufgerufen.
Er prüft, ob es etwas zu tun gibt, wo und was. Gibt es nix zu tun, so tut er auch nicht viel mehr, als eben nur zu prüfen.
Der FB wird von aussen gesteuert
- ein Bit für "Initialisierung"
- ein Bit für "nächste Array-Belegung"
- ein Bit für "alle Rollläden öffnen"
- ein Bit für "alle Rollläden schliessen"
und er steuert nach aussen die Aktionen
- "Rollladen 1 öffnen"
- "Rollladen 1 schliessen"
- u.s.w. das gleiche für die anderen 6 Rollläden.
Die Bits, die als IN_OUT oder OUTPUT deklariert sind, setzt er auch wieder zurück.
Die Bits, die als INPUT deklariert sind, darfst Du länger anstehen lassen - musst Du aber nicht, weil er nur die positiven Flanken auswertet. Aber Du musst sie auch selbst rücksetzten, bevor Du sie wieder setzen kannst, um einen neuen Auftrag auszulösen.
D.h., Du musst einiges drum herum basteln, aber das willst Du ja schliesslich auch. Du willst bestimmen, wann alle Rollläden geöffnet/geschlossen werden sollen.
Du willst bestimmen, wie Dein Rollladen auf das Kommando öffnen/schliessen reagieren soll. Der FB gibt Dir nur vor, wann welcher womit dran ist und welche Pause eingelegt wird.

Ich poste dies schon mal, damit Du nicht unnötig lange auf eine erste Reaktion warten musst ... ;)
 
Zuletzt bearbeitet:
Hallo Heinileini,

vielen Dank.

Der Compiler meckert über

Int_To_Real(TRUNC(trR)
Typ DINT kann nicht in Typ INT konvertiert werden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Der Compiler meckert über

Int_To_Real(TRUNC(trR)
Typ DINT kann nicht in Typ INT konvertiert werden.
Dann ändern wir in ...
Code:
X_Zuf := ABS(X_Zuf * 997.0 - [COLOR=#0000cd][B]Dint[/B][/COLOR]_To_Real(TRUNC(X_Zuf * 997.0))) ; // nächste ZufallsZahl
... an zwei Stellen im Programm und in ...
Code:
X_Zuf := ABS(trR - [COLOR=#0000cd][B]Dint[/B][/COLOR]_To_Real(TRUNC(trR))) ; // VorkommaStellen löschen
... an einer anderen Stelle und ...
rauchen die CodeSys-Beschreibung in der Pfeiffe:
TRUNC
Konvertierung vom Typ REAL zum Typ INT. Es wird nur der Betrag des ganzzahligen Anteils der Zahl genommen.
Da steht sowieso schon Unsinn: "der Betrag" passt schon nicht zu einem der Beispiele:
Beispiele in ST:
i:=TRUNC(1.9); (* Ergebnis ist 1 *)
i:=TRUNC(-1.4); (* Ergebnis ist -1 *) <===<<<
Ich hoffe Du findest die Stellen (ich meine die in Deinem Programm) wieder. ;)

Bitte um Rückmeldung! Die CompilerMeldung ist mir nicht wirklich klar. Vielleicht wäre Weglassen von DINT_TO_REAL noch besser? Wenn ja, warum??? :confused:
 
Zuletzt bearbeitet:
Hallo Heinileini,

Bitte um Rückmeldung! Die CompilerMeldung ist mir nicht wirklich klar. Vielleicht wäre Weglassen von DINT_TO_REAL noch besser? Wenn ja, warum??? :confused:

Dann bin ich wenigstens nicht alleine :-)

Ich hatte da schon ein wenig rumprobiert, bin mir aber nicht sicher was ich da eigentlich mache.

X_Zuf := ABS(trR - (TRUNC(trR))) ; lefert
Implizierte Konvertierung von DINT nach REAL: Möglicher Datenverlust

Den Rest probiere ich morgen, vielen Dank und gute Nacht
 
Zurück
Oben