Vorstellung und erste Frage Umschalter/Vergleicher 1-Byte-Werte

pauly2072

Level-1
Beiträge
31
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

da dies mein erster Beitrag in diesem Forum ist, möchte ich mich kurz vorstellen: Ich bin freiberuflicher Projektleiter in der Industrie und - als zweites Standbein - Systemintegrator für Home-Automation auf KNX-Basis. Ich habe auch einige Erfahrung mit dem Gira Homeserver, möchte aber nun verschiedene Aufgaben mittels des Wago 750-849 Feldbuscontrollers lösen und bin daher gerade (ganz am Anfang) dabei, mich mit der Codesys-Programmierung zu befassen. Die Schnittstellen KNX/WAGO habe ich soweit am Laufen.

Folgende Funktion habe ich mit dem Homeserver zwar schon erfolgreich realisiert, möchte sie jedoch nun auch mithilfe des Wago-
Feldbuscontrollers durchführen:

Eine Spindeltreppe über zwei Stockwerke hat 26 Stufen. Unter jeder Stufe ist ein 24V-LED-Stripe (nur weiß) angebracht. Jedes Stripe wird
über einen separaten Kanal angesteuert (Barthelme DMX Controller 66000424). Der DMX-Bus wird mittels des LAN Stage-Profi und des Wago-
Bausteins FbDMX_StageProfi angesteuert.

Ca. 80 cm über jeder Stufe ist ein Lichttaster installiert. Mittels der Lichttastersignale (auf Wago-DI-Karten) soll die Stufenbeleuchtung mit der Bewegung des 'Treppenbenutzers' mitwandern: 100% an der Stufe der aktuellen Position der Person und ein paar Stufen ober- und unterhalb der Person jeweils abnehmende Dimmwerte. Die jeweiligen Dimmwerte werden fix parametriert.

D.h. jedem Lichttaster werden die entsprechenden fixen Dimmwerte (0-255) zugeordnet, die bei Belegung des Lichttasters über den DMX-Bus an die jeweiligen Stufen-Stripes ausgegeben werden. Da aber von Personen mit etwas imposanteren Maßen auch mal zwei Lichttaster gleichzeitig belegt werden können, oder sich auch mal mehr als eine Person auf der Treppe befinden können, sollen die von dann mehreren Lichttastersignalen initiierten Dimm-Bytes verglichen und dann der jeweilig höchste Wert auf den DMX-Bus geschickt werden.

Z.B.:

Lichttaster 4 (Treppenstufe 4) ist belegt. Es werden folgende Dimm-Fixwerte an einen 'Vergleicher' geschickt:

Stufe 7 = DMX-Byte 4.7 = 10%
Stufe 6 = DMX-Byte 4.6 = 30%
Stufe 5 = DMX-Byte 4.5 = 70%
Stufe 4 = DMX-Byte 4.4 = 100%
Stufe 3 = DMX-Byte 4.3 = 70%
Stufe 2 = DMX-Byte 4.2 = 30%
Stufe 1 = DMX-Byte 4.1 = 10%
alle anderen Stufen = 0%

Soweit, so gut.

Gleichzeitig ist Lichttaster 9 (Treppenstufe 9) belegt. Es werden also die folgende Dimm-Fixwerte an den 'Vergleicher' geschickt:

Stufe 12 = DMX-Byte 9.12 = 10%
Stufe 11 = DMX-Byte 9.11 = 30%
Stufe 10 = DMX-Byte 9.10 = 70%
Stufe 9 = DMX-Byte 9.9 = 100%
Stufe 8 = DMX-Byte 9.8 = 70%
Stufe 7 = DMX-Byte 9.7 = 30%
Stufe 6 = DMX-Byte 9.6 = 10%
alle anderen Stufen = 0%

Der 'Vergleicher' vergleicht ;) und schickt das jeweils das Byte mit dem höheren Wert auf den DMX-Bus:

wenn DMX-Byte 4.1 > DMX-Byte 9.1 dann DMX-Byte 4.1 als Byte 1 auf den DMX-Bus, ansonsten DMX-Byte 9.1 als Byte 1 auf den DMX-Bus
wenn DMX-Byte 4.2 > DMX-Byte 9.2 dann DMX-Byte 4.2 als Byte 1 auf den DMX-Bus, ansonsten DMX-Byte 9.2 als Byte 1 auf den DMX-Bus
.
.
.
wenn DMX-Byte 4.12 > DMX-Byte 9.12 dann DMX-Byte 4.12 als Byte 1 auf den DMX-Bus, ansonsten DMX-Byte 9.12 als Byte 1 auf den DMX-Bus
wenn DMX-Byte 4.13 > DMX-Byte 9.13 dann DMX-Byte 4.13 als Byte 1 auf den DMX-Bus, ansonsten DMX-Byte 9.13 als Byte 1 auf den DMX-Bus

D.h. für obiges Beispiel:

Stufe 13 = DMX-Byte 13 = 0%
Stufe 12 = DMX-Byte 12 = 10%
Stufe 11 = DMX-Byte 11 = 30%
Stufe 10 = DMX-Byte 11 = 70%
Stufe 9 = DMX-Byte 9 = 100%
Stufe 8 = DMX-Byte 8 = 70%
Stufe 7 = DMX-Byte 7 = 30%
Stufe 6 = DMX-Byte 6 = 30%
Stufe 5 = DMX-Byte 5 = 70%
Stufe 4 = DMX-Byte 4 = 100%
Stufe 3 = DMX-Byte 3 = 70%
Stufe 2 = DMX-Byte 2 = 30%
Stufe 1 = DMX-Byte 1 = 10%

Also insgesamt für 26 Lichttastersignale, 16 Dimm-Fixwerte und 26 Ausgabebytes auf den DMX-Bus.

Nun erwarte ich von Euch sicher keine Lösung auf dem berühmten Silbertablett, aber für eine Hilfe bei dem folgenden Schritt wäre ich echt dankbar (idealerweise in CFC): Wie realisiere ich quasi einen Schalterbaustein, der mir je nach Zustand eines bool'schen Einganges E1 (Lichttastersignal) einen 1-Byte-Wert (Dimm-Fixwert) auf einen Ausgang/Variable A1 durchschaltet (bei E1 = TRUE) und bei E1 = FALSE ein 1-Byte-Signal mit dem Wert 0 durchschaltet (bzw. zum 'Vergleicher' gibt). Das sollte eigentlich eine Standardlösung sein, aber offensichtlich seh ich den Wald vor lauter Bäumen nicht...

Auch genial wäre ein Tipp, wie ich diesen 'Vergleicher' angehe. So ein Baustein mit mindestens 16 1-Byte-Eingängen, der mir am Ausgang das Byte mit dem höchsten Wert ausgibt, wäre schon was feines... ;)

So, nun hoffe ich, dass es jemand beim Lesen bis hierher geschafft hat, und ich verspreche, dass mein nächster Beitrag (besser meine nächste Frage ;)) etwas kürzer ausfallen wird...

Ich hab auch mal zwei Screenshots von meiner Lösung mit dem Gira Homeserver angehängt.

Anhang anzeigen Ausgabe Dimmwerte an Vergleicher HS 4.pdfAnhang anzeigen Vergleich Byte 1 HS 4.pdf

Vielen Dank im Voraus

Peter
 
wenn DMX-Byte 4.1 > DMX-Byte 9.1 dann DMX-Byte 4.1 als Byte 1 auf den DMX-Bus, ansonsten DMX-Byte 9.1 als Byte 1 auf den DMX-Bus
wenn DMX-Byte 4.2 > DMX-Byte 9.2 dann DMX-Byte 4.2 als Byte 1 auf den DMX-Bus, ansonsten DMX-Byte 9.2 als Byte 1 auf den DMX-Bus
.
.
.
wenn DMX-Byte 4.12 > DMX-Byte 9.12 dann DMX-Byte 4.12 als Byte 1 auf den DMX-Bus, ansonsten DMX-Byte 9.12 als Byte 1 auf den DMX-Bus
wenn DMX-Byte 4.13 > DMX-Byte 9.13 dann DMX-Byte 4.13 als Byte 1 auf den DMX-Bus, ansonsten DMX-Byte 9.13 als Byte 1 auf den DMX-Bus

...und copy and paste kann er auch nicht... :oops:

So ist es besser:

wenn DMX-Byte 4.1 > DMX-Byte 9.1 dann DMX-Byte 4.1 als Byte 1 auf den DMX-Bus, ansonsten DMX-Byte 9.1 als Byte 1 auf den DMX-Bus
wenn DMX-Byte 4.2 > DMX-Byte 9.2 dann DMX-Byte 4.2 als Byte 2 auf den DMX-Bus, ansonsten DMX-Byte 9.2 als Byte 2 auf den DMX-Bus
.
.
.
wenn DMX-Byte 4.12 > DMX-Byte 9.12 dann DMX-Byte 4.12 als Byte 12 auf den DMX-Bus, ansonsten DMX-Byte 9.12 als Byte 12 auf den DMX-Bus
wenn DMX-Byte 4.13 > DMX-Byte 9.13 dann DMX-Byte 4.13 als Byte 13 auf den DMX-Bus, ansonsten DMX-Byte 9.13 als Byte 13 auf den DMX-Bus
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wie realisiere ich quasi einen Schalterbaustein, der mir je nach Zustand eines bool'schen Einganges E1 (Lichttastersignal) einen 1-Byte-Wert (Dimm-Fixwert) auf einen Ausgang/Variable A1 durchschaltet (bei E1 = TRUE) und bei E1 = FALSE ein 1-Byte-Signal mit dem Wert 0 durchschaltet (bzw. zum 'Vergleicher' gibt). Das sollte eigentlich eine Standardlösung sein, aber offensichtlich seh ich den Wald vor lauter Bäumen nicht...

Lesen bildet. Ich glaube SEL ist keine schlechte 'Wahl'... ;)
 
Ich würde das in ST machen und in einer Schleife.

Als Input ein Array aus 26 Bool (Lichttaster).
Als INOUT ein Array aus 26 Byte (Ausgabe).

Zuerst eine Schleife (1-26), die das Array Ausgabe mit 0 belegt.
Danach eine Schleife (1-26), die den jeweils zum Index gehörenden Lichttaster auf "True/False" prüft.

Ist er "False", weiter zum nächsten Schleifendurchlauf.

Ist er "True", dann:

1. den zum Index gehörenden Ausgabewert auf 100 setzen,
2. Index -1 auf > 0 prüfen, wenn ja, dann prüfen ob Ausgabewert < 70, wenn ja dann auf 70 setzen
3. Index -2 auf > 0 prüfen, wenn ja, dann prüfen ob Ausgabewert < 30, wenn ja dann auf 30 setzen
4. Index -3 auf > 0 prüfen, wenn ja, dann prüfen ob Ausgabewert < 10, wenn ja dann auf 10 setzen
5. Index +1 auf < 27 prüfen, wenn ja, dann prüfen ob Ausgabewert < 70, wenn ja dann auf 70 setzen
6. Index +2 auf < 27 prüfen, wenn ja, dann prüfen ob Ausgabewert < 30, wenn ja dann auf 30 setzen
7. Index +3 auf < 27 prüfen, wenn ja, dann prüfen ob Ausgabewert < 10, wenn ja dann auf 10 setzen

Dann zum nächsten Schleifenindex, nach 26 ist dann Ende, alle Ausgänge sind korrekt gesetzt.
Da alles in einem SPS-Zyklus erfolgt, werden die Ausgänge nicht nach der "Löschschleife" auf dem KNX-Bus 0,
sie werden in der nachfolgenden "Schreibschleife" gleich wieder mit den neuen Werten beschrieben.

Also in einer For-Schleife 7 doppelte IF-Anweisungen.
 
2. Index -1 auf > 0 prüfen, wenn ja, dann prüfen ob Ausgabewert < 70, wenn ja dann auf 70 setzen

Hi Ralle,

erstmal herzlichen Dank für Deinen Vorschlag. Damit hast Du mich erstmal auf die richtige Schiene gesetzt, denn selber wär ich im Leben nicht darauf gekommen, das von so einer Seite aus anzugehen.

Ein Problem habe ich aber noch: Die Array-Indizes lassen wohl nicht so einfach 'berechnen' (arData_ITRP_DMX_A_OUT[nCount-1]), wie ich das hier gemacht habe:

Code:
arData_ITRP_Sens_IN[1]:=DI_17B00;
arData_ITRP_Sens_IN[2]:=DI_17B01;
arData_ITRP_Sens_IN[3]:=DI_17B02;
arData_ITRP_Sens_IN[4]:=DI_17B03;
arData_ITRP_Sens_IN[5]:=DI_17B04;
arData_ITRP_Sens_IN[6]:=DI_17B05;
arData_ITRP_Sens_IN[7]:=DI_17B06;
arData_ITRP_Sens_IN[8]:=DI_17B07;
arData_ITRP_Sens_IN[9]:=DI_17B08;
arData_ITRP_Sens_IN[10]:=DI_17B09;
arData_ITRP_Sens_IN[11]:=DI_17B10;
arData_ITRP_Sens_IN[12]:=DI_17B11;
arData_ITRP_Sens_IN[13]:=DI_17B12;
arData_ITRP_Sens_IN[14]:=DI_17B99;
arData_ITRP_Sens_IN[15]:=DI_2AB00;
arData_ITRP_Sens_IN[16]:=DI_2AB01;
arData_ITRP_Sens_IN[17]:=DI_2AB02;
arData_ITRP_Sens_IN[18]:=DI_2AB03;
arData_ITRP_Sens_IN[19]:=DI_2AB04;
arData_ITRP_Sens_IN[20]:=DI_2AB05;
arData_ITRP_Sens_IN[21]:=DI_2AB06;
arData_ITRP_Sens_IN[22]:=DI_2AB07;
arData_ITRP_Sens_IN[23]:=DI_2AB08;
arData_ITRP_Sens_IN[24]:=DI_2AB09;
arData_ITRP_Sens_IN[25]:=DI_2AB10;
arData_ITRP_Sens_IN[26]:=DI_2AB11;
arData_ITRP_Sens_IN[27]:=DI_2AB12;
arData_ITRP_Sens_IN[28]:=DI_2AB99;
FOR nCount:=1 TO 28 DO
arData_ITRP_DMX_A_OUT[nCount]:=0;
END_FOR;
FOR nCount:=1 TO 28 DO
IF arData_ITRP_Sens_IN[nCount]=TRUE
THEN arData_ITRP_DMX_A_OUT[nCount]:=100;
END_IF;
IF (arData_ITRP_Sens_IN[nCount]=TRUE) AND (nCount-1>0) AND (arData_ITRP_DMX_A_OUT[nCount-1]<70)
THEN arData_ITRP_DMX_A_OUT[nCount-1]:=70;
END_IF;
IF (arData_ITRP_Sens_IN[nCount]=TRUE) AND (nCount-2>0) AND (arData_ITRP_DMX_A_OUT[nCount-2]<30)
THEN arData_ITRP_DMX_A_OUT[nCount-2]:=30;
END_IF;
IF (arData_ITRP_Sens_IN[nCount]=TRUE) AND (nCount-3>0) AND (arData_ITRP_DMX_A_OUT[nCount-3]<10)
THEN arData_ITRP_DMX_A_OUT[nCount-3]:=10;
END_IF;
IF (arData_ITRP_Sens_IN[nCount]=TRUE) AND (nCount+1<29) AND (arData_ITRP_DMX_A_OUT[nCount+1]<70)
THEN arData_ITRP_DMX_A_OUT[nCount+1]:=70;
END_IF;
IF (arData_ITRP_Sens_IN[nCount]=TRUE) AND (nCount+2<29) AND (arData_ITRP_DMX_A_OUT[nCount+2]<30)
THEN arData_ITRP_DMX_A_OUT[nCount+2]:=30;
END_IF;
IF (arData_ITRP_Sens_IN[nCount]=TRUE) AND (nCount+3<29) AND (arData_ITRP_DMX_A_OUT[nCount+3]<10)
THEN arData_ITRP_DMX_A_OUT[nCount+3]:=10;
END_IF;
END_FOR;

Fehlermeldung bei Start (Simulation): FEHLER: Falscher Index für Array! Aufrufhierarchie aufrufen!

Wo liegt die zweite Fehlerursache? (die erste kenn ich, die sitzt vor dem Monitor)


Peter
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du darfst nur auf das Array zugreifen wenn der Array-Index in einem zulässigen Bereich 1..28 ist. Das konntest Du Dir bestimmt auch so schon denken ;)
Du darfst das Prüfen des Array-Index und das Zugreifen auf das Array nicht in die gleiche IF-Abfrage packen, weil der ST-Compiler vermutlich nicht optimiert, d.h. nach einem unerfüllten AND das IF nicht komplett abbricht und trotzdem noch auf das Array zugreift.

Helfen wir dem Compiler mal ein bisschen beim Optimieren und Abkürzen und formulieren so:
Code:
FOR nCount := 1 TO 28 DO
  IF arData_ITRP_Sens_IN[nCount] = TRUE THEN
    arData_ITRP_DMX_A_OUT[nCount] := 100;

    IF nCount > 1 THEN
      IF arData_ITRP_DMX_A_OUT[nCount-1] < 70 THEN
        arData_ITRP_DMX_A_OUT[nCount-1] := 70;
      END_IF;
    END_IF;

    IF nCount > 2 THEN
      IF arData_ITRP_DMX_A_OUT[nCount-2] < 30 THEN
        arData_ITRP_DMX_A_OUT[nCount-2] := 30;
      END_IF;
    END_IF;

//...

    IF nCount < 26 THEN
      IF arData_ITRP_DMX_A_OUT[nCount+3] < 10 THEN
        arData_ITRP_DMX_A_OUT[nCount+3] := 10;
      END_IF;
    END_IF;

  END_IF;
END_FOR;

Ich würde es besser so lösen, daß ich ein Array mit "Randfeldern" benutze, dann braucht man die Indizes nicht prüfen:
Code:
VAR
  arData_ITRP_DMX_A_OUT : ARRAY [-2..31] OF INT ;  //oder .. OF BYTE ?
...
Zum Bus wird trotzdem nur das Teil-Array arData_ITRP_DMX_A_OUT[1] bis arData_ITRP_DMX_A_OUT[28] geschickt.

Harald
 
Ich würd' das Ganze auf der S7 unter SCL so lösen:
Code:
[FONT=Courier New]CONST
    Stufen:= 26;                                                             // Anzahl Stufen
    Neben :=  3;                                                             // benachbarte Stufen
END_CONST

VAR_INPUT
    Stufe: ARRAY [1..Stufen] OF BOOL;                                        // Belegungserkennung Stufe
END_VAR

VAR_OUTPUT
    DMX: ARRAY [1..Stufen] OF BYTE;                                          // Byte-Ausgabe für DMX
END_VAR

VAR_TEMP
    Dimm: ARRAY [0..Neben] OF BYTE;                                          // Dimmstufen
    i: INT;                                                                  // Index-Variable [/FONT][FONT=Courier New]benachbarte [/FONT][FONT=Courier New]Stufen
    z: INT;                                                                  // Index-Variable Stufen
END_VAR


    // Dimmstufen festlegen
    Dimm[0]:= 255;                                                           // Dimmstufe 0 = 100% = 255 
    Dimm[1]:= 179;                                                           // Dimmstufe 1 =  70% = 179 
    Dimm[2]:= 102;                                                           // Dimmstufe 2 =  40% = 102 
    Dimm[3]:=  25;                                                           // Dimmstufe 3 =  10% =  25 
    

    // Treppenstufen abfragen und DMX-Werte zuweisen
    FOR z:= 1 TO Stufen BY 1 DO                                              // Schleife über alle Stufen
        DMX[z]:= 0;                                                          // DMX-Wert für Stufe zurücksetzen
        FOR i:= 0 TO Neben BY 1 DO                                           // Schleife über benachbarte Stufen
            IF Stufe[ SEL(G:= z + i > Stufen, IN0:= z + i, IN1:= z) ] OR     // Wenn Stufe i höher  (wenn existent, sonst eigene) oder
               Stufe[ SEL(G:= z - i < 1,      IN0:= z - i, IN1:= z) ]        //      Stufe i tiefer (wenn existent, sonst eigene) belegt
            THEN                                                             // Befehle bei belegter Stufe:
                DMX[z]:= Dimm[i];                                            //      DMX-Byte entspechend Abstand zu belegter Stufe zuweisen und
                EXIT;                                                        //      Schleife über benachbarte Stufen vorzeitig verlassen
            END_IF;                                                          // Ende Befehle bei belegter Stufe
        END_FOR;                                                             // Ende Schleife über benachbarte Stufen
    END_FOR;                                                                 // Ende Schleife über alle Stufen
[/FONT]
Sollte unter ST sicher ähnlich aussehen.
 
Zuletzt bearbeitet:
Ich würde es besser so lösen, daß ich ein Array mit "Randfeldern" benutze, dann braucht man die Indizes nicht prüfen:
Das sollte man sich noch aus einem anderen Grund überlegen:
Momentan gehen beim Verlassen der Treppe die letzen 4 Stufen alle auf einmal aus. Mit Randfeldern könnte man diese über einen Timer virtuell "begehen" und so die Treppe allmählich ausgehen lassen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du darfst nur auf das Array zugreifen wenn der Array-Index in einem zulässigen Bereich 1..28 ist. Das konntest Du Dir bestimmt auch so schon denken ;)
Du darfst das Prüfen des Array-Index und das Zugreifen auf das Array nicht in die gleiche IF-Abfrage packen, weil der ST-Compiler vermutlich nicht optimiert, d.h. nach einem unerfüllten AND das IF nicht komplett abbricht und trotzdem noch auf das Array zugreift.
Ja, das kann ich mir so denken, seit ich Deinen Post gelesen habe... ;)
Aber, meine Gedanken gingen schon erst gar nicht so weit, weil ich davon ausging, mit "... AND (nCount-1>0)" den Zugriffsversuch auf das Array mit einem ungültigen Index schon von vorneherein ausgeschlossen zu haben. Auf die Idee, dass der ST-Compiler das ganz anders sieht, wäre ich allerdings nie gekommen...

Jedenfalls vielen Dank für Deine Horizonterweiterung (also - ich spreche von MEINEM Horizont! ;)).

Ich werde das zunächst mal so umsetzen, und wenn das alles klappt, werde ich mich daran versuchen, huckis SCL-Lösung unter ST zum Laufen zu kriegen. Die Dimm-Fixwerte auch gleich in ein Array zu packen gefällt mir sehr gut! Auch dafür many thanks! :)

Ich würde es besser so lösen, daß ich ein Array mit "Randfeldern" benutze, dann braucht man die Indizes nicht prüfen:
Das sollte man sich noch aus einem anderen Grund überlegen:
Momentan gehen beim Verlassen der Treppe die letzen 4 Stufen alle auf einmal aus. Mit Randfeldern könnte man diese über einen Timer virtuell "begehen" und so die Treppe allmählich ausgehen lassen.
Dass die letzten 4 Stufen beim Verlassen der Treppe alle auf einmal ausgehen, wäre mir bestimmt erst beim Test am lebenden Objekt unangenehm aufgefallen! :D Das mit der 'virtuellen Timerbegehung' werde ich dann ganz sicher so einbinden.

Wenn dann alles soweit läuft, träum ich ja schon davon, die Umschaltung von einem Dimmwert auf den anderen nicht abrupt ablaufen zu lassen, sondern fließend über eine art Dimmwert-Rampe. Und dann noch unterschiedliche Laufzeitwerte der Rampen, d.h. Rampendauer für jeweils die erste Stufe ober- und unterhalb z.B. 1 Sekunde, zweite Stufe 2 Sekunden, usw. Dann die Starts der Rampen nicht alle zeitgleich mit der Belegung des Lichttasters, sondern auch noch zeitlich gestaffelt.

Die Krönung zum Schluss wäre natürlich noch die Auswertung der Bewegungsrichtung der Person, d.h. in Bewegungsrichtung werden mehr Stufen beleuchtet, als gegen die Bewegungsrichtung (also hinter der Person). Das wäre dann sicherlich spannend, wenn zwei Personen die Treppe gleichzeitig benutzen. Der eine rauf, der andere runter... :D

So, mancher wir jetzt bestimmt denken, der hat ne Vollmeise. Ich habe an meiner Treppe oben und unten jeweils einen Wechselschalter und gut is. Damit komm ich auch gut beleuchtet über die Stufen. :D

Aber ich denke, in einem SPS-Forum wird man mir das nachsehen... ;)

Peter
 
Ich würde es besser so lösen, daß ich ein Array mit "Randfeldern" benutze, dann braucht man die Indizes nicht prüfen:
Code:
VAR
  arData_ITRP_DMX_A_OUT : ARRAY [-2..31] OF INT ;  //oder .. OF BYTE ?
...

Das mit den Randfeldern ist beim Funktionsbaustein "FbDMX_StageProfi" wohl so nicht zu lösen (siehe Anhang).

Kann es sein, dass dieser Baustein nur Arrays mit eben (1..255) zulässt?

Fehler 4012.jpg
 
Dann musst Du halt mit 2 Arrays arbeiten - ein größeres internes für die Zuweisungen und davon kopierst Du dann nur die Member 1 bis 28 in das Ausgangs-Array für den anderen Baustein.

Harald
 
Dass die letzten 4 Stufen beim Verlassen der Treppe alle auf einmal ausgehen, wäre mir bestimmt erst beim Test am lebenden Objekt unangenehm aufgefallen! :D Das mit der 'virtuellen Timerbegehung' werde ich dann ganz sicher so einbinden.

Wenn dann alles soweit läuft, träum ich ja schon davon, die Umschaltung von einem Dimmwert auf den anderen nicht abrupt ablaufen zu lassen, sondern fließend über eine art Dimmwert-Rampe.
Wenn Du eine Dimmwert-Rampe integrierst, kannst Du Dir wahrscheinlich die virtuelle Begehung sparen, da sie ja im Prinzip das Gleiche macht.
Von 255 auf 0 zu dimmen, dauert schließlich von Haus aus länger, als von 25 auf 0. Somit ist die entferntere Stufe auch eher aus.

Dafür hast Du dann beim Hochdimmen eventuell ein Problem, wenn es mit dem Begehen der Stufen mithalten muss. Oder dort höhere "Geschwindigkeiten" verwenden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja, klar, gerne!

Ich schick mal voraus, dass sich mir die Variablenklassen VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT noch nicht so ganz erschließen, wann man welche Klassen wie verwendet. Muss ich z.B. eine Variable, die ich in einem Programmbaustein als VAR_OUTPUT deklariere, in einem anderen Programmbaustein, in dem diese Variable verarbeitet werden soll, dort dann nochmals deklarieren und zwar als VAR_INPUT? Warum dann nicht gleich alles als VAR_IN_OUT deklarieren? Oder besser gleich alles als globale Variablen? Dann muss ich nicht beachten, in welchem (auch evtl. künftigen) Programmbaustein welche Variable verwendet werden soll?

Mir ist schon klar, dass es die diversen Variablenklassen nicht ohne Grund gibt... Hat das damit zu tun, dass wenn ich alles als global deklariere, ich zuviel Speicherplatz verbrate und die Zykluszeit unnötig in die Höhe treibe? So hab ich mirs jedenfalls versucht zu erklären. ;)

Ich habe jedenfalls im Moment alle Variablen, die auch in anderen Programmbausteinen verwendet werden, als global deklariert, da mir Deklarationen als VAR_INPUT oder VAR_OUTPUT beim Übersetzen Fehlermeldungen generierten, dass hier noch genau 1 Eingang erwartet würde, oder dort eine Varible nicht deklariert sei.

Da dieses Handling aber schließlich eine sehr grundlegende Sache ist, werde ich da bei mir noch Licht reinbringen müssen. Diese Basics sind m. E. in der Hilfe oder im Handbuch nicht gut dokumentiert.

Meine Umsetzung von Haralds Vorschlag:

PROGRAM _1000_DMX_Master_A
Deklaration:
Code:
VAR
 DMX_Master_A  : FbDMX_StageProfi;
 Enable    : BOOL := TRUE;
 PortNumber   : WORD := 10001;
 FirstChannel  : WORD := 1;
 NumberOfChannels : BYTE := 12;
 Ready    : BOOL;
 Connect    : BOOL;
 ErrorCode   : DINT;
 ErrorWatchdog  : BOOL;
END_VAR
Code:
Code:
DMX_Master_A(
 xEnable:= Enable,
 sIPaddress:= '192.168.2.250',
 wPortNumber:= PortNumber,
 wStartChannel:= FirstChannel,
 bNumberOfChannels:= NumberOfChannels,
 abDMX_Values:= arData_ITRP_DMX_A_OUT,
 xReady=> Ready,
 xConnect=> Connect,
 diError=> ErrorCode,
 xWatchdog=> ErrorWatchdog);

PROGRAM _1010_Ansteuerung_DMX_Innentreppe
Deklaration:
Code:
VAR
 nCount: INT;
 arTemp_ITRP_DMX_A_OUT :ARRAY[-2..31] OF BYTE;
END_VAR
Code:
Code:
arData_ITRP_Sens_IN[1]:=DI_17B00;
arData_ITRP_Sens_IN[2]:=DI_17B01;
arData_ITRP_Sens_IN[3]:=DI_17B02;
arData_ITRP_Sens_IN[4]:=DI_17B03;
arData_ITRP_Sens_IN[5]:=DI_17B04;
arData_ITRP_Sens_IN[6]:=DI_17B05;
arData_ITRP_Sens_IN[7]:=DI_17B06;
arData_ITRP_Sens_IN[8]:=DI_17B07;
arData_ITRP_Sens_IN[9]:=DI_17B08;
arData_ITRP_Sens_IN[10]:=DI_17B09;
arData_ITRP_Sens_IN[11]:=DI_17B10;
arData_ITRP_Sens_IN[12]:=DI_17B11;
arData_ITRP_Sens_IN[13]:=DI_17B12;
arData_ITRP_Sens_IN[14]:=DI_17B99;
arData_ITRP_Sens_IN[15]:=DI_2AB00;
arData_ITRP_Sens_IN[16]:=DI_2AB01;
arData_ITRP_Sens_IN[17]:=DI_2AB02;
arData_ITRP_Sens_IN[18]:=DI_2AB03;
arData_ITRP_Sens_IN[19]:=DI_2AB04;
arData_ITRP_Sens_IN[20]:=DI_2AB05;
arData_ITRP_Sens_IN[21]:=DI_2AB06;
arData_ITRP_Sens_IN[22]:=DI_2AB07;
arData_ITRP_Sens_IN[23]:=DI_2AB08;
arData_ITRP_Sens_IN[24]:=DI_2AB09;
arData_ITRP_Sens_IN[25]:=DI_2AB10;
arData_ITRP_Sens_IN[26]:=DI_2AB11;
arData_ITRP_Sens_IN[27]:=DI_2AB12;
arData_ITRP_Sens_IN[28]:=DI_2AB99;

FOR nCount := -2 TO 31 DO
arTemp_ITRP_DMX_A_OUT[nCount]:=0;
END_FOR;
FOR nCount := 1 TO 28 DO
  IF arData_ITRP_Sens_IN[nCount] = TRUE THEN
    arTemp_ITRP_DMX_A_OUT[nCount] := 100;
    IF arTemp_ITRP_DMX_A_OUT[nCount-1] < 70 THEN
      arTemp_ITRP_DMX_A_OUT[nCount-1] := 70;
    END_IF;
    IF arTemp_ITRP_DMX_A_OUT[nCount-2] < 30 THEN
      arTemp_ITRP_DMX_A_OUT[nCount-2] := 30;
    END_IF;
    IF arTemp_ITRP_DMX_A_OUT[nCount-3] < 10 THEN
      arTemp_ITRP_DMX_A_OUT[nCount-3] := 10;
    END_IF;
    IF arTemp_ITRP_DMX_A_OUT[nCount+3] < 10 THEN
      arTemp_ITRP_DMX_A_OUT[nCount+3] := 10;
    END_IF;
    IF arTemp_ITRP_DMX_A_OUT[nCount+2] < 30 THEN
      arTemp_ITRP_DMX_A_OUT[nCount+2] := 30;
    END_IF;
    IF arTemp_ITRP_DMX_A_OUT[nCount+1] < 70 THEN
      arTemp_ITRP_DMX_A_OUT[nCount+1] := 70;
    END_IF;
  END_IF;
END_FOR;

FOR nCount := 1 TO 28 DO
arData_ITRP_DMX_A_OUT[nCount] := arTemp_ITRP_DMX_A_OUT[nCount];
END_FOR;

Globale_Variablen
Deklaration:
Code:
VAR_GLOBAL

(* _0252_KNX_Sensoren_Innentreppe *)

   (* DI 13A - 8 DI - E3-E8 -----------------------------------*)
 DI_17B00 AT %IX13.6  : BOOL;
 DI_17B01 AT %IX13.7  : BOOL;
 DI_17B02 AT %IX13.8  : BOOL;
 DI_17B03 AT %IX13.9  : BOOL;
 DI_17B04 AT %IX13.10 : BOOL;
 DI_17B05 AT %IX13.11 : BOOL;
   (* DI 13B - 8 DI - E1-E8 -----------------------------------*)
 DI_17B06 AT %IX13.12 : BOOL;
 DI_17B07 AT %IX13.13 : BOOL;
 DI_17B08 AT %IX13.14 : BOOL;
 DI_17B09 AT %IX13.15 : BOOL;
 DI_17B10 AT %IX14.0  : BOOL;
 DI_17B11 AT %IX14.1  : BOOL;
 DI_17B12 AT %IX14.2  : BOOL;
 DI_17B99 AT %IX14.3  : BOOL;
   (* DI 14A - 8 DI - E1-E8 -----------------------------------*)
 DI_2AB00 AT %IX14.4  : BOOL;
 DI_2AB01 AT %IX14.5  : BOOL;
 DI_2AB02 AT %IX14.6  : BOOL;
 DI_2AB03 AT %IX14.7  : BOOL;
 DI_2AB04 AT %IX14.8  : BOOL;
 DI_2AB05 AT %IX14.9  : BOOL;
 DI_2AB06 AT %IX14.10 : BOOL;
 DI_2AB07 AT %IX14.11 : BOOL;
   (* DI 14B - 8 DI - E1-E6 -----------------------------------*)
 DI_2AB08 AT %IX14.12 : BOOL;
 DI_2AB09 AT %IX14.13 : BOOL;
 DI_2AB10 AT %IX14.14 : BOOL;
 DI_2AB11 AT %IX14.15 : BOOL;
 DI_2AB12 AT %IX15.0  : BOOL;
 DI_2AB99 AT %IX15.1  : BOOL;

(* _1000_DMX_Master_A *)

 arData_ITRP_DMX_A_OUT :ARRAY[1..255] OF BYTE;

(*  _1010_Ansteuerung_DMX_Innentreppe *)

 arData_ITRP_Sens_IN  :ARRAY[1..28] OF BOOL;
END_VAR

Meine Umsetzung von huckis Vorschlag:

PROGRAM _1000_DMX_Master_A
Deklaration: wie oben
Code: wie oben

PROGRAM _1010_Ansteuerung_DMX_Innentreppe
Deklaration:
Code:
VAR
 arTemp_ITRP_DMX_A_OUT: ARRAY [1..Stufen] OF BYTE; (* BYTE-Ausgabe füR DMX *)
 arDimm:     ARRAY [0..Neben] OF BYTE; (* Dimmstufen *)
 i:      INT;      (* Index-Variable benachbarte Stufen *)
 z:      INT;      (* Index-Variable Stufen *)
END_VAR
Code:
Code:
(* Übergabe der Sensoreingänge an Array *)

//... wie oben

(* Dimmstufen festlegen *)

arDimm[0]:= 255;   (* Dimmstufe 0 = 100% = 255 *)
arDimm[1]:= 179;   (* Dimmstufe 1 =  70% = 179 *)
arDimm[2]:= 102;   (* Dimmstufe 2 =  40% = 102 *)
arDimm[3]:=  25;   (* Dimmstufe 3 =  10% =  25 *)

(* Treppenstufen abfragen und DMX-Werte zuweisen *)

FOR z:= 1 TO Stufen BY 1 DO           (* Schleife über alle Stufen *)
 arTemp_ITRP_DMX_A_OUT[z]:= 0;         (* DMX-Wert für Stufe zurücksetzen *)
 FOR i:= 0 TO Neben BY 1 DO          (* Schleife über benachbarte Stufen *)
  IF arData_ITRP_Sens_IN[SEL(z + i > Stufen, z + i, z)] OR (* Wenn Stufe i höher  (wenn existent, sonst eigene) oder *)
     arData_ITRP_Sens_IN[SEL(z - i < 1, z - i, z)]   (*      Stufe i tiefer (wenn existent, sonst eigene) belegt *)
  THEN              (* Befehle bei belegter Stufe: *)
   arTemp_ITRP_DMX_A_OUT[z]:= arDimm[i];     (*      DMX-Byte entspechend Abstand zu belegter Stufe zuweisen und *)
   EXIT;             (*      Schleife über benachbarte Stufen vorzeitig verlassen *)
  END_IF;              (* Ende Befehle bei belegter Stufe *)
 END_FOR;              (* Ende Schleife über benachbarte Stufen *)
END_FOR;               (* Ende Schleife über alle Stufen *)
FOR z:= 1 TO Stufen BY 1 DO           (* Schleife über alle Stufen *)
arData_ITRP_DMX_A_OUT[z] := arTemp_ITRP_DMX_A_OUT[z];    (* Ausgabe Array DMX-Wert an Array DMX Master A *)
END_FOR;               (* Ende Schleife über alle Stufen *)

Globale_Variablen
Deklaration:
Code:
VAR_GLOBAL CONSTANT

(*  _1011_Ansteuerung_DMX_Innentreppe *)

 Stufen: INT := 28;   (* Anzahl Stufen *)
 Neben: INT :=  3;   (* benachbarte Stufen *)

END_VAR

VAR_GLOBAL

(* _0252_KNX_Sensoren_Innentreppe *)

//... wie oben

(* _1000_DMX_Master_A *)

 arData_ITRP_DMX_A_OUT :ARRAY[1..255] OF BYTE;

(*  _1011_Ansteuerung_DMX_Innentreppe *)

 arData_ITRP_Sens_IN: ARRAY [1..Stufen] OF BOOL; (* Belegungserkennung Stufe *)
END_VAR
 
Dass die letzten 4 Stufen beim Verlassen der Treppe alle auf einmal ausgehen, wäre mir bestimmt erst beim Test am lebenden Objekt unangenehm aufgefallen! :D Das mit der 'virtuellen Timerbegehung' werde ich dann ganz sicher so einbinden.

Beim Grübeln darüber, wie ich die virtuelle Begehung, bzw. die Dimmrampe einbinde (in huckis Vorschlag), ist mir aufgefallen, dass sämtliche Lichter ja nicht nur beim Verlassen der der Treppe (nach oben, wie auch nach unten) auf einmal ausgehen, sondern auch immer dann, wenn das dürre Nachbarskind beim Treppensteigen sich genau zwischen zwei Lichttasterbeams befindet.

Das würde ein Geblinke...
 
Ein Grund mehr, die Rampe dem virtuellen Begehen vorzuziehen.

Schnelles Einschalten langsames Ausdimmen sollte da eine gute Lösung sein.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Zwischenfrage:

Ich bin gerade dabei, die Dimm-Rampen einzubauen und stecke mit folgendem Problem fest:

Aus der "oscat_basic_333.lib" möchte ich die mir für meine Zwecke passend scheinende Funktion "FRMP_B" verwenden. Deren Eingang "TD : TIME (Abgelaufene Zeit)" beschalte ich mit dem Ausgang der Standardfunktion TON. Die Standardfunktion TON lässt sich als Array definieren, die Oscat-Funktion FRMP_B aber nicht.
Code:
 arTON:  ARRAY [1..Stufen, 0..Neben] OF TON;
 arFRMP_B: ARRAY [1..Stufen, 0..Neben] OF FRM_B;
Zudem ist mir nicht klar, wie ich den Ausgang von FRM_B 'abgreife'. Wenn ich versuche, das mit der Zeile "FRMP_B => arDiffR[z]" zu erreichen, bekomme ich die Fehlermeldung, dass die Funktion FRMP_B zu viele Parameter habe (daher im Code als Kommentar gesetzt).
Code:
FOR z:= 1 TO Stufen BY 1 DO  (* Schleife über alle Stufen *)
 FOR i:= 0 TO Neben BY 1 DO (* Schleife über benachbarte Stufen *)
  arTON[z,i](
   IN := arDiff[z]<>0,
   PT:= arDimmT[i],
   Q => arDimmTE[i],
   ET => arRampT[i]);
  FRMP_B[z,i](
   START := BYTE#255-arDiff[z],
   DIR := arDiff[z]>0,
   TD := arRampT[i],
   TR := DWORD_TO_TIME((BYTE#255/(arDiff[z]+arDiffR[z]-BYTE#255))*TIME_TO_DWORD(arDimmT[i])));
   (* FRMP_B => arDiffR[z]); *)
 END_FOR;
END_FOR;
 
M.M.n. hast Du auch einen Denkfehler in Deinem Programm. Jede Stufe hat nur 2 DMX-Werte - einen IST und einen SOLL. Warum also die Schleifen über benachbarte Stufen?
Die benachbarten Stufen fahren eh' ihre eigene Rampe!

PS: Nur der Sollwert hängt von der Belegung der Nachbarstufen ab. Aber das hast Du ja schon weiter oben erfasst.
 
Zuletzt bearbeitet:
Zurück
Oben