Step 7 6. Potenz einer beliebigen BCD Zahl in Strep7 (SCL)

Tyson92

Level-1
Beiträge
18
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Morgen,

im Rahmen meines Mechatronik Studiums muss ich die folgende Aufgabe bearbeiten.
1.JPG
Diese soll ich in STEP 7 und in der Sprache SCL schreiben.

Das Projekt habe ich mit einer CPU 412-2D erstellt und eine SCL Datei erzeugt.
Die Verwirklichung mit Akku 1 ist für mich unklar. Mein aktueller Lösungsansatz sieht so aus:

Code:
FUNCTION FC1 : VOID                     // Erzeugen der Funktion FC1
   
   
VAR_TEMP              
    Int_MW100:INT;            // Variable fuer die Umwandlung in Int
    Real_Ergebnis:REAL;        // Variable Ergebnis der Potenzrechnung
END_VAR




Int_MW100:= BCD_TO_INT(Merkerwort100);  // MW 100 (BCD) in INT umwandeln    




Real_Ergebnis:= Int_MW100**6;        // Potenzrechnung 


                    // Rückgabe/Ausgabe des Ergebnis (fehlt noch)


END_FUNCTION

Leider weiß ich nicht ob es der Vorgabe durch die Grafik entspricht oder ob ich auf dem Holzweg bin.
Ich hoffe ihr könnt mir weiter helfen.

Grüße
 
Sieht so aus, als ob ihr das in AWL lösen sollt, suche mal nach dem Akku-Befehl (PUSH).
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Die Grafik entspricht einer AWL-Lösungsvorgabe aber leider ist diese nicht ganz richtig im Bezug zur Aufgabe (spezieller Professor).
In der übergeordneten Aufgabenstellung wird die Programmierung in SCL verlangt.
 
Na ja, dann ist doch die Ausführun in SCL ok.
Außerdem ist es ratsam, die richtigen Typumwandlungen vorzunehmen. Der Compiler macht zwar einige automatisch, aber dann muß man schon wissen, was er wie macht.

In deinem Fall:

Int_MW100 --> in Real wandeln vor Vwerwendung

Hier würde es aber wahrscheinlich ohne Typwandlung gehen, das kannst du ja mal austesten.
 
Ich hatte die BCD-Zahl aus Merkerwort100 in INT umgewandelt nach Aufgabenstellung.
Eigentlich wollte ich die Rechnung in INT machen, also die Potenzrechnung aber ich konnte das Ergebnis nicht in INT_Ergebnis abspeichern, dass ging nur mit REAL_Ergebnis.

Ist die Speicherung in INT nicht möglich und ich sollte dann vorher aus Int_MW100 dann Real_MW100 machen?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe es nun so gelöst und hoffe es ist richtig im Bezug der Typenwandlung:

Code:
FUNCTION FC1 : VOID                     	// Erzeugen der Funktion FC1
   


// Hilfsvariablen deklarieren   
VAR_TEMP              
    Int_MW100:INT;                      	// Variable fuer die Umwandlung in Int
    Real_Ergebnis:REAL;                 	// Variable Ergebnis der Potenzrechnung
    Real_MW100: REAL;                   	// Variable fuer Umwandlung in REAL
    Int_Ergebnis:INT;                   	// Variable fuer Umwandlung in Int
END_VAR


// Umwandlungen für Rechnung
Int_MW100:= BCD_TO_INT(Merkerwort100);          // MW 100 (BCD) in INT umwandeln (Mekerwort100 ist MW100 in Symboltabelle)  


Real_MW100:= INT_TO_REAL (Int_MW100);           // Int_MW100 in Real_MW100 umwandeln


// Rechnung 
Real_Ergebnis:= Real_MW100**6;                  // Potenzrechnung im Format REAL 


// Umwandlung / Ausgabe des Ergebnis
Int_Ergebnis:= REAL_TO_INT (Real_Ergebnis);     // Ergebnis der Rechnung von REAL in INT


Ergebnis:= INT_TO_BCD (Int_Ergebnis);           // Ergebnis von INT in BCD umwandeln und in Symbol Ergebnis schreiben, steht fuer MW3 in Symboltabelle




END_FUNCTION 					// Ende der Funktion FC1
 
Hallo,

mal davon abgesehen, das man für so eine Aufgabe (Berechnung der Potenz für einen Wert) nicht direkt aus und in Merkern lesen oder schreiben sollte (besser wäre mit Eingangs- und Ausgangsvariable zu arbeiten), gehe ich davon aus, daß die Verwendung der integrierten Potenzfunktion nicht gewünscht wird. Gerade da das Bild mit angegeben ist.

Ich vermute mal die Aufgabe soll nur mit einfacher Multiplikation und Schleife verwendet werden. Dann benötigst Du auch nur die Wandlung von BCD in Int und zurück.

Gruß
 
Zuletzt bearbeitet:
Wobei es in AWL da auch keine direkte Potenzfunktion bei beliebiger Basis und Exponent gibt, das muss man auch über die entsprechende Logarithmengesetze umstellen mit x^n = e^(n*ln(x)) für die es dann in AWL entsprechende Operationen gibt.

Wenn das Ergebnis in ein Merkerwort (d.h. 16 Bit) passen soll, dann könnte man auch eine einfache Tabelle/Sprungliste an Abhängigkeit von x einsetzen, denn es passt ja nur noch 5^6 in ein Integer, und bei BCD Kodierung sogar nur noch 3^6, d.h. vier mögliche Eingabewerte 0, 1, 2 und 3 die überhaupt erlaubt sind damit das Ergebnis wieder BCD kodiert in ein Wort passt.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Bei der Wahl zwischen Cholera und Pest hätte ich mich für DINT entschieden. Oder habe ich in der Aufgabenstellung etwas übersehen? Und das OK-Flag sollte man abfragen. Vielleicht zielt die Übung genau auf die Bereichsüberschreitung?
 
Zuletzt bearbeitet:
Die Überlegung mit der Schleife ist ein guter Einwand, wahrscheinlich entspricht es mehr der Aufgabenstellung.
Ich habe es nun nochmal zu einem Schleifenkonstrukt geändert.
Code:
FUNCTION FC1 : VOID                             // Erzeugen der Funktion FC1
   


// TEMP Hilfsvariablen deklarieren   
VAR_TEMP              
    Int_MW100:INT;                              // Variable fuer die Umwandlung in Int
    Int_Ergebnis:INT;                           // Variable fuer Umwandlung in Int
    Index:INT;                                  // Laufvariable
    Int_MW100Konstant: INT;                    // Konstante fuer Potenzrechnung
END_VAR




// Umwandlungen für Rechnung
Int_MW100:= BCD_TO_INT(Merkerwort100);          // MW 100 (BCD) in INT umwandeln (Mekerwort100 ist MW100 in Symboltabelle)  




// Speichern von konstanten Wert fuer Potenz
Int_MW100Konstant:=Int_MW100; 




// For Schleife fuer Potenzrechnung
FOR INDEX:= 0 TO 6 BY +1 DO                    // Laufvrariable laeuft noch 0 bis 6 


Int_MW100:= Int_MW100*Int_MW100Konstant;       // Bereits berechneter Wert mal Konstanten Wert  


END_FOR;




Ergebnis:= INT_TO_BCD (Int_MW100);               // Ergebnis von INT in BCD umwandeln und in Symbol Ergebnis schreiben, steht fuer MW3 in Symboltabelle




END_FUNCTION                                    // Ende der Funktion FC1

Die Schleife zählt nur scheinbar weiter als gewollt. Bei der Berechnung von 2^6 erhalte ich 256. Ich weiß leider nicht genau warum diese dann bis 2^8 durchläuft.
Ich denke ich brauche noch eine Abfrage von der Laufvariable wie z.B. in Java, allerdings weiß ich nicht wie ich es hier umsetzen sollte.

Wenn ich nicht direkt in den Merkern schreiben und lesen sollte, soll ich diese dann am Anfang in eine Variable schreiben und am Ende die Variable wieder in den Merker schreiben?
 
Zuletzt bearbeitet:
1. Dein Index läuft bei 0 los, also grehst du 7 Mal durch die Schleifen, von 0 bis 6.
2. in deiner Schleife passiert also Folgendes:

0
2*2

4
1
2*4

8
2
2*8

16
3
2*16

32
4
2*32

64
5
2*64

128
6
2*128

256

Du mußt die Schleife von 0 bis 4 laufen lassen oder von 1 bis 5, ja nachdem, wie du es vom Aussehen her besser findest.
 
bei x^n = e^(n*ln(x))
habe ich immer im Hinterkopf wieviel Operationen die Berechnung von exp() und ln() kosten.
Wenn klar ist, dass es eine ganze Potenz reicht doch ausmultiplizieren.
Wenn zudem immer die 6. berechnet werden soll, hallte ich auch die Schleife für aufwendiger als:
intvar:=BCT_TO_INT(Merkerwort100);
dintvar:=intvar*intvar; // x**2
dintvar:=dintvar*intvar; // x**3
dintvar:=dintvar*dintvar; // x**6
 
bei x^n = e^(n*ln(x))
habe ich immer im Hinterkopf wieviel Operationen die Berechnung von exp() und ln() kosten.

Aus der SCL Operation ** (also x**n) macht der SCL Übersetzer dann eine entsprechende AWL Sequenz nach den Rechenregeln.

Ich hatte mal ein paar mehr von den Siemens ET200SP Energiemesskarten zu verarbeiten, die ihre Werte getrennt in Basis und Exponent übertragen. Meine Auswertefunktion pro Karte hatte ich in SCL verfasst, und so ein basis**exponent ist ja schnell hingeschrieben. Bis ich dann feststellte, dass die Zykluszeit wirklich exorbitant in die Höhe ging und ich die Auswertung umschreiben musste.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
Wenn ich nicht direkt in den Merkern schreiben und lesen sollte, soll ich diese dann am Anfang in eine Variable schreiben und am Ende die Variable wieder in den Merker schreiben?

Damit das nicht unbeantwortet bleibt:

Code:
FUNCTION FC1 : WORD                             // Erzeugen der Funktion FC1 mit Rückgabewert
   
VAR_INPUT
    Wert:WORD;
END_VAR


// TEMP Hilfsvariablen deklarieren   
VAR_TEMP              
    Int_MW100:INT;                              // Variable fuer die Umwandlung in Int
    Int_Ergebnis:INT;                           // Variable fuer Umwandlung in Int
    Index:INT;                                  // Laufvariable
END_VAR


// Umwandlungen für Rechnung
Int_MW100:= BCD_TO_INT(Wert);          // an Eingangsvariable Wert (BCD) übergebene Zahl in INT umwandeln   


// Speichern von konstanten Wert fuer Potenz
Int_Ergebnis:=Int_MW100; 


// For Schleife fuer Potenzrechnung
FOR INDEX:= 1 TO 5 BY +1 DO                    
    Int_Ergebnis:= Int_Ergebnis*Int_MW100;       // Bereits berechneter Wert mal Konstanten Wert  
END_FOR;


FC1:= INT_TO_BCD (Int_Ergebnis);                // Ergebnis von INT in BCD umwandeln und in Rückgabewert schreiben
END_FUNCTION                                    // Ende der Funktion FC1
und noch einmal ohne Schleife
Code:
FUNCTION FC1 : WORD                             // Erzeugen der Funktion FC1 mit Rückgabewert
   
VAR_INPUT
    Wert:WORD;
END_VAR


// TEMP Hilfsvariablen deklarieren   
VAR_TEMP              
    Int_MW100:INT;                              // Variable fuer die Umwandlung in Int
    Int_Ergebnis:INT;                           // Variable fuer Umwandlung in Int
END_VAR


// Umwandlungen für Rechnung
Int_MW100:= BCD_TO_INT(Wert);                   // an Eingangsvariable Wert (BCD) übergebene Zahl in INT umwandeln   




Int_Ergebnis:=Int_MW100; 
Int_Ergebnis:= Int_Ergebnis*Int_MW100;          // ^2  
Int_Ergebnis:= Int_Ergebnis*Int_MW100;          // ^3  
Int_Ergebnis:= Int_Ergebnis*Int_MW100;          // ^4  
Int_Ergebnis:= Int_Ergebnis*Int_MW100;          // ^5  
Int_Ergebnis:= Int_Ergebnis*Int_MW100;          // ^6  


FC1:= INT_TO_BCD (Int_Ergebnis);                // Ergebnis von INT in BCD umwandeln und in Rückgabewert schreiben
END_FUNCTION                                    // Ende der Funktion FC1


Aufruf erfolgt dann .B. unter SCL mit
Code:
Ergebnis:=FC1(Wert:=Merkerwort100);


Siehe auch hier: https://support.industry.siemens.co...angsparameter-ret_val-verfügt-?dti=0&lc=de-WW


Gruß
 
Ich habe mal folgendes Testprogramm auf eine S7-1214C (...AG40...,Firmware 4.2.1, TIA 14.0) geladen.
Zykluszeitüberwachung auf 1000ms gestellt
Dann habe ich per Beobachtungstabelle die Variable wahl gesteuert und unter Diagnose die aktuelle Zykluszeit abgelesen.
Ergebnisse:
1: 158-173
2: 158-173
3: 50-59
4: 141-154
5 187-202
6: 10-12
7: 9-12
8: 2-3
9: 2
10 9-11
11 8-10
Die Tests 21 bis 31 (Daten im optimierten DB statt im Merkerbereich) brachten dieselben Ergebnisse.
Fazit: x**y ist grottenschlecht umgesetzt, exp(ln(x)) ist besser, ausmultiplizieren ist noch besser, aber nur mit Integer. Der Datentransfer von und zu big endian vintage schadet nicht. Da haben sie möglicherweise einpaar hardwaremäßig gekreuzte Leitungen drin.
Code:
"looplen":=1000;
(* einfacher Test *)
IF "wahl" = 1 THEN
    FOR "i" := 1 TO "looplen" DO
        "realvar" := "i" ** 6;
    END_FOR;
END_IF;
(* Ergebnis Ganzzahl könnte dem Compiler vielleicht zu denken geben *)
IF "wahl" = 2 THEN
    FOR "i" := 1 TO "looplen" DO
        "dintvar" := "i" ** 6;
    END_FOR;
END_IF;
(* produzert weniger Überläufe *)
IF "wahl" = 3 THEN
    FOR "i" := 1 TO "looplen" DO
        "intvar" := "i" MOD 32;
        "dintvar" := "intvar" ** 6;
    END_FOR;
END_IF;
(* exponent als Real angegeben, aber ganz *)
IF "wahl" = 4 THEN
    FOR "i" := 1 TO "looplen" DO
        "realvar" :="i" ** 6.0;
    END_FOR;
END_IF;
(* exponent wirklich "reell" *)
IF "wahl" = 5 THEN
    FOR "i" := 1 TO "looplen" DO
        "realvar" :="i" ** 6.101;
    END_FOR;
END_IF;
(* über Logarithmus *)
IF "wahl" = 6 THEN
    FOR "i" := 1 TO "looplen" DO
        "realvar" := EXP(6.0 * LN("i"));
    END_FOR;
END_IF;
(* über Logarithmus, krummer Exponent *)
IF "wahl" = 7 THEN
    FOR "i" := 1 TO "looplen" DO
        "realvar" := EXP(6.101 * LN("i"));
    END_FOR;
END_IF;
(* Vorschlag im Forum *)
IF "wahl" = 8 THEN  
    FOR "i" := 1 TO "looplen" DO
        "dintvar" := "i";
        "dintvar" := "dintvar" * "dintvar";
        "dintvar" := "dintvar" * "i";
        "dintvar" := "dintvar" * "dintvar";
    END_FOR;
END_IF;
(* 1. Multiplikation kürzer *)
IF "wahl" = 9 THEN
    FOR "i" := 1 TO "looplen" DO
        "intvar" := "i";
        "intvar" := "intvar" * "intvar"; 
        "dintvar" := "intvar" * "i";
        "dintvar" := "dintvar" * "dintvar";
    END_FOR;
END_IF;
(* Rechnung in floating point *)
IF "wahl" = 10 THEN
    FOR "i" := 1 TO "looplen" DO
        "realvar" := "i";
        "realvar" := "realvar" * "realvar";
        "realvar" := "realvar" * "i";
        "realvar" := "realvar" * "realvar";
    END_FOR;
END_IF;

(* Intger nach FP vermeiden, könnte in Registern einer FP-Unit 
    gehalten werden *)
"realcnt" := 0;
IF "wahl" = 11 THEN
    FOR "i" := 1 TO "looplen" DO
        "realcnt" := "realcnt" + 1.0;
        "realvar" := "realcnt" * "realcnt";
        "realvar" := "realvar" * "realcnt";
        "realvar" := "realvar" * "realvar";
    END_FOR;
END_IF;

(* Und nun nochmal alles mit Variablen in einem optimierten DB *)

IF "wahl" = 21 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."realvar" := "i" ** 6;
    END_FOR;
END_IF;
IF "wahl" = 22 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."dintvar" := "i" ** 6;
    END_FOR;
END_IF;
IF "wahl" = 23 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."intvar" := "i" MOD 32;
        "d"."dintvar" := "d".intvar ** 6;
    END_FOR;
END_IF;
IF "wahl" = 24 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."realvar" := "i" ** 6.0;
    END_FOR;
END_IF;
IF "wahl" = 25 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."realvar" := "i" ** 6.101;
    END_FOR;
END_IF;
IF "wahl" = 26 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."realvar" := EXP(6.0 * LN("i"));
    END_FOR;
END_IF;
IF "wahl" = 27 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."realvar" := EXP(6.101 * LN("i"));
    END_FOR;
END_IF;
IF "wahl" = 28 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."dintvar" := "i";
        "d"."dintvar" := "d"."dintvar" * "d"."dintvar";
        "d"."dintvar" := "d"."dintvar" * "i";
        "d"."dintvar" := "d"."dintvar" * "d"."dintvar";
    END_FOR;
END_IF;
IF "wahl" = 29 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."intvar" := "i";
        "d"."intvar" := "d"."intvar" * "d"."intvar";
        "d"."dintvar" := "d"."intvar" * "i";
        "d"."dintvar" := "d"."dintvar" * "d"."dintvar";
    END_FOR;
END_IF;
IF "wahl" = 30 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."realvar" := "i";
        "d"."realvar" := "d"."realvar" * "d"."realvar";
        "d"."realvar" := "d"."realvar" * "i";
        "d"."realvar" := "d"."realvar" * "d"."realvar";
    END_FOR;
END_IF;
IF "wahl" = 31 THEN
    FOR "i" := 1 TO "looplen" DO
        "d"."realcnt" := "d"."realcnt" + 1.0;
        "d"."realvar" := "d"."realcnt" * "d"."realcnt";
        "d"."realvar" := "d"."realvar" * "d"."realcnt";
        "d"."realvar" := "d"."realvar" * "d"."realvar";
    END_FOR;
END_IF;
 
Die Schleife zählt nur scheinbar weiter als gewollt. Bei der Berechnung von 2^6 erhalte ich 256. Ich weiß leider nicht genau warum diese dann bis 2^8 durchläuft.
"Nur scheinbar"?

x^0 = 1
x^1 = x
x^2 = x * x
x^3 = x * x * x
x^4 = x * x * x * x
x^5 = x * x * x * x * x
x^6 = x * x * x * x * x * x

Zähl mal die '*' zwischen den 'x'!
Bei x^6 gibt es 5 Multiplikationen, die ausgeführt werden müssen.
Also Exponent - 1 = Anzahl Multiplikatonen = Anzahl SchleifenDurchläufe.
Deine SchleifenDurchläufe von 0 bis 6 sind aber 7 ... also 2 zuviel!

Wenn ich nicht direkt in den Merkern schreiben und lesen sollte, soll ich diese dann am Anfang in eine Variable schreiben und am Ende die Variable wieder in den Merker schreiben?
Und vergiss nicht das Ergebnis wieder in BCD zu wandeln und an den DekadenEinsteller zurückzuschicken!? :ROFLMAO:

Was sagen denn Dein "spezieller Professor" und die "übergeordnete Aufgabenstellung" dazu?

Gruss, Heinileini
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wie sollen denn unzulässige Eingangswerte bzw. inkorrekte Ergebnisse signalisiert werden?

Wenn das Ergebnis in ein Merkerwort (d.h. 16 Bit) passen soll, dann könnte man auch eine einfache Tabelle/Sprungliste an Abhängigkeit von x einsetzen, denn es passt ja nur noch 5^6 in ein Integer, und bei BCD Kodierung sogar nur noch 3^6, d.h. vier mögliche Eingabewerte 0, 1, 2 und 3 die überhaupt erlaubt sind damit das Ergebnis wieder BCD kodiert in ein Wort passt.
Code:
FUNCTION FC1 : WORD
VAR_INPUT
    Wert : WORD;
END_VAR
VAR_TEMP              
    BCD_Ergebnis : WORD;
END_VAR

  CASE WORD_TO_INT(Wert) OF
    0 : BCD_Ergebnis := 0 ;
    1 : BCD_Ergebnis := 1 ;
    2 : BCD_Ergebnis := 16#64 ;
    3 : BCD_Ergebnis := 16#729 ;
    4 : BCD_Ergebnis := 16#4096 ; //soll evtl. schon unzulässig sein?
  ELSE:
        BCD_Ergebnis := 16#9999 ; //Ergebnis-Ersatzwert bei unzulässigen Eingangswerten
        OK := FALSE;              //Ergebnis als inkorrekt signalisieren
  END_CASE;

  FC1 := BCD_Ergebnis;            //Ergebnis in FC-Rückgabewert schreiben
END_FUNCTION

Harald
 
Es ist doch an den Haaren herbei gezogen, dass das Ergebnis in ein Wort passen muss oder gar BCD-codiert sein soll. Wer tut sich denn so eine irrsinnige Fehlinterpretation an?

Was man jedoch nicht verhindern kann ist eine Bereichsüberschreitung. Selbst wenn nur zwei Dekaden des BCD-Schalters verwendet werden(?), so wäre das Ergebnis eine 12-stellige Zahl. Selbst ein Dint ist nur 10-stellig. Verhindern kannst du diese Bereichsüberschreitung nicht, aber erkennen kannst du sie. Wenn ich der Professor wäre, dann würde ich das selbstverständlich prüfen ;) .
 
Vielen Danke für die ausführliche Antwort.
Mir ist allerdings nun unklar wie ich diese veränderte Funktion über die Beobachtungstabelle steuern kann, bzw. wie ich dann die Werte zum Testen übergeben muss. Muss ich dann noch Änderungen in der Symboltabelle vornehmen?
 
Zurück
Oben