Reihenfolge per Zufallsgenerator bestimmen

Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Heinileini,

vielen Dank.

Ja, es ist nur eine Warnung.

Ich habe den Code entsprechend geändert und getestet. Ich denke, dass alles in Ordnung ist.

Ein FB ist sicherlich die bessere Lösung. Bereitete mir aber ein Problem beim Aufruf im PLC_PRG, da alle Ein- und Ausgänge belegt werden müssen. Da ich mich aber zuerst mit dem ganzen "Zufallsgemüse" beschäftigen wollte (um wenigstens halbwegs zu verstehen, was da abläuft) habe ich den ganzen Rest weggelassen. Simulieren kann ich das dann nur in einem POU.

Nun habe ich begonnen einfach nur die Funktion AUF mit fester Zeit einzufügen. Wenn das funktioniert kommt der nächste Schritt dazu...

Am Ende können wir das gerne in einen FB packen.

Es ist sicherlich ein längerer Weg, und bequemer wäre es, einen von Dir gebauten FB zu verwenden. Aber andersherum ist der Lerneffekt größer.

In Beitrag#55 ist mein aktuelles Problem beschrieben: zu Beginn werden 2 Aufgaben gleichzeitig aufgerufen.

Ich würde mich freuen, wenn jemand diesen Fehler behebt, oder noch besser, mir zeigt, wie man diesen Teil besser und effizienter programmiert.

Ich freue mich über Kritiken und Verbesserungen.
 
... an einer anderen Stelle und ...
rauchen die CodeSys-Beschreibung in der Pfeiffe:
Hallo Heinileini

Die Hilfe ist bei Codesys sehr spezifisch.
ich nutze meistens https://help.codesys.com/
Wolfgang nutzt e!cockpit Firmware 17. Das entspricht als Basis Codesys 3.5.14. Auf der o.g.S. kann man die Version explizit einstellen.
Der IEC-Operator dient der Konvertierung vom Typ REAL zum Typ DINT. CODESYS nimmt nur den ganzzahligen Anteil der Zahl.

Code:
X_Zuf := ABS(trR - (TRUNC(trR))) ;
X_Zuf := ABS(trR - DINT_TO_REAL(TRUNC(trR))) ; // VorkommaStellen löschen
Das die erste Zeile eine Warnung wirft ist erstmal völlig i.o. Die 2. Zeile läuft ohne Anmerkung des Compilers durch.

Holger
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

nur mal nebenbei

Der IEC-Operator dient der Konvertierung vom Typ REAL zum Typ DINT. CODESYS nimmt nur den ganzzahligen Anteil der Zahl.

diVar := TRUNC (-1.4) ; (* Result: -1 *)


Das Ergebnis enthält aber den ganzzahligen Teil mit dem Vorzeichen, und nicht nur den ganzzahligen Anteil der Zahl.


Der von Heinileini geänderte Code ist okay.
 
In Beitrag#55 ist mein aktuelles Problem beschrieben: zu Beginn werden 2 Aufgaben gleichzeitig aufgerufen.
Während die PausenZeit läuft, muss der "AufgabenVerteiler" stillgelegt, also nicht durchlaufen werden.
IF NOT Pause THEN
... "AufgabenVerteiler" ...
END_IF ;

@Holger
Danke! Offensichtlich (zumindest in Deinem Link) wurde TRUNC geändert von INT in DINT und die Beschreibung korrigiert, was den "Betrag" betrifft (jetzt "ganzzahliger Anteil").

Gruss, Heinileini
 
Hallo Heinileini,

Dein Code zur Abarbeitung der Aufgaben ist sicherlich strukturierter programmiert als meine Ansätze, aber ich habe ihn nicht ans Laufen bekommen. Warum auch immer. Daher habe ich mir Gedanken gemacht und nach einer Lösung gesucht.
Dieser Ansatz funktioniert nun, daher möchte ich gerne darauf aufbauen und die weiteren Schritte zufügen. Mir fällt es so leichter den Ablauf zu verstehen.

Das ist mein Ansatz für AUF mit zufälliger Pausenzeit:
Code:
IF AUF_Start = TRUE THEN                                                    // nur für Test
    IF Y_WR = FALSE THEN                                                        // nur für Test
        iAct := 0;
        PauseIN := TRUE;
        Y_WR := TRUE;    
    END_IF                                                                        //
END_IF

   TP_Pause (IN := PauseIN, PT := PausePT) ;            
   Pause := TP_Pause.Q;
   
IF iAct < 7 THEN
    IF Pause = FALSE 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        
    END_IF
    PauseIN := FALSE;
    IF Pause = FALSE THEN
        Y_Startwert := FALSE;                                                            //Funktion für Zafallszahl stoppen und anschließend Pausenzeit berechnen
        PausePT := REAL_TO_TIME((X_Zuf * TIME_TO_REAL(PauseMax - PauseMin)) + TIME_TO_REAL(PauseMin)) ;  // Wartezeit in ms
        iAct:= iAct + 1;
        PauseIN := TRUE;
        Y_Startwert := TRUE;                                                                //Funktion für Zufallszahl starten
    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;                                                                    //nur zum Test, später anpassen
    Y_WR := FALSE;                                                                            //nur zum Test, später anpassen
    Y_Startwert := FALSE;                                                    
END_IF

Nein, an mir ist sicherlich kein Programmierer verloren gegangen. Daher möchte ich Euch bitten, diesen Code zu verbessern, oder mir zu zeigen, wie man dies richtig macht.

Im Voraus vielen Dank für Eure Hilfe
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin Wolfgang,

habe jetzt alles komplett (hoffentlich!?) im FB zusammengeschrieben und auch zaghaft versucht, auf Deine VariablenNamen zu ändern (letzteres aber wieder abgebrochen, um DoppeltGemoppeltes zu vermeiden).
Der FB sollte jetzt selbständig in der Lage sein, ...
- die Initialisierung und
- die nächste ArrayBelegung
anzuleiern.
Wenn diese beiden Aktionen auch noch bzw. nicht mehr von extern (über die Inputs) gestartet werden sollen: siehe Zeilen mit '(optional)' im Kommentar.

Das Thema 'globale Variablen' ist jetzt vom Tisch. Sollte jetzt so funktionieren, wenn nur noch der FB darauf zugreift.

Verzeih mir, wenn ich nicht auf Deine Bitte eingegangen bin, aber ich blicke auch schon so doch kaum noch durch! ;)

Gruss, Heinileini
Code:
FUNCTION_BLOCK UpsAndDowns

    TOF_Pause     : TOF  ; // Timer für (variable) Pausenzeit

VAR_INPUT
    ibInit        : BOOL ; // pos. Flanke: Initialisierung des ZufallszahlenGenerators und des Array (optional)
    ibNext        : BOOL ; // pos. Flanke: nächste ArrayBelegung (optional)
    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 : ARRAY[0..6] OF INT; // Array mit 7 zufällig angeordneten Zahlen 1..7
    X_Zuf         : REAL ; // 0.0 < ZufallsZahl < 1.0
    X_Prim        : INT  ; // Primzahl 2..32749
    iAct          : INT := 8 ; // 0..6: Index für giA[]; 7: letzte Aufgabe der Sequenz; 8: Sequenz beendet
    trR           : REAL ; // temporär
    bTimerIN      : BOOL ; // StartImpuls für Pausen-TOF 
    sbInitAut     : BOOL ; // FlankenMerker automatische Initialisierung  
    sbNextAut     : BOOL ; // FlankenMerker automatische nächste ArrayBelegung 
    sbInitPre     : BOOL ; // FlankenMerker Initialisierung von extern (optional)
    sbNextPre     : BOOL ; // FlankenMerker nächste ArrayBelegung von extern (optional)
    tiTmp         : INT  ; // temporär 
    tiIdx1        : INT  ; // temporär
    tiIdx2        : INT  ; // temporär
    tTimerPT      : TIME ; // Dauer für Pausen-TOF im Bereich laut itMin .. itMax (z.B. 60..300 s)
END_VAR

// Prüfung, ob "AUF" und "ZU" gleichzeitg. Wenn ja, dann "AUF" löschen
iobBlindsUp := iobBlindsUp AND NOT iobBlindsDown ; 
// Prüfung, ob Init erforderlich
If X_Prim < 2 OR X_Prim > 32740 OR giA[0] = 0 OR X_Zuf <= 0.0 OR X_Zuf >= 1.0 Then 
    sbInitAut := FALSE ;
END_IF ;  
// = = = = = < Initialisierung ZufallsZahl und Array > = = = = =
// IF (iobBlindsUp OR iobBlindsDown) AND NOT sbInitAut OR ibInit AND NOT sbInitPre THEN 
IF (iobBlindsUp OR iobBlindsDown) AND NOT sbInitAut THEN 
    // - - - < 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 X_Zuf bilden > - - -
    If X_Prim < 2 OR X_Prim > 32740 Then // X_Prim im gültigen Bereich?
        X_Prim := 2 ; // nein: mit Primzahl 2 vorbesetzen
    Else
        Repeat // ja: nächste Primzahl suchen
            X_Prim := X_Prim + 1 + X_Prim MOD 2 ; // +1 wenn gerade, sonst +2
            tiBis := DINT_TO_INT(TRUNC(SQRT(Int_To_Real(X_Prim)))) ; // Obergrenze für möglichen Faktor festlegen
            tbEnd := True ;
            For tiIdx1 := 3 To tiBis By 2 Do
                If X_Prim Mod tiIdx1 = 0 Then 
                    tbEnd := False ;
                    Exit ; // Prüfung abbrechen, wenn restlos teilbar
                End_If ;     
            End_For ;
        Until tbEnd
        End_Repeat ; // Suche beenden, wenn nicht restlos teilbar
    End_If ;
    trR := SQRT(Int_To_Real(X_Prim)) ; // Wurzel aus Primzahl - gebraucht werden die Nachkommastellen
    X_Zuf := ABS(trR - DINT_TO_REAL(TRUNC(trR))) ; // Vorkommastellen löschen
    sbInitAut := TRUE ;
END_IF ;  
sbInitPre := ibInit ; // FlankenMerker (optional)
// = = = = = < Ende der Initialisierung von ZufallsZahl und Array > = = = = =

// = = = = = < Array-Shuffle > = = = = =
// IF (iobBlindsUp OR iobBlindsDown) AND NOT sbNextAut OR ibNext AND NOT sbNextPre THEN // (optional)
IF (iobBlindsUp OR iobBlindsDown) AND NOT sbNextAut THEN
    // - - - < Array rotieren > - - -
    tiTmp:= giA[0] ;
    For tiIdx1 := 0 To 5 Do
        giA[tiIdx1] := giA[tiIdx1 + 1] ;
    End_For ;
    giA[6] := tiTmp ;
    
    // - - - < Idx1 bilden > - - -
    X_Zuf := ABS(X_Zuf * 997.0 - Dint_To_Real(TRUNC(X_Zuf * 997.0))) ; // nächste ZufallsZahl, Vorkommastellen löschen
    tiIdx1 := Real_To_Int(X_Zuf * 7.0) ; // sklaieren in den Bereich 0..6
    
    // - - - < Idx2 bilden > - - -
    X_Zuf := ABS(X_Zuf * 997.0 - Dint_To_Real(TRUNC(X_Zuf * 997.0))) ; // nächste ZufallsZahl, Vorkommastellen löschen
    tiIdx2 := Real_To_Int(X_Zuf * 7.0) ; // sklaieren in den Bereich 0..6
    
    // - - - < ggfs Idx2 korrigieren > - - -
    If tiIdx1 = tiIdx2 Then 
        tiIdx2 := (tiIdx2 + 3) Mod 7 ;
    End_If ;
    
    // - - - < 2 zufällig festgelegte Elemente des Array tauschen > - - -
    tiTmp:= giA[tiIdx1] ; 
    giA[tiIdx1] := giA[tiIdx2] ;
    giA[tiIdx2] := tiTmp ;
END_IF ; 
sbNextPre := ibNext ; // FlankenMerker (optional)
sbNextAut := iobBlindsUp OR iobBlindsDown ; // FlankenMerker
// = = = = = < Ende von Array-Shuffle > = = = = =

// = = = = = < Rollläden und Pausen steuern > = = = = =
    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 TOF_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 
                X_Zuf := ABS(X_Zuf * 997.0 - DINT_TO_REAL(TRUNC(X_Zuf * 997.0))) ; // neue ZufallsZahl, Vorkommastellen löschen
                tTimerPT := REAL_TO_TIME((X_Zuf * TIME_TO_REAL(itMax - itMin)) + TIME_TO_REAL(itMin)) ; // skalieren, Wartezeit in ms
            END_IF ;
        END_IF ;
        iAct := iAct + 1 ; // ... und Vorlage der nächsten Aufgabe vorbereiten
    END_IF ;

    TOF_Pause (IN := bTimerIN, PT := tTimerPT) ; // Pausen-Timer
    bTimerIN := FALSE ; // TimerStart rücksetzen
    IF iAct > 7 THEN // wenn Sequenz komplett durchlaufen, dann AuftragsMerker rücksetzen ;
        iobBlindsUp := FALSE ; iobBlindsDown := FALSE ; sbNextAut := FALSE ;
    END_IF ;
// = = = = = < Ende von Rollläden und Pausen steuern > = = = = =
END_FUNCTION_BLOCK
 
Zuletzt bearbeitet:
Hallo Heinileini,

Verzeih mir, wenn ich nicht auf Deine Bitte eingegangen bin, aber ich blicke auch schon so doch kaum noch durch! ;)

Nein, das verzeihe ich nicht :-)
Wenn Du angeblich kaum noch durchblickst, was soll ich dann sagen?

Nun gut, ich gebe mich geschlagen und habe es ausprobiert - im Prinzip läufts. Ich habe es einige Male AUF und AB laufen lassen. Dabei sind zwei mal doppelte Zahlen im Array aufgetaucht. Werde mir das morgen noch in Ruhe anschauen. Brauche mal wieder eine Weile, bis ich den Ablauf durchschaue.

Vielen lieben Dank für Deine Hilfe und noch einen schönen Abend

PS Danke für die vielen Kommentare :-)
@ Mache Dir bitte keine Mühe, ich teste alles nochmal in aller Ruhe.
 
Zuletzt bearbeitet:
Hallo Heinileini,

hier mein Update:

Beim Start des FB wird das Array nicht korrekt gefüllt. Statt der 5 enthält es immer die Zahl 8182.
Vermutlich ist der Code < 2 zufällig festgelegte Elemente des Array tauschen > die Ursache. Wenn ich ihn auskommentiere ist das Array korrekt gefüllt.

Force ich die Zahl 8182 im Array auf 5 funktioniert der FB eine ganze Weile. Dann taucht im Array mal eine Zahl auf, die nicht korrekt ist. Zum Beispiel -14702
Auch hier vermute ich den Fehler im Code < 2 zufällig festgelegte Elemente des Array tauschen >
tiTmp hat dann den Wert -14702

Wenn ich alles richtig deute, wurde für tidx2 die gleiche Zahl wie für tidx1 gebildet und das Tauschen schon während der Erzeugung der Ersatzzahl für tidx2 ausgeführt. Bin mir dabei aber nicht sicher.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin Wolfgang,
leider kann ich bisher nicht viel Verdächtiges finden.
- 2 Tippfehler im Kommentar (sklaieren statt skalieren)
- 2 Stellen, an denen 'tiTmp :=' stehen sollte und das Leerzeichen vor dem ':=' fehlt
Wie der Compiler auf die fehlenden Leerzeichen reagiert, weiss ich nicht. Füg sie bitte ein.
Ansonsten bitte auch mal darauf achten, ob ...
- 'X_Zuf' jetzt wirklich immer nur positive Werte im Bereich >0.0 .. <1.0 enthält und
- 'tiIdx1' und 'tiIdx2' immer nur positive Werte im Bereich 0..6 enthalten.
 
Hallo Heinileini,

Leerzeichen vor oder nach dem ':=' scheinen egal zu sein, lediglich ein Leerzeichen zwischen dem Doppelpunkt und dem Gleichheitszeichen erzeugt Fehler.
Ich habe die Leerstellen an den angesprochenen Stellen eingefügt.

Um ganz sicher zu sein, dass nichts von mir eingefügtes Fehler verursacht. In PLC_PRG habe ich am Baustein bei iobBlindsDown als Eingang die globale Variable Merker.Start_AB und bei iobBlindsUp die globale Variable Merker.Start_AUF eingetragen.

Den Baustein prüfe ich mit "Applikation simulieren". Dort habe ich die beiden Merker am Anfang des Code eingetragen und und Force sie auf True um die Funktion zu starten.

Die Fehlerbeschreibung habe ich in Beitrag#68 beschrieben.

Ich bin mir nicht sicher, ob meine Annahme richtig ist. Das Programm arbeitet den Code doch einmal durch, setzt am Ende alle Variablen und läuft dann den Code erneut durch usw.
Wenn ich es richtig beobachte, gibt es keine Fehler wenn ich < 2 zufällig festgelegte Elemente des Array tauschen > auskommentiere, dann wird auch zu Beginn das Array korrekt gefüllt.

Wenn ich die Auskommentierung entferne sieht es so aus, als wenn immer nur dann ein Fehler auftritt, wenn die zweite Zufallszahl erneut gebildet wird und beim Tauschen noch nicht erzeugt ist.

Eventuell bin ich hier aber auch total auf dem Holzweg.
 
... sieht es so aus, als wenn immer nur dann ein Fehler auftritt, wenn die zweite Zufallszahl erneut gebildet wird und beim Tauschen noch nicht erzeugt ist.
Es beruhigt mich, dass das "fehlende Leerzeichen" nichts mit dem Spuk zu tun hat - das hätte mich nicht nur sehr gewundert, sondern derbe schockiert. :ROFLMAO:
Aber, dass der Index noch umgebogen wird, während mit seiner Hilfe bereits der Tauschvorgang ausgeführt wird ... irgendwie überschreitet das mein VorstellungsVermögen.
Wir sind doch hier mit PLC-Programmierung zugange, nicht mit NC-Programmierung!? ;)
An der Simulation wird es doch wohl nicht liegen.
Und was passiert, wenn - allen Erwartungen zum Trotz - bei der Adressierung des Array mit einem Index <0 oder >6 ins Leere gegriffen wird? Flippt die Steuerung bzw. die Simulation aus oder gibt's ne FehlerMeldung?

Sorry, mir fällt nichts mehr ein. Bitte weiterhin X_Zuf und die beiden Indizes tiIdx1 & tiIdx2 im Auge behalten, wie schon zuvor gesagt.

Grübel, grübel ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Heinileini,

Grübel bitte nicht zuviel :-)

Wir sind doch hier mit PLC-Programmierung zugange, nicht mit NC-Programmierung!?
Keine Ahnung, was ist der Unterschied?

An der Simulation wird es doch wohl nicht liegen.

Ich werde das Programm mal auf die SPS laden und dort testen. Dazu brauche ich aber ein wenig Zeit. Ich melde mich, wenn ich das ausprobiert habe.

Und was passiert, wenn - allen Erwartungen zum Trotz - bei der Adressierung des Array mit einem Index <0 oder >6 ins Leere gegriffen wird? Flippt die Steuerung bzw. die Simulation aus oder gibt's ne FehlerMeldung?

Wenn ich es richtig beobachtet habe, wird das letzte Array (7) anstelle des falschen Wertes aufgerufen. Die ganze Prozedur läuft aber bis zum Ende durch. Ich achte nochmal genau darauf.

Ich bin mir nicht sicher, ob meine Annahme richtig ist. Das Programm arbeitet den Code doch einmal durch, setzt am Ende alle Variablen und läuft dann den Code erneut durch usw.

Ist das richtig?
 
1. Keine Ahnung, was ist der Unterschied?

2. Wenn ich es richtig beobachtet habe, wird das letzte Array (7) anstelle des falschen Wertes aufgerufen.

3. Die ganze Prozedur läuft aber bis zum Ende durch. Ich achte nochmal genau darauf.
Ist das richtig?
Zu 1.:
Bei PLC-Programmen kann man sich darauf verlassen, dass die Befehle immer schön "der Reihe nach" abgearbeitet werden, so, wie man es erwartet.
Ausnahmen sind, wenn ein Ablauf durch einen anderen unterbrochen wird, z.B. durch einen ZeitAlarm. Dann sollte aber, sobald der Alarm ("Interrupt") abgearbeitet ist, das Programm sauber ab der Stelle weiter ausgeführt werden, an der es unterbrochen wurde.
Bei NC-Programmen ist es so, dass mehrere folgende Befehle schon parallel in Angriff genommen werden, weil die NC-Befehle in ihrer Auswirkung z.T. nahtlos ineinander übergehen müssen, also die Ausführung im Detail davon abhängig ist, wie es anschliessend weitergehen soll. Z.B. die Fahrt in X-Richtung abbremsen und dann die Fahrt in Y-Richtung starten, ggfs mit "Verrunden" der Ecke.
Das kann zu Überraschungen führen, dadurch dass z.B. bereits mit Werten gerechnet wird, die im ProgrammAblauf aber erst später festgelegt werden. Aber vergessen wir diesen Blick über den Tellerrand ganz schnell wieder, solange wir in der PLC arbeiten und keine "parallel" laufenden Tasks haben.

Zu 2.:
"das letzte Array (7)"? Eigentlich haben wir ein Array [0..6]!

Zu 3.:
Ja, die Prozedur wird in jedem Zyklus komplett durchlaufen. Komplett heisst von Anfang bis Ende, aber natürlich nur diejenigen Abschnitte, die nicht übersprungen werden (wegen IF oder CASE oder WHILE oder EXIT).
 
Hallo Heinileini,

Okay, keine klare Aussage von mir.
Array [0 ... 6] mit Inhalt (1 ... 7) in gemischter Reihenfolge. Bei einem Fehler steht, wie zum Beispiel beim ersten Starten statt der 5 die 8182 als Inhalt im Array.
In der Case-Anweisung werden diese aufgerufen, dabei wird statt AUF_5 oder AB_5 die 7 ausgeführt. Alles läuft dann weiter, bis iAct 7 ist. Danach ist ein neuer Start nötig.

Ich habe das Programm allerdings noch nicht in der SPS getestet.

Bringt es etwas, wenn man das Bilden der 2 Zahlen in einer If-Schleife ausführt und erst danach das Tauschen zum Ende mit iAct = 7 ausführt?
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Heinileini,

mal eine Anmerkung

Code:
    tiTmp := giA[Zuf_1] ; 
    giA[Zuf_1] := giA[Zuf_2] ;
    giA[Zuf_2] := tiTmp ;

Wird hier nicht auf einen Bereich des Arrays [ 0 ... 6 ] mit einer Zufallszahl ( Zuf_1 oder Zuf_2 ) zugegriffen, die Werte zwischen 1 ... 7 annehmen können?

Ist nur so eine Vermutung, eventuell bin ich aber auch auf dem Holzweg.

Habe es immer noch nicht in der Steuerung probieren können.
 
Wird hier nicht auf einen Bereich des Arrays [ 0 ... 6 ] mit einer Zufallszahl ( Zuf_1 oder Zuf_2 ) zugegriffen, die Werte zwischen 1 ... 7 annehmen können?
Du bist genial, Wolfgang, bitte in den beiden Zeilen 7.0 ändern in 6.0 !
Code:
    tiIdx1 := Real_To_Int(X_Zuf * 7.0) ; // skalieren in den Bereich 0..6
Code:
    tiIdx2 := Real_To_Int(X_Zuf * 7.0) ; // skalieren in den Bereich 0..6
Sorry, der Real_to_Int rundet doch - wie oft habe ich jetzt schon darüber hinweg gelesen :oops:

Aus lauter Verzweiflung wollte ich schon vorschlagen, in der VAR-Deklaration diverses zu initialisieren, aber ...
Alle Variablendeklarationen und Datentypelemente können Initialisierungen (Zuweisung eines
initialen Wertes) enthalten. Sie erfolgen mit dem Zuweisungsoperator " := ". Für Variablen von
elementaren Typen sind diese Initialisierungen Konstanten. Die Default-Initialisierung ist für alle
Deklarationen 0.
... sollte eigentlich genügen.
 
Hallo Heinileini,

die beiden Zeilen habe ich geändert. Jetzt funktionierts.

Ein blindes Huhn findet auch mal ein Korn :-)
Aber wenn es hilft, dass der Erstklässler jetzt in die zweite Klasse darf...

Ich hoffe, dass ich morgen alles ins Programm integrieren kann.

Nochmal vielen lieben Dank für Deine Mühe und Geduld.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Heinileini,

den FB habe ich ins Programm integriert und auf die Steuerung geladen. Es sieht so aus, als ob alles funktioniert.

Nun habe ich noch Fragen zu

Code:
    sbInitAut : BOOL ; // FlankenMerker automatische Initialisierung  
    sbNextAut : BOOL ; // FlankenMerker automatische nächste ArrayBelegung 
    sbInitPre  : BOOL ; // FlankenMerker Initialisierung von extern (optional)
    sbNextPre : BOOL ; // FlankenMerker nächste ArrayBelegung von extern (optional)

Wofür sind die Variablen gut?
Wieso Flankenmerker, müssten Sie dann nicht als Datentyp R_TRIG deklariert sein?
Werden sie überhaupt benötigt?

Code:
VAR_IN_OUT
    Start_AB : BOOL ; // Startet Sequenz "Rollläden in zufälliger Reihenfolge schliessen"
    Start_AUF : BOOL ; // Startet Sequenz "Rollläden in zufälliger Reihenfolge öffnen"
END_VAR

Wieso IN_OUT, werden sie nicht nur zum Starten der Sequenz benötigt, also nur als IN?
 
1. Wofür sind die Variablen gut?
Wieso Flankenmerker, müssten Sie dann nicht als Datentyp R_TRIG deklariert sein?
Werden sie überhaupt benötigt?

2. Wieso IN_OUT, werden sie nicht nur zum Starten der Sequenz benötigt, also nur als IN?
Moin Wolfgang.

Zu 1.:
Ist denn R_TRIG ein eigener DatenTyp?
Die "FlankenMerker" benutze ich für die selbstgestrickten (bin so altmodisch!) FlankenErkennungen. Darin werden die Zustände für den Vergleich mit den aktuellen Zuständen im nächsten Zyklus gespeichert.
Der Begriff "FlankenMerker" sagt übrigens nicht aus, dass man hierfür Merker benutzen muss, sondern nur, dass sie sich etwas merken müssen. ;)

Natürlich darfst Du zur FlankenErkennung wahlweise die von der ProgrammierSprache bereitgestellten HilfsMittel benutzen, aber erst dann, wenn Du verstanden hast, wie eine FlankenErkennung funktioniert.
Jawoll, dies eine Drohung! :ROFLMAO:
Du brauchst Dich nur in den Beiträgen hier im Forum umzusehen - die FlankenErkennung bzw. der Umgang mit den angebotenen vermeintlichen Vereinfachungen ist leider ein DauerBrenner.

Zu 2.:
Diese VAR_IN_OUTs dienen als Schnittstelle zum "Drumherum". Sie werden einerseits vom FB abgefragt, ob's Arbeit gibt und andererseits vom FB zurückgesetzt, wenn die Arbeit erledigt ist.
Immerhin dauert es ja eine Weile, bis die 7 RollladenAktionen mit ihren anschliessenden Pausen fertig sind.
Somit kannst Du im "Drumherum" die entsprechenden Bits abfragen, mit denen Du den FB parametriert hast, um zu erfahren ob/wann die gestartete Prozedur beendet ist und Du brauchst Dir auch keinen Kopf zu machen, wann der richtige Moment gekommen ist, diese Bits wieder zu löschen.

Ein schönes RestWochenEnde wünscht Dir Heinileini

PS:
Nachtrag zu 1.: Natürlich werden sie benötigt. Die Aktionen "Initialisieren" und "nächste ArrayBelegung festlegen" sollen nur einmalig ausgeführt werden, wenn man sie startet.
Stell Dir vor, während eine der Aktionen "Rollläden öffnen" oder "Rollläden schliessen" aktiv ist, würde ständig der Inhalt des Array weiter durcheinandergewirbelt ... wie willst Du dann sicherstellen, dass auch alle 7 Rollläden geöffnet bzw. geschlossen werden? "MomentAufnahme" machen und mit einer Kopie des Array arbeiten, die gar nicht nötig ist?
 
Zuletzt bearbeitet:
Hallo Heinileini,

zu 1.) zumindest werden 2 Bausteine angeboten.

Bevorzugt verwende ich FUP, und dort ganz gerne die an den Eingängen angebotene Flankenerkennung. Diese Version kannte ich aus meiner Programmiererei an der alten SPS noch nicht.

So richtig verstanden habe ich die Flankenerkennung sicherlich nicht, denn ich werde immer mal wieder überrascht, dass etwas nicht so funktioniert, wie ich das erwarte.
Kennst Du gute Tutorials die ich durchackern könnte?

Auch Dir noch einen schönen Sonntag
 
Zurück
Oben