# BR-Studio und Strukturierter Text - Problem



## Kirpitsch (10 Juni 2011)

Hallo alle zammen  Ich muss ein Programm mit BR-Studio in Verbindung mit der ST (Strukturierter Text) Programmiersprache schreiben.

Folgendes ist meine Aufgabe:
Ich habe einen pneumatischen Zylinder (doppeltwirkend) und 2 stück 3/2-Magnetventile (pneumatische Rückstellung) welche den Zylinder hin- und herfahren lassen sollen.


So sieht mein Quellcode aus:

//////////////////////////////////
// Steuerung Magnetventil 1 //
//////////////////////////////////

// Variable setzen
input_1 := TRUE;

// Zeitverzögerung beim Ausschalten des Ventils
TP_01( IN:=input_1, PT:=T#3s500ms );

// input_1 + Zeitverzögerung an Magnetventil_1 senden
magnetventil_1_do := TP_01.Q;
elapsedTime_1 := TP_01.ET;

// Variable Rücksetzen
input_1 := FALSE;



//////////////////////////////////
// Steuerung Magnetventil 2 //
//////////////////////////////////

IF (elapsedTime_1 = T#3s500ms) THEN

        // Variable setzen
        input_2 := TRUE;

        // Zeitverzögerung beim Ausschalten des Ventils
        TP_02( IN:=input_2, PT:=T#3s500ms );

        // input_2 + Zeitverzögerung an Magnetventil_2 senden
        magnetventil_2_do := TP_02.Q;
        elapsedTime_2 := TP_02.ET;

        // Variable Rücksetzen
        input_2 := FALSE;

END_IF

Problem ist, dass der Zylinder bei diesem Code nur einmal hin- und zurück fährt. Ich will aber dass er das z.B. 10 mal tut, so oft ich es eben will.

BR-Studio arbeitet ja mit den Cyclic#1 - Cyclic#8 Dingern (weis grade nicht wie ich das nennen soll^^) welche ja z.B. alle 10ms wiederholt werden. Also dachte ich, dass meine Ventile bei meinem Code endlos ein und ausgehen müssten, das ist aber nicht der Fall. Das ganze passiert nur einmal, dann ist schluß.

Wie könnte ich das umsetzen, dass es funktioniert?

Ich hoffe, dass ich einigermaßen erklären konnte was ich möchte. Wenn mein Code nicht gut ist, dann korrigiert mich auch bitte.

Gruß
Kirpitsch


----------



## Verpolt (10 Juni 2011)

```
// Variable setzen
input_1 := TRUE;
```
Deine Zeit wird so nur einmal gestartet (kein Flankenwechsel)

Also der Input_1 sollte für ein neues Ansteuern der Zeit sein Signal wechseln


----------



## Kirpitsch (10 Juni 2011)

Ich setze ihn doch am Ende auch wieder auf FALSE. Oder verstehe ich was falsch? kannst das in meinem Quellcode evtl. ändern und nochmal posten? Wäre echt hilfreich.


----------



## bits'bytes (10 Juni 2011)

Kirpitsch schrieb:


> Ich setze ihn doch am Ende auch wieder auf FALSE. Oder verstehe ich was falsch? kannst das in meinem Quellcode evtl. ändern und nochmal posten? Wäre echt hilfreich.


Hi,
du musst in einmal auf FALSE haben wenn du den PULS-Fub (TP_...) aufrufst. Da setzt du ihn aber immer vorher auf true.

```
TP_01( IN:=input_1, PT:=T#3s500ms );

input_1 = true

...
code
...
if (was weiss ich) then
  input_1 = false           ; erzeugt einen startpuls, da in einem durchgang = 0
endif
```


----------



## Kirpitsch (11 Juni 2011)

@bits'bytes

Den besten Dank dir, mit deinem Code hats funktioniert!!! 

Habe außerdem bemerkt, dass meine CPU jede Milisekunde das Programm durchgearbeitet hat, d.h. ich konnte nicht erkennen, dass das Ventil für diese 1ms sich kurz ausschaltet und dann sofort wieder ein ist.

Danke dir nochmals


----------



## bits'bytes (11 Juni 2011)

Hi,
besser wäre es allerdings wenn du sowas machen würdest..., dann hast du keinen Zyklus Verzögerung

```
TP_01( IN:=input_1, PT:=T#3s500ms );
input_1 = false

...
code
...
if (was weiss ich) then
  input_1 = true           ; erzeugt einen startpuls, da ein durchgang = 1
endif

; wenn du sofort wieder zurückfahren willst
  
TP_02( IN:=EDGENEG(TP_01.Q), PT:=T#3s500ms );
```


----------



## Kirpitsch (14 Juni 2011)

So habe das mal ausprobiert aber es funzt nicht, das Ventil 1 wird innerhalb 1ms dauernd eingeschaltet wenns ausgeht....

So hab ich deinen Code umgesetzt, ich hab wohl nen Fehler drin:

TP_01( IN:=input_1, PT:=T#1500ms );
input_1 := FALSE;

magnetventil_1_do := TP_01.Q;

IF (magnetventil_1_do = FALSE) THEN
     input_1 := TRUE;    //erzeugt einen startpuls, da ein durchgang = 1
END_IF



TP_02( IN:=EDGENEG(TP_01.Q), PT:=T#1500ms );
magnetventil_2_do := TP_02.Q;


----------



## Kirpitsch (14 Juni 2011)

eine kleine Ergänzung:

Dein erstes Codebeispiel habe ich so umgesetzt:

// Magnetventil 1
IF (magnetventil_1_do = TRUE) OR (magnetventil_2_do = FALSE) THEN

    TP_01( IN:=input_1, PT:=schalten_ms );
    input_1 := TRUE;

    magnetventil_1_do := TP_01.Q;

    IF (TP_01.ET = schalten_ms) THEN

        input_1 := FALSE;

    END_IF

END_IF





// Magnetventil 2
IF (magnetventil_1_do = FALSE) THEN

    TP_02( IN:=input_2, PT:=schalten_ms );
    input_2 := TRUE;

    magnetventil_2_do := TP_02.Q;


    IF (TP_02.ET = schalten_ms) THEN

        input_2 := FALSE;

    END_IF

END_IF

Das hat verzögerungsfrei funktioniert. Mit Verzögerungsfrei meine ich natürlich dass die Verzögerung von 1ms meiner Taskklasse nicht berücksichtigt wird. Oder habe ich doch eine Verzögerung beim Umschalten meiner Ventile die ich im Code nur nicht bemerkt habe?


----------



## bits'bytes (14 Juni 2011)

Kirpitsch schrieb:


> So habe das mal ausprobiert aber es funzt nicht, das Ventil 1 wird innerhalb 1ms dauernd eingeschaltet wenns ausgeht....
> 
> So hab ich deinen Code umgesetzt, ich hab wohl nen Fehler drin:
> ...
> ...



Hi,
wenn du do_1 sofort mit der negativen Flanke seiner selbst setzt ist do_1 ja quasi dauernd aktiv....

siehe mal folgendes Beispiel, habe jetzt den Wiederstart einfach mit einem Zeitglied verzögert....


```
PROGRAM _INIT
    TON_01.PT    := T#7s;        // Nach sieben Sekunden wieder starten
    magnetventil_1_do := 0;
    magnetventil_2_do := 0;
END_PROGRAM

PROGRAM _CYCLIC
    // neuen Zyklus starten wenn beide DO's 0 sind 7 Sekunden warten
    IF (magnetventil_1_do = 0) AND (magnetventil_2_do = 0) THEN
        TON_01.IN := 1;
    END_IF
    TON_01 (IN:= TON_01.IN, PT:= TON_01.PT);
    IF (TON_01.Q = 1) THEN
        TON_01.IN := 0;
        input_1 := 1;
    END_IF
        
    // Ventil auf
    TP_01( IN:=input_1, PT:=T#1500ms );
    input_1 := FALSE;
    magnetventil_1_do := TP_01.Q;

    // Ventil zu...
    TP_02( IN:=EDGENEG(TP_01.Q), PT:=T#1500ms );
    magnetventil_2_do := TP_02.Q;
END_PROGRAM
```


----------



## Kirpitsch (18 Juni 2011)

Hi, habe den Code gleich mal in mein PowerPanel übertragen und es tut perfekt. Und dass ich damit sogar den Startzyklus gewollt verzögern kann ist natürlich eine tolle Sache. An dieser Stelle vielen Dank.

Ich habe natürlich auch versucht den Code zu verstehen und an einer Stelle habe ich noch ne Frage. Kurz nachdem du prüfst ob beide DO's = 0 sind, kommt der folgende Quelltext:

TON_01 (IN:= TON_01.IN, PT:= TON_01.PT);
        IF (TON_01.Q = 1) THEN
             TON_01.Q := 0;
             input_1 : = 1;
        END_IF

Hier machst du ja den Funktionsaufruf der Einschaltverzögerung mit Parameterübergabe. Dann fragst du, ob der Ausgang von TON_01 auf TRUE gesetzt ist. Ist dies der Fall, dann wird input_1 ebenfalls auf TRUE gesetzt. Diese IF-Bedingung muss also zwingend erfüllt sein, da sonst meine Ventile niemals schalten werden oder? Ich habe aber im ganzen Quelltext keine einzige Zeile mit TON_01.Q := TRUE gesehen.

Heist das jetzt, dass wenn ich den Funktionsaufruf TON_01 (IN:= TON_01.IN, PT:= TON_01.PT); mit Parameterübergabe mache, dass dann automatisch mein Ausgang TON_01.Q auf TRUE gesetzt wird? 

Und noch eine Frage zum InitCode, wird dieser, wenn meine Taskklasse alle 10ms neu durchläuft, auch alle 10ms neu aufgerufen?

Gruß


----------



## bits'bytes (18 Juni 2011)

Hi!



Kirpitsch schrieb:


> Hi, habe den Code gleich mal in mein PowerPanel  übertragen und es tut perfekt. Und dass ich damit sogar den Startzyklus  gewollt verzögern kann ist natürlich eine tolle Sache. An dieser Stelle  vielen Dank


Freut mich 



Kirpitsch schrieb:


> ..Kurz nachdem du prüfst ob beide DO's = 0 sind, kommt der folgende Quelltext:
> 
> ```
> TON_01 (IN:= TON_01.IN, PT:= TON_01.PT);
> ...


----------



## Kirpitsch (24 Juni 2011)

> Du hast ja die Variable TON_01 als TON Zeitglied definiert, oder nicht ?



Natürlich, sonst würde glaube ich auch der Compiler gleich schimpfen. Also ich denke hiermit ist eigentlich alles was ich so wissen wollte geklärt worden. Danke nochmal :-D


----------



## Kirpitsch (29 Juni 2011)

So es hat sich doch wieder ein Problem aufgetan.

Ich möchte zählen wie oft mein Zylinder eine bestimmte Position durchfährt. So sieht mein Code aus:


IF (druckregelvenil_druck = 0) THEN    // Bei jedem Neustart oder
                                                   // Programmabruch der Fall
    wegmitte := sensor_weg;
    zeit_wegmitte := 0;
    n := 0;
END_IF

IF (sensor_weg = wegmitte) AND (n = 1) THEN
    n := 0;
    zeit_wegmitte := 0;
    IF(startbutton = TRUE) THEN
        zyklenzahl := zyklenzahl + 1;
    END_IF
END_IF

IF (sensor_weg <> wegmitte) THEN
    zeit_wegmitte := zeit_wegmitte + 1;
    n := 1;
END_IF

IF (startbutton = FALSE) THEN
    zyklenzahl := 0;
END_IF



So und eigentlich tut das auch (hoffe ich hab beim schreiben keinen Fehler im Code) aber wenn ich einen Neustart des Systems (Stromausfall ^^) mache, dann zählt er die Zyklen zwar auch, aber fängt dann z.B. gleich bei 10 an, dannach zählt er normal weiter. Wie könnte ich den Fehler drin haben?


----------



## bits'bytes (29 Juni 2011)

Hallo ,

kurz einige Punkte

a) du solltest den Code mittels # des Editors hier einfügen, dann kann man in auch leichter (eventuell  lesen

b) du solltest Copy/Paste verwenden, dann kannst du dich auch nicht verschreiben 


c) zu deinem Code

- ist kein Code-Fragment sondern der gesamte Code, oder ?
- wozu ist die Variable "zeit_wegmitte", wird nicht verwendet

- "zyklenzahl" wird beim INIT nicht gelöscht, (da kein INIT ?)

- ist "startbutton" eine IO-Variable oder ein Merker ?

- du solltest keine Variablen verwenden wie "n" oder "i"



```
IF (druckregelvenil_druck = 0) THEN // Bei jedem Neustart oder // Programmabruch der Fall
    wegmitte := sensor_weg;
    zeit_wegmitte := 0;
    n := 0;
END_IF

IF (sensor_weg = wegmitte) AND (n = 1) THEN
    n := 0;
    zeit_wegmitte := 0;
    IF(startbutton = TRUE) THEN
        zyklenzahl := zyklenzahl + 1;
    END_IF
END_IF

IF (sensor_weg <> wegmitte) THEN
    zeit_wegmitte := zeit_wegmitte + 1;
    n := 1;
END_IF

IF (startbutton = FALSE) THEN
    zyklenzahl := 0;
END_IF
```
so kommts mir ein bisschen übersichtlicher vor (achtung: syntax ist nicht structured text, sondern misch-masch)


```
if (EDGEPOS(startbutton)) then
     zyklenzahl = 0
endif

if (sensor_weg = wegmitte) then   // ist wieder auf Position die geprüft werden soll
    zyklenzahl = zyklenzahl + war_weg and startbutton
    war_weg = 0
else
    war_weg = 1    // ist weg von prüfposition, wenn er wieder drauf fährt, zählen
endif
```


----------

