S7-SCL Anfänger

StepUser

Level-1
Beiträge
5
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo
bin Anfänger in SCL. Habe jetzt mal 2 kurze Bausteine programmiert.
Könnt ihr die mal anschauen? Und mir nur mal kurz sagen, was man verbessern könnte oder was ich falsch gemacht habe
wills ja richtig lernen.

Code:
FUNCTION_BLOCK FB40

TITLE = 'Betriebsstundenzähler'
VERSION : '1.0'
AUTHOR  : Wotke
NAME    : BSZ
FAMILY  : family

// Bausteinparameter
VAR_INPUT
    // Eingangsparameter
    // Freigabe = Der Betriebsstundenzähler wird freigegeben und beginnt zu zählen
    // Reset = Die Betriebsstunden werden auf 0 zurückgesetzt
    // Ausgabe = Auswahl in welcher Einheit die Zeit ausgegeben werden soll
    //           1 = Stunden
    //           2 = Minuten
    //           3 = Sekunden
Freigabe:BOOL;
Reset:BOOL;
Ausgabe:INT;
END_VAR

VAR_IN_OUT
    // Durchgangsparameter
END_VAR

VAR_OUTPUT
    // Ausgangsparameter
    // Je nach dem welche Ausgabe parametriert wurde (1,2 oder 3)
    // wird entweder Stunden, Minuten oder Sekunden ausgegeben
Betriebsstunden:REAL;
END_VAR

VAR_TEMP
    // temporäre Variablen
END_VAR
VAR
    // statische Variablen
Takt:BOOL;
Sekunde:REAL;
Timer1:SFB4;
E1,E2,E4:REAL;
E3:DINT;
END_VAR

LABEL
    MARKE1;
    MARKE2;
END_LABEL

BEGIN
// Anweisungsteil
// Betriebsstunden zurücksetzen bei MARKE2
// Freigabe BSZ. Wenn Freigabe=0 dann springe zu
// MARKE1 (Bausteinende)
IF Reset THEN GOTO MARKE2;
ELSIF NOT Freigabe THEN GOTO MARKE1;
END_IF;

//Timer für Takt zum Sekundenzählen
Timer1 (IN:=NOT Takt, PT:=T#1s);
Takt:=Timer1.Q;

// Wenn Takt=0 springe zu MARKE1 (Bausteinende)
// Wenn Takt=1 zähle eine Sekunde hoch
IF NOT Takt THEN GOTO MARKE1;
ELSIF Takt THEN Sekunde:=Sekunde+1;
END_IF;
// Je nach parametrierung des Ausgangs "Ausgabe"
// wird in das jeweilige Format umgerechet
IF Ausgabe=1 THEN E1:=((Sekunde/60)/60);
ELSIF Ausgabe=2 THEN E1:=(Sekunde/60);
ELSIF Ausgabe=3 THEN E1:=Sekunde;
END_IF;

// Begrenzung der Betriebsstunden Ausgabe
// auf 2 Nachkommastellen
E2:= (E1*100.0);
E3:= REAL_TO_DINT (E2);
E4:= DINT_TO_REAL (E3);
Betriebsstunden:= (E4/100.0);
GOTO MARKE1;

// MARKE2 = Zurücksetzen Betriebsstundenzähler
MARKE2: 
Sekunde:=0;
Betriebsstunden:=0;

MARKE1: ;
    ;
END_FUNCTION_BLOCK


Code:
FUNCTION_BLOCK FB50
// Ausgang wird geschalten, wenn:
// TIME_OF_DAY gleich oder zwischen Ein- und Ausschaltzeit ist
// und DAY_CHECK ein positives Ergebnis liefert.
TITLE = 'Wochenschaltuhr'
VERSION : '1.0'
AUTHOR  : Wotke
NAME    : Schaltuhr
FAMILY  : Zeiten

    // Bausteinparameter
VAR_INPUT
    // Eingangsparameter
    Einschaltzeit:TOD;
    Ausschaltzeit:TOD;
    Sonntag:BOOL:=0;
    Montag:BOOL:=0;
    Dienstag:BOOL:=0;
    Mittwoch:BOOL:=0;
    Donnerstag:BOOL:=0;
    Freitag:BOOL:=0;
    Samstag:BOOL:=0;
END_VAR

VAR_IN_OUT
    // Durchgangsparameter
END_VAR

VAR_OUTPUT
    // Ausgangsparameter
Ausgang:BOOL;
END_VAR

VAR_TEMP
    // temporäre Variablen
END_VAR

VAR
    // statische Variablen
SPS_DT:DATE_AND_TIME;
SPS_TOD:TOD;
SPS_DAY:INT;
RetVal:INT;
DAY_CHECK:BOOL;
END_VAR

BEGIN
// Anweisungsteil
// Datum und Uhrzeit holen
RetVal := SFC1(CDT:= SPS_DT);
// DATE aus DATE_AND_TIME holen
SPS_DAY:= FC7 (IN:= SPS_DT);
// DAY_TIME aus DATE_AND_TIME holen
SPS_TOD:= FC8 (IN:= SPS_DT);

// Vergleicht aktuelles Datum mit Eingangsbeschaltung
// Wenn Eingangsbeschaltung mit aktuellem Datum übereinstimmt
// wird DAY_CHECK = TRUE
IF Sonntag AND SPS_DAY=1 THEN DAY_CHECK:=1;
ELSIF Montag AND SPS_DAY=2 THEN DAY_CHECK:=1;
ELSIF Dienstag AND SPS_DAY=3 THEN DAY_CHECK:=1;
ELSIF Mittwoch AND SPS_DAY=4 THEN DAY_CHECK:=1;
ELSIF Donnerstag AND SPS_DAY=5 THEN DAY_CHECK:=1;
ELSIF Freitag AND SPS_DAY=6 THEN DAY_CHECK:=1;
ELSIF Samstag AND SPS_DAY=7 THEN DAY_CHECK:=1;
ELSE DAY_CHECK:=0;
END_IF;

// Vergleicht Einschaltzeit mit aktueller Tageszeit (TIME_OF_DAY) und frägt DAY_CHECK ab.
// Bei positivem VKE Ausgang = TRUE.
// Bei Ausschaltzeit fällt DAY_CHECK weg (bei Tageswechsel soll die Anlage weiterlaufen).
// Ist Ausschaltzeit kleiner oder gleich TIME_OF_DAY Ausgang = FALSE.
IF (Einschaltzeit <= SPS_TOD) AND DAY_CHECK THEN Ausgang:=1;
ELSIF (Ausschaltzeit <= SPS_TOD) AND Ausgang THEN Ausgang:=0;
END_IF;
    ;
END_FUNCTION_BLOCK

Funktionieren tuen sie. aber das sollte ja nicht nur das hauptziel sein. Dass der Baustein irgendwie funktioniert. egal wie er ausschaut oder wie schlecht programmiert

bitte um eueren rat.

Danke
 
Zu 1:
- Goto rauswerfen
- Sekundenzähler vom Typ DINT anlegen (geht zwar hier auch mit Real mit ausreichender Genauigkeit, aber für sowas ist eine Ganzzahl besser geeignet)
- Prüfen ob die Variablen E1 bis E4 wirklich notwendig sind, bzw. ob diese unbedingt statische Variablen sein müssen
- Den Ausgabetyp 'sinnvoll' vorbelegen. Wenn er jetzt nicht beschaltet wird hat er den Wert 0. Was dann?

Zu 2:
- Case Anweisung ansehen
- Anstelle absoluter Adressen wie FC7 oder FC8 den symbolischen Namen verwenden
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Und mir nur mal kurz sagen, was man verbessern könnte oder was ich falsch gemacht habe
wills ja richtig lernen.
Deine Wochenzeitschaltuhr funktioniert nur wenn sich Ein- und Ausschaltzeitpunkt sich im gleichen Tag befinden.
Folgende Schaltmöglichkeiten sind z.B. nicht möglich:
Ein: Montag 22:00 - Aus: Dienstag 4:00
Ein: Mittwoch 5:00 - Aus: Sonntag 5:00
 
1.
-warum soll man goto nicht verwenden? wird meiner meinung nach benötigt, damit er immer höher zählt.
- ja kann ich verstehen DINT wäre besser
- man könnte auch temp nehmen denk ich. aber variablen zum merken der ergebnisse sind doch notwendig oder?
- wenn ich alle zahlen um eins runter nehme dann wäre stunden 0. oder ich mach einfach Ausgabetyp:INT:=1;

2.
-case anweisung: du meinst wahrscheinlich bei DAY_CHECK oder?
habe ich mir angeschaut. aber

case SPS_DAY of
1: ???
ich müsste ja schreiben
1: AND Sonntag then DAY_CHECK:=1;
oder wie meinst du

- macht das irgendeinen unterschied? außer vielleicht, dass man schneller erkennt was der bausten macht.

danke
 
Deine Wochenzeitschaltuhr funktioniert nur wenn sich Ein- und Ausschaltzeitpunkt sich im gleichen Tag befinden.
Folgende Schaltmöglichkeiten sind z.B. nicht möglich:
Ein: Montag 22:00 - Aus: Dienstag 4:00
Ein: Mittwoch 5:00 - Aus: Sonntag 5:00

hmm
ich denke schon
ich den baustein zwar nur kurz getestet aber

Code:
IF (Einschaltzeit <= SPS_TOD) AND DAY_CHECK THEN Ausgang:=1;
ELSIF (Ausschaltzeit <= SPS_TOD) AND Ausgang THEN Ausgang:=0;
END_IF;

Er fängt an wenn die Einschaltzeit gleich oder kleiner der TIME_OF_DAY ist und DAY_CHECK auch in ordnung ist.

und läuft so lange bis die ausschaltzeit kleiner oder gleich TIME_OF_DAY ist und Ausgang gesetzt ist.

habe mir darüber schon gedanken gemacht.
deshalb habe ich bei ausschaltzeit den day_check weggelassen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
-warum soll man goto nicht verwenden? wird meiner meinung nach benötigt, damit er immer höher zählt.

In deinem Programm lassen sich die Gotos doch sehr einfach ersetzen
Code:
IF Reset THEN
    // Irgendwas rücksetzen
END_IF;
und
Code:
IF Takt THEN
   // Befehle die beim Takt ausgeführt werden sollen
END_IF;


- man könnte auch temp nehmen denk ich. aber variablen zum merken der ergebnisse sind doch notwendig oder?
Du kannst doch einfach je nach Ausgabetyp die Berechnung in einer Zeile hinschreiben. In deinem Fall machen diese Zwischenvariablen das jetzt nicht unbedingt übersichtlicher. Eine Umrechnung von Sekunden in Minuten/Stunden lässt sich wohl noch einfach überblicken.
Z.B. mit einem Case:
Code:
CASE Ausgabetyp OF
    // Sekunden
    1: Betriebsstunden := ((Sekunde/60)/60);
    // Minuten
    2: Betriebsstunden := 
    ...

-case anweisung: du meinst wahrscheinlich bei DAY_CHECK oder?
habe ich mir angeschaut. aber

case SPS_DAY of
1: ???
ich müsste ja schreiben
1: AND Sonntag then DAY_CHECK:=1;
oder wie meinst du

- macht das irgendeinen unterschied? außer vielleicht, dass man schneller erkennt was der bausten macht.

Ja stimmt, so wie du es jetzt hast ist es mit einer IF-Konstruktion etwas einfacher.
Aber mit dem Case-Beispiel von dir würden auch die Zeilen
Code:
DAY_CHECK := false;
CASE SPS_DAY OF
   1: DAY_CHECK := Sonntag;
   2: DAY_CHECK := Montag;
...
reichen. Denn wenn der Code hier erreicht wird hat SPS_DAY ja den richtigen Wert.
 
Aber du weißt doch gar nicht an welchem Tag ausgeschaltet werden soll.
Montag bis Mittwoch geht nicht.

ich hab mir das so gedacht.
hab den code heute nochmal angeschaut und überbessert.
hier schaltet er nämlich nicht aus wenn day_check noch 1 ist.

aber er weiß doch wann er ausschalten soll oder?

wenn ich auf montag dienstag und mittwoch true gebe
und ein bei 22:00uhr und aus bei 2:00uhr nachts dann schaltet er jeweils am montag dienstag und mittwoch um 22uhr abend ein und am darauffolgenden tag wieder aus.
also auch wenn donnerstag nicht aktiv ist läuft er donnerstags bis 2:00uhr

sobald ein tag z.b. donnerstag hier kein true hat ist day_check 0 und donnerstags um 22:00uhr wird nicht mehr eingeschaltet


danke für eure tipps
 
Zuviel Werbung?
-> Hier kostenlos registrieren
[/QUOTE]
Du kannst doch einfach je nach Ausgabetyp die Berechnung in einer Zeile hinschreiben. In deinem Fall machen diese Zwischenvariablen das jetzt nicht unbedingt übersichtlicher. Eine Umrechnung von Sekunden in Minuten/Stunden lässt sich wohl noch einfach überblicken.
Z.B. mit einem Case:
Code:
CASE Ausgabetyp OF
    // Sekunden
    1: Betriebsstunden := ((Sekunde/60)/60);
    // Minuten
    2: Betriebsstunden := 
    ...
[/QUOTE]

Die Berechnung ja
aber ich benutze die variablen dazu, dass die nachkommastellen konstant bleiben und nicht mal 0,25 und dann 0,35646546
kann ich das auch irgendwie ohne diese variablen lösen?
dankeschön
 
@TE:
Das war das Thema dieses Thread :
.. Habe jetzt mal 2 kurze Bausteine programmiert.
Könnt ihr die mal anschauen? Und mir nur mal kurz sagen, was man verbessern könnte oder was ich falsch gemacht habe
wills ja richtig lernen.

.....

Funktionieren tuen sie. aber das sollte ja nicht nur das hauptziel sein. Dass der Baustein irgendwie funktioniert. egal wie er ausschaut oder wie schlecht programmiert

bitte um eueren rat.
... und genau diesen Sinn hatten die Antworten von Thomas und Paule ...
 
Kleine Anmerkung noch zu den Kommentaren in einem SCL Baustein.

zwischen TITLE und AUTHOR Zeile kann man noch eine Beschreibung des Bausteins schreiben.

Code:
TITLE = 'Betriebsstundenzähler'
// Dieser Baustein zählt die Betriebsstunden
// V1.0 erste veröffentlichte Version
// V1.1 verbesserung in der Performance
 VERSION : '1.1'

Das hat den Vorteil das der übersetzte Baustein über eine Beschreibung der Funktion verfügt, selbst wenn die Quelle nicht mitgegeben wird oder der Instandhalter nicht über SCL verfügt.

Dieser Kommentar taucht dann wenn man per Rechtsklick auf den Baustein -> Eigenschaften öffnet. Im Allgemeinen Teil als Kommentar auf.


Danach in der Schnittstellendeklaration alle IN, OUT und INOUT Variablen und wenn möglich auch die Temp und Stat Variablen mit einem Kommentar versehen

Code:
VAR_INPUT
     ID : INT ;   // Adresse des Modules im Bus 
    CHA : INT ;   // Kommunikationskanal z.B. 3 für Com3 
    CHF : DWORD ; // Konfigurationsmaske für Zählerkonfiguration

Wenn man das so macht ist dieser Kommentar sowohl in der übersetzten Schnittstelle sichtbar als auch wenn man einen Call Aufruf macht in jedem Feld das man anklickt.
Test_2.jpg


So erkennt auch jemand anderes was an einer Schnittstelle erwartet wird und um was es geht. Ohne das zuerst Dokumentation in 4 Ordner verteilt gewälzt werden muss.

mfG René
 
Zurück
Oben