TIA Warum warnt mich der Compiler?

Ludewig

Level-2
Beiträge
898
Reaktionspunkte
166
Zuviel Werbung?
-> Hier kostenlos registrieren
(Kategorie Perfektionismus)
Manchmal könnte ich am TIA-Compiler "verzweifeln". Für einne anspruchsvollen Kunden benötige ich möglichst warnungsfreien Code. Die zweite Zeile in dem untenstehenden Codefetzen bekomme ich jedoch nicht warnungsfrei, egal welche Umformatierung ich anwende. Eigentlich will ich nur die Nachkommastellen von 0-6 möglichst selbsterklärend errechnen und die hier nicht dargestellte Standardoperation multiplizieren, runden, dividieren ausführen.
Klar, der Baustein funzt auch mit dem Gekringel problemlos. Aber wie kann ich das schreiben, ohne dass gemoppert wird.
Die Meldung lautet: Das Vorzeichen oder die Genauigkeit des Werts können verloren gehen.


Code:
FUNCTION "Kommastellen kürzen" : Real
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      Realzahl : Real;
      Nachkommastellen : USInt;
   END_VAR

   VAR_TEMP
      "Nachkommastellen limitiert" : USInt;
      Faktor : UDInt;
   END_VAR


BEGIN
    #"Nachkommastellen limitiert":= LIMIT(MN:=USInt#0, IN:=#Nachkommastellen, MX:=USInt#6);
    #Faktor := 10 ** #"Nachkommastellen limitiert";
END_FUNCTION
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das Ergebnis der Potenzoperation ** besitzt den Datentyp Real bzw. LReal. Du hast ein implizite Konvertierung auf UDInt. Imho sollte es den Compiler beruhigen wenn du den Ausdruck in ein REAL_TO_DINT oder LREAL_TO_DINT packst.

Wenn du in den Voreinstellungen von TIA die IEC Prüfung aktivierst, werden alle impliziten Datentypkonvertierungen verboten, und du musst immer explizit hinschreiben. Meiner Meinung nach ist diese Einstellung zu bevorzugen, weil es einige Fehler vermeidet.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
"Kategorie Perfektionismus": Wenn ich der Compiler wäre, dann würde ich warnen:
Sie verwenden Leerzeichen in Funktionsnamen und Variablennamen. Siemens wird sich den internationalen Gepflogenheiten anpassen und in einer der nächsten TIA Versionen den Schwachfug mit den Leerzeichen nicht mehr unterstützen!

:cool: Harald
 
Dank an Thomas.
So geht's:
#Faktor := LREAL_TO_UDINT(DInt#10 ** #"Nachkommastellen limitiert");
Übersetzen beendet (Fehler: 0; Warnungen: 0)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wobei ich jetzt nicht wiederfinden konnte, ob LREAL_TO_UDINT rundet oder abschneidet.
Denn intern läuft das vermutlich auf e hoch x heraus, d.h. a hoch x wird in e hoch (x * ln a) umgewandelt. ln a kann vom Compiler ausgerechnet und als Konstante eingesetzt werden, aber z.B. mein Billigtaschenrechner kommt bei der Rechnung von 10 hoch 6 schon auf 999999.99999. Evtl. ist hier ein case für die Fälle 0 bis 6 besser und vor allem schneller (zumindest wenn du vorhast die Funktion x-fach zu verwenden sollte man daran denken).
 
Über eine Case-of-Variante habe ich auch schon nachgedacht. Meine Anfrage bezog sich lediglich auf meine Wissenslücke, dass Int**Int ein LREAL ergibt. In diese Richtung habe ich sowas von überhaupt nicht überlegt.
Es ist auch immer das Spiel, wieviel Komfort man in eine Funktion hineinpackt. Was hilft demjenigen, der den Code später warten muss, was überfordert ihn?
 
Den Faktor 10^(0..6) kann man auch ohne REAL-Wandlung in Ganzzahl berechnen. Etwa so (ungetestet):
Code:
#"Nachkommastellen limitiert" := LIMIT(MN:=0, IN:=#Nachkommastellen, MX:=6);
#Faktor := BCD_TO_UDINT(SHL(IN:= DWORD#1, N:= #"Nachkommastellen limitiert" * 4));
Ich weiß aber nicht ob das in den S7-1x00 effizienter ist.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Eigentlich will ich nur die Nachkommastellen von 0-6 möglichst selbsterklärend errechnen und die hier nicht dargestellte Standardoperation multiplizieren, runden, dividieren ausführen.
Warum eigentlich willst Du die Nachkommastellen ermitteln und limitieren (Abschneiden? Runden?) ? Reicht das nicht, wenn Du in der HMI die Anzahl anzuzeigender Nachkommastellen einstellst und das HMI rundet die Anzeige-Werte auf die gewünschte Anzahl Nachkommastellen?
Sobald Du mit einem "gerundeten" REAL-Wert weiterrechnest (z.B. wieder durch Faktor dividierst), dann tauchen wieder zusätzliche Nachkommastellen auf.
Sobald das Ergebnis wieder in REAL gewandelt und weitergerechnet wird, ist das ganze Abschneiden der Nachkommastellen genau genommen "für die Katz", weil da tauchen wieder Nachkommastellen auf:
TRUNC(123.456 * 10.0) ergibt 1234
INT_TO_REAL(1234) ergibt 1234.0
1234.0 / 10.0 ergibt 123.40000152587890625
Wenn sich die Anzeige nicht auf weniger Stellen einstellen läßt, dann nützt ein Abschneiden (Runden) von Nachkommastellen wenig, weil ja das Ergebnis der (L)REAL-Berechnung wieder auf die nächstgelegene darstellbare Zahl gerundet wird - es kommen wieder Nachkommastellen dazu!

Beispiel: 1.234123 auf 3 Nachkommastellen abschneiden und das Ergebnis 1.234 wieder in eine REAL-Variable speichern ergibt nicht 1.234000 sondern 1.233999... - was die Anzeige auch so anzeigen wird, wenn sie immer 6 Nachkommastellen anzeigt.

Oder willst Du nur die Nachkommastellen haben? Dafür gibt es in TIA die Anweisung FRAC. Inwieweit FRAC empfindlich für Rundungsfehler wegen dem IEEE 754 Speicherformat für Gleitkommazahlen ist, habe ich allerdings keine Erfahrung.

Die verbreitete naive Vorstellung (und das seit Jahren von Siemens für Programmieranfänger verbreitete Beispielprogramm)
Nachkommastellen := RealzahlMitNachkommastellen - RealzahlOhneNachkommastellen;
funktioniert nicht immer, sondern eigentlich nur, wenn der Wert von Nachkommastellen eine Zweierpotenz(*) ist. Wenn der Wert keine Zweierpotenz(*) ist, dann kommt es darauf an, ob der Wert auf- oder abgerundet zum nächstmöglichen REAL-Wert gespeichert wird. Dadurch kann sich die Ziffernfolge von Nachkommastellen ändern, z.B.: 123.45 - 123.0 = 0.4499969

(*) EDIT: nicht "Zweierpotenz ist", sondern "als Summe von Zweierpotenzen darstellbar ist"

Harald
 
Zuletzt bearbeitet:
...Nachkommastellen ändern, z.B.: 123.45 - 123.0 = 0.4499969

Das habe ich vor kurzem auch ähnlich gehabt. Ich wollte das Schaltjahr berechnen. Leider hat es so nicht funktioniert. Habe es jetzt anders gelöst und funktioniert.

Auf solche Dinge sollte man achten, das sind sehr interessante Fallen.

Mfg Hannes
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@ Harald in #12
Die zentrale Funktion ist eigentlich in der Tat die Wandlung in DInt mit definierter Nachkommastelle, weil die hier in der Firma verwendete Visualisierungssoftware, dann auf "Wertänderung" statt auf "zyklisch" eingestellt werden kann und weniger Datenmüll produziert. Das paralllel ein Real rauskommt, der in der Regel leichter lesbar ist (z.B 36.14 statt 36.13975) ist eher ein Nebeneffekt.

Bisher habe ich den Faktor direkt eingegeben, wollte aber für den Inbetriebsetzer eine möglichst selbsterklärende Lösung mit "Nachkommastellen" basteln.
 
Und in der Visualisierung werden dann Vorkomma und Nachkomma in getrennten Feldern dargestellt? Wie können solche Daten denn weiterverarbeitet werden, z.B. in einer Datenbank archiviert werden?

Mir ist das etwas suspekt. Aber ich musste meine SPS auch schon mal ein eine Visualisierung anbinden, da hieß es von der Firma die das projektierte, ich solle die Daten doch bitte nur alle 30 Sekunden schicken. Ich meinte nur: Ich schicke überhaupt nichts, ihr holt die Daten ab. Antwort: Ich solle doch nur alle 30 Sekunden schicken. Ich: Okeeeeey, mache ich.
 
DInt mit definierter Nachkommastelle
Das interpretiere ich so, daß die Visu an vorher vereinbarter fester Stelle ein Komma in die Anzeige der DINT-Ganzzahl einfügt (daher auch Festkommazahl genannt, wo die Information über die Position des Dezimalkomma nicht im Wert enthalten, aber vereinbart ist). Da kann man z.B. 10 Ziffern in 32 Bit unterbringen und nicht nur 7 wie bei REAL.

Z.B. soll in der Visu eine Position oder Länge in Meter mit 3 Nachkommastellen angezeigt werden, die Visu kann oder soll aber nicht mit Fließkommazahlen (Gleitkommazahlen) umgehen. Also stellt man den tausendfachen Wert als "Festkommazahl" zur Verfügung (also in Millimeter anstatt Meter) und die Visu fügt bei der Anzeige 3 Stellen von hinten das Komma ein. Man könnte auch die Übergabe in Zentimeter vereinbaren, dann müsste die Meter-Anzeige das Komma 2 Stellen von hinten einfügen.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Exakt, die Visu soll z.B. 2123, 512 mNHN millimetergenau darstellen und gleichzeitig bei jedem Millimetersprung einen Eintrag in den Historienspeicher erzeugen. Eine aus mehreren Werten berechnete REAL-Zahl ändert sich aber de facto permanent. Die Visu würde also bei Triggerung durch Wertänderung ständig Werte ablegen, mit einem passenden DINT nur bei Änderung von 1mm ( oder auch 5 oder 1cm, je nach Rechenvorschrift).

Die Alternative wäre, dass die SPS für jeden Wert die Änderung berechnet und Speicherimpulse übergibt. Das ist mehr Aufwand.
 
Zurück
Oben