Frage zu meinem Baustein

Gini

Level-1
Beiträge
32
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Leute,

ich hätte da mal gerne eine Frage zu meinem Baustein gestellt.

Folgende Sache: Ein Kunde von mir möchte gerne auf der Visu (flex 2008) sehen, wieviel "KW" laut Typenschild momentan aktiv sind.
Ich habe mir jetzt einen Baustein gebastelt der auch wunderbar funktioniert. Über eine Schleife wird jeder einzelne Ausgang auf "True" abgefragt und gegebenenfalls der entsprechende Wert addiert.

Ich habe also in meinem Fall die Ausgänge 0.0 - 19.7. Dementsprechend habe ich mir einen DB mit den Werten angelegt. Heisst, ich habe pro Ausgang einen Realwert hinterlegt. (Bei reversierantrieben natürlich dann den Wert für beide Ausgänge eingegeben).

Ausgänge die keinerlei Bänder oder andere Verbraucher schalten habe ich auf Real 0.0 im DB gesetzt.

Meine Frage bezieht sich jetzt eigentlich nur darauf, ob diese Programmierung so in Ordnung wäre oder man noch etwas einkürzen könnte.

Wäre lieb wenn sich das mal jemand anschauen könnte. Ich rufe den FC übrigens im OB35 (100ms) auf.


MfG, Iris

Code:
      CALL  "KW-Berechnung"
       KW_DB         :="KW-Werte"
       Adresse_Anfang:=L#0
       Adresse_Ende  :=L#19
       KW_OUT        :=MD10

Code:
      AUF   #KW_DB
      L     #Adresse_Anfang
      T     #Byte_Adresse
      L     0
      T     #Bit_Adresse
      L     0.000000e+000
      T     #KW
m002: L     #Byte_Adresse
      SLD   3
      LAR1  
      L     #Bit_Adresse
      +AR1  
      U     A [AR1,P#0.0]
      SPBN  m001
      L     #Byte_Adresse
      L     32
      *D    
      T     #Temp1
      L     #Bit_Adresse
      L     4
      *D    
      T     #Temp2
      L     #Temp1
      L     #Temp2
      +D    
      T     #Temp3
      SLD   3
      LAR1  
      L     DBD [AR1,P#0.0]
      L     #KW
      +R    
      T     #KW
m001: L     #Bit_Adresse
      L     1
      +D    
      T     #Bit_Adresse
      L     7
      >D    
      SPBN  m002
      L     0
      T     #Bit_Adresse
      L     #Byte_Adresse
      L     1
      +D    
      T     #Byte_Adresse
      L     #Adresse_Ende
      >D    
      SPBN  m002
      L     #KW
      T     #KW_OUT
      SET   
      SAVE  
      CLR
 
Mal gaaanz prinzipiell. Wenn ein Motor zB. 7,5 kW laut Typenschild hat dann bedeutet das doch nicht, daß auch 7,5 kW abgerufen werden. Motoren im Maschinenbau laufen praktisch nie unter Volllast. Damit ist das was Du machst eigentlich bestenfalls ein Schätzeisen.
Ich hätte in die Zuleitung eine Stromwandler eingebaut, auf einen Analogeingang gegeben und dan in der S7 die Leistung berechnet. Das wäre zwar immer noch nicht genau aber bviel besser als das was du da machst.
Allermindestens würde ich im Betrieb mal die real existierenden Ströme der Antriebe ( oder sonstigen Verbraucher ) messen und diese in den DB schreiben.

peter(R)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Code

Hi Peter,

das ist mir und dem Kunden auch bewusst. Er ist halt ein neugieriger Mensch :D. Hat hier immer seine Aufstellung mit den KW-Angaben. Nun würde er es halt gerne angezeigt bekommen. (Nur der Neugier wegen). Soll mein Problem nicht sein solange er meine Zeit bezahlt.
Das mit dem tatsächlichen Messen der Leistung aller Antriebe lasse ich mal lieber bleiben. Das wird mir etwas zuviel :D.
Mit dem Stromwandler in der Zuleitung habe ich Ihm auch vorgeschlagen. Wird wahrscheinlich demnächst auch dazwischengebaut.

Es ging mir in erster Linie auch nur darum, ob man meinen Code (ich habe relativ lange daran getüftelt) vielleicht noch etwas verbessern kann. Funktionieren tut er einwandfrei. Aber vielleicht habe ich es mir ja auch etwas zu umständlich gemacht.

Durch seinen Wunsch konnte ich endlich mal etwas mit Pointern probieren. Habe ich vorher noch nie so richtig gemacht.
Daher bin ich eigentlich froh dass ich wieder etwas dazugelernt habe.
 
Zuletzt bearbeitet:
Was noch am Programm zu vereinfachen wäre (ich würds aber so lassen, wenn es denn nun geht :) )ist, daß du eigentlich keine Trennung zwischen Bit und Byte benötigst. Mit dem Befehl SLD 3 erzeugst du ja einen Zeiger. Die rechten 3 Bit repräsentieren dabei im Zeiger die Bitadresse. Durch SLD 3 ist die erstmal 0, da ja die rechten Bits erstmal einfach mit Null aufgefüllt wurden.

Wenn man sich nun mal die Zeiger für einige Byte ansieht:
0 SLD 3 --> 0*2*2*2 = 0
1 SLD 3 --> 1*2*2*2 = 8
2 SLD 3 --> 2*2*2*2 = 16
3 SLD 3 --> 3*2*2*2 = 24
.
.
.
19 SLD 3 --> 19*2*2*2 = 152

Du kannst also einfach den Zeiger einmal am Anfang mit SLD 3 erzeugen und dann je Bit immer einfach nur 1 aufaddieren auf den Zeiger! Die Abbruchbedingung wäre dann, wenn der Zeiger > Adresse_Ende SLD 3 also größer 152 + 7 (152 entspricht 19.0, 159 entspricht 19.7) ist.
 
Zuletzt bearbeitet:
@peter(R): *ACK*


@ Gini: Hallo Iris, Deine Kommentare im Code sind "spitze":rolleyes:

Code:
      T     #Temp2
      L     #Temp1
      L     #Temp2    //<<< z. B. könnte man das hier weglassen
      +D
es läßt sich immer etwas wegkürzen, aber da kann dann auch die Übersichtlichkeit leiden. Die Funktion ist doch wichtiger solange Speicherplatz und Zykluszeit nicht leiden. Ich finde einige erklärende Kommentare viel nützlicher.

Gruß Soli
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi Gini,
Wie schon gesagt, wären ein paar kommentierende Bemerkungen gut.
Grundsätzlich lässt sich eine Aufgabe auf verschiedenen Wegen lösen. Du hast einen (DEINEN) Weg gewählt und dabei viel gelernt. Das ist Spitze.
Hier mal eine etwas andere Lösung (sie ist aber nicht ausprobiert, ich glaube aber, dass sie funktioniert)
Zur Erklärung:
Deine Bit laufen von 0.0 bis 19.7. Betrachtet man den Speicher als fortlaufende Nummernfolge, werden die Bit 0 bis 159 belegt.
Nimm mal z.B. die Nummer 159 und stelle sie binär dar (159 = 10011 111). Dann entspricht das genau der "richtigen" SPS-Adresse, nämlich 19.7.
Wenn man also programmiert
L 159
LAR1, dann zeigt AR1 genau auf das Bit 19.7 und man kann sofort weiter programmieren
U A[AR1,P#0.0]. Ergebnis: Es ist keinerlei Schieberei erforderlich!
Wie ist das bei der indirekten Wortadressierung?
Dein "Leistungswert" für Bit 19.7 steht z.B. im DBD100 in den Datenbyte 636...639, also DBD636
Wenn man also programmiert
L 159 damit steht im Akku1(ohne Vornullen) 10011111
SLD 32 jetzt steht im Akku1 (ohne Vornullen) 1001111100000
LAR1 damit steht im AR1 (ohne Vornullen) 1001111100 000, AR1 zeigt deshalb sofort auf die richtige Wortadresse!
L DBD[AR1,P#0.0], damit wird das DW geladen auf das die linken bit des AR1 zeigen. Und das ist genau die Nummer 636.
Da man nun den richtigen Inhalt geladen hat, kann man entsprechend weiter verarbeiten (siehe Beispielprogramm)
Ich wurde oft gefragt, warum Siemens das mit den Adressregistern "so kompliziert" gemacht hat. Das Beispiel zeigt genau den Grund.
Leider wird dieser Zusammenhang bei der Vermittlung der Wortverarbeitung und der indirekten Adressierung zu wenig bekannt gemacht.
Aber schön, dass du dein Problem hier eingestellt hast. Vielleicht hilft es ja dem Einen oder Anderen.
Code:
       AUF  DB      100
       L    0.000000e+00
       T    #KW
       L    #Max_Bitnummer               // Maximale Bitnummer laden
m001  :T    #Zeiger                      // Zeiger initialisieren
       LAR1
       U    A [AR1,P#0.0]                // adressierter Ausgang = 1 ?
       SPBN m002                         // <-- nein, dann springe
       L    #Zeiger                      // ansonsten Zeiger auf DBD ausrichten
       SLD            5
       LAR1
       L    DBD [AR1,P#0.0]              // Leistungswert des Ausganges laden
       L    #KW                          // bisher kummulierten Leistungswert laden
       +R                                // addieren und zwischenspeichern
       T    #KW
m002  :L    #Zeiger                      // Test auf Schleifenende
       LOOP m001
       L    #KW                          // Summenleistung laden
       T    #Leistung                    // und ausgeben
Viel Erfolg weiterhin.
eNDe
 
...
L 159 damit steht im Akku1(ohne Vornullen) 10011111
SLD 32 jetzt steht im Akku1 (ohne Vornullen) 1001111100000
LAR1 damit steht im AR1 (ohne Vornullen) 1001111100 000, ...

ich hoffe das der Wert bei SLD "5" heißen sollte, sonst habe ich nämlich doch nichts verstanden:confused:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
      SET   
      SAVE  
      CLR

Ich mach jetzt zwar schon einige Jahre SPS, aber der Sinn dieser 3 Zeilen als Bausteinabschluß erschliesst sich mir jetzt nicht ganz.
Steht das im Zusammenhang durch den Aufruf im OB35?

Gruß
Dieter
 
Letzte 3 Zeilen

Hallo Blockmove,
Bausteine haben in FUP einen Eingang EN und einen Ausgang ENO. Damit können FUP-Bausteine "in Reihe" geschaltet werden. Ein Baustein in dieser Kette wird nur bearbeitet, wenn der Eingang EN ein 1-Signal führt, bei 0-Signal wird er nicht bearbeitet.
Der tiefere Sinn ist, dass man damit sehr einfach Bausteine aufrufen kann oder eben nicht, andererseits wird über diesen Mechanismus verhindert, dass ein FUP-Baustein bearbeitet wird, wenn der vorherige Baustein ein fehlerhaftes Ergebnis liefert.
Zuständig dafür ist das sog. Bie-Bit. Dieses kann innerhalb des Bausteins beeinflusst werden. Es gibt seinen Inhalt an den ENO-Ausgang aus. Die 3 Zeilen bedeuten also:
SET setze auf jeden Fall das VKE auf 1
SAVE übertrage das VKE in das BIE-Bit (und erlaube damit die fehlerfreie Reihenschaltung)
CLR lösche das VKE (oder besser, schreibe in das VKE eine 0)
Wenn der betrachtete Baustein immer nur alleine verwendet wird, wären die 3 genannten Befehle nicht notwendig.
MfG
eNDe
 
Hallo Blockmove,
Bausteine haben in FUP einen Eingang EN und einen Ausgang ENO. Damit können FUP-Bausteine "in Reihe" geschaltet werden. Ein Baustein in dieser Kette wird nur bearbeitet, wenn der Eingang EN ein 1-Signal führt, bei 0-Signal wird er nicht bearbeitet.
Besten Dank für die Erklärung.
Es ist doch das Schöne an unserem Job, dass es immer was Neues zu entdecken bzw. zu lernen gibt :)

Gruß
Dieter
 
Zuviel Werbung?
-> Hier kostenlos registrieren
BIE-Bit / XOR-Box für KOP

Wissenswertes zum BIE-Bit (weil es hier gerade angesprochen wurde)

Das BIE-Bit kann man beim Beobachten eines Bausteinaufrufs in FUP/KOP direkt sehen.
Ist das BIE-Bit am Bausteinende 1, dann wird der Rahmen der Baustein-Box grün.

Alle SFB und SFC zeigen über das BIE-Bit an, ob die Funktion fehlerfrei ausgeführt wurde.

Das BIE-Bit nutze ich gern in eigenen Analogeingang-Skalierungsbausteinen für die Anzeige
Drahtbruch/Überlauf --> BIE=0 / OK --> BIE=1
Den ENO-Ausgang kann man platzsparend sofort weiterverknüpfen,
z.B.(KOP): ENO|---|NOT|---(#Stoerung)


Mit Hilfe des BIE-Bit kann man sich die in KOP nicht vorhandene XOR-Box selber als FC
programmieren (auch mit mehr als 2 Eingängen):

Code:
FUNCTION FC102 : VOID
TITLE =XOR-Box für KOP
NAME : XOR2

VAR_INPUT
  IN1 : BOOL ;	
  IN2 : BOOL ;	
END_VAR

BEGIN
NETWORK
TITLE =XOR-Verknüpfung auf ENO ausgeben
      X     #IN1; 
      X     #IN2; 
      SAVE  ; 
END_FUNCTION

Einsatz in KOP:
Code:
                  +--------+
                  | FC102  |
                  | "XOR2" |  M10.3    M10.7
------------------|EN   ENO|---| |------( )
                  |        |
  M10.0    M10.1  |        |
---| |------| |---|IN1     |
                  |        |
  M10.2           |        |
---|/|------------|IN2     |
                  +--------+
Gruß
PN/DP
 
Benchmark Rechenzeit vs. Codegröße

Ich rufe den FC übrigens im OB35 (100ms) auf.
Ich würde die KW-Berechnung nicht im OB35 machen, sondern normal irgendwo im OB1-Zyklus.
Im OB35 wird das von vielen Kunden nicht gern gesehen, zumal es nicht zwingend im OB35 sein
muß. Im OB35 erzeugt das schwankende Zykluszeiten.

Ich würde wahrscheinlich die ganze KW-Berechnung nicht in so einer eleganten Schleife machen,
sondern in einem FC die 160 oder weniger Addierungen stupide linear hintereinander schreiben,
da kann man auch besser Sonderfälle berücksichtigen (gleicher Antrieb vorwärts oder rückwärts,
Ausgang ist gar kein Antrieb und/oder soll nicht eingerechnet werden).

Weiter würde ich eventuell die KW-Werte als Festwerte im linearen Programmcode und nicht in
einem DB angeben, um dann wieder Speicherplatz zu sparen (DB mit 160 REAL = 160*4 = 640 Byte).

Ich würde auch darüber nachdenken, ob ich in REAL rechnen muß. Hundertfache KW-INT auf DINT
addieren und am Ende erst zu REAL wandeln und durch 100 teilen: 2 Nachkommastellen.

Code:
//lineares Addieren, KW-Werte aus DB100
      AUF   "KW-Werte"        //DB100
      L     0.000000e+000     //KW-Summe in AKKU1 mit 0.0kW initialisieren

      O     A      0.0        //Antrieb1 vor Ein?
      O     A      0.1        //Antrieb1 rück Ein?
      SPBN  M002
      L     DBD    0          //Antrieb1 KW
      +R

M002: U     A      0.2        //Antrieb2 Ein?
      SPBN  M003
      L     DBD    4          //Antrieb2 KW
      +R

M003: U     A      0.3        //Antrieb3 Ein?
      SPBN  M004
      L     DBD    8
      +R
...
...

M197: U     A     19.7        //AntriebX Ein?
      SPBN  M200
      L     DBD  636          //AntriebX KW
      +R

M200: T     #KW_OUT

Benchmark

Diese Vorschläge fallen mir spontan ein, weil ich schon seit 1996 S7-300 programmiere und die CPUs
damals noch nicht so leistungsfähig waren wie heute.
Ich denke, es wird mal Zeit, die Erfahrungen anhand aktueller CPUs zu überprüfen. Ich habe einen
Benchmarktest der verschiedenen Programmlösungen mit einer CPU 315-2 PN/DP gemacht.

Fazit: Das Ergebnis überrascht mich nun doch ein wenig. Die Rechenzeit-Unterschiede sind nicht
mehr so gewaltig, wie sie noch vor 4 Jahren gewesen wären. Doch wenn es auf kurze und gleichmäßige
Zykluszeit ankommt, ist es immer noch richtig, die lineare Programmierung in Betracht zu ziehen.
Der Programmierer muß entscheiden, ob er lieber kurzen oder lieber schnellen Code will.

Code:
[FONT="Arial"][COLOR="blue"]Befehlsausführungszeiten Festpunktarithmetik und Gleitpunktarithmetik (Angaben von Siemens)[/COLOR][/FONT]

S7-300 CPU                Festpunkt Gleitpunkt
alte Generation
  314/315/315-2DP (2001)    2,0µs     50,0µs
neue Generation mit MMC
  314/315-2 (PN/)DP         2,0µs      3,0µs
  317-2 (PN/)DP             0,2µs      1,0µs
  319-2 PN/DP               0,02µs     0,04µs

Code:
[FONT="Arial"][COLOR="Blue"]Benchmark-Ergebnisse bei kein Ausgang Ein (0%), 50% Ausgänge Ein und alle Ausgänge Ein (100%)
(getestet und gemessen auf CPU 315-2 PN/DP und dann für CPU alte Generation hochgerechnet)[/COLOR][/FONT]

                 MC7-Code + DB   Rechenzeit 0/50/100%   alte CPU 0/50/100%
                     Byte  Byte      ms (gemessen)         ms (berechnet)
Schleife [URL="http://www.sps-forum.de/showthread.php?p=213963#post213963"]Gini[/URL]         184 + 640    2,1 / 2,8 / 3,5       2,1 / 6,6 / 11,0
Schleife [URL="http://www.sps-forum.de/showthread.php?p=213979#post213979"]eNDe[/URL]          70 + 640    1,2 / 1,6 / 1,9       1,2 / 5,4 /  9,4
linear aus DB        1734 + 640    0,4 / 0,5 / 0,6       0,4 / 4,3 /  8,1
linear fest REAL     2012     -    0,4 / 0,4 / 0,5       0,4 / 4,2 /  8,0
linear fest INT      1740     -    0,4 / 0,4 / 0,5       0,4 / 0,4 /  0,5

Es ist zu sehen, daß die Bearbeitungszeiten der Gleitpunktarithmetik so stark verbessert wurden, daß
es praktisch keinen Unterschied mehr macht, ob mit Festpunkt- oder Gleitpunkt-Befehlen gerechnet
wird. (bei der 317 und entsprechend großem Programm könnte man noch drüber nachdenken)

Gegenüber der reinen KW-Addition benötigen Schleifen ein vielfaches an Rechenzeit für die
Adressberechnung, die indirekten Zugriffe und das zwischenspeichern.
(Schleife von Gini: 7-fache Zeit, optimierte Schleife von eNDe: 4-fache Zeit)
Der Programmcode als Schleife ist allerdings wesentlich kürzer und eleganter.

Gerade bei Schleifen lohnt es sich, den Code zu optimieren, Befehle möglichst aus der Schleife
herauszuhalten und/oder Befehle zusammenzufassen (z.B. SLD 5).

Am Code von eNDe kann man fast nichts mehr optimieren.
icon14.gif

Nur das "L #Zeiger" vor dem "SLD 5" ist überflüssig, der Wert ist noch im AKKU1.
Zur Ehrenrettung:
Der Befehl erhöht die Verständlichkeit des Codes und macht bei 100% eingeschalteten Ausgängen
gerade mal 0,032ms mehr Rechenzeit aus.
(ich hätte den Befehl im Quelltext auch hingeschrieben, aber auskommentiert)

Gruß
PN/DP

PS:
In der Abschluß-Sequenz SET + SAVE + CLR von Gini ist CLR eigentlich überflüssig.
Das VKE wird zwar an den aufrufenden Baustein zurückgegeben, kann da aber nicht weiter verknüpft
werden (/ER ist 0), nur einer boolschen Variable zugewiesen werden, und das auch nur in AWL.
 
Zurück
Oben