Umsetzung von Skalierungen in SPS-Programme
Der nächste Abschnitt beschäftigt sich damit, wie die gewonnenen Erkenntnisse in Programme umgesetzt werden können. Wobei hier lediglich mit Strukturierten Text (Wird im Folgenden mit ST abgekürzt) gearbeitet wird.
Auf den ersten Blick scheint die Sache ganz einfach zu sein, man muss lediglich die Formeln umsetzen. Die folgende Formel
könnte man in ST z.B. so umsetzen.
Code:
r32_Spannung = i16_Messwert * 10 / 32767;
Allerdings ist es nicht so einfach, denn es gibt hierbei einen erheblichen Stolperstein, nämlich das die Steuerung unter bestimmten Umständen nicht mit Fließkommazahlen, sondern mit Ganzzahlen rechnet. Bei einer Rechnung rein mit Ganzzahlen ist das Ergebnis auch bei einer Division immer eine Ganzzahl, auch wenn das Ergebnis, wie in obigem Beispiel, am Ende in einer Fließkommavariable (Stichwort: implizite Typkonvertierung) gespeichert wird.
Durch die Deklaration einer Variable weiß die SPS im wahrsten Sinn des Wortes womit sie rechnen muss, bei direkt im Code angegebenen Werten ist dies jedoch nicht so und die SPS oder genauer die Entwicklungsumgebung muss da sozusagen raten.
Sowohl beim TIA-Portal von Siemens, als auch bei Entwicklungsumgebungen die auf
Codesys basieren betrachtet die Entwicklungsumgebung Zahlen ohne Nachkommastellen als Ganzzahl und welche mit als Fließkommazahlen. Möchte man also, dass die Entwicklungsumgebung eine glatte Zahl als Fließkommazahl betrachtet muss man diese mit mindestens einer Nachkommastelle angeben. Möchte man z.B. die Zahl 40 im Code angeben und soll diese als Fließkommazahl interpretiert werden, muss man stattdessen 40.0 eingeben.
Variablen können automatisch über die explizite Typkonvertierung in andere Typen gewandelt werden, da es hier auch zu Problemen kommen kann wäre es allerdings besser dafür, soweit vorhanden, spezielle Funktionen zu nutzen. Sowohl bei Siemens als auch bei
Codesys basierten Steuerungen haben diese Funktionen die Namenskonvention QUELLTYP_TO_ZIELTYP. Die Funktion um einen Integerwert in ein Real zu wandeln würde also INT_TO_REAL heißen.
Werden diese Hinweise nicht beachtet, kann es zu erheblichen Rechenfehlern kommen, wie ich noch demonstrieren werde.
Sowohl die Entwicklungsumgebung von Siemens als auch die der
Codesys Derivate unterscheiden nicht nur zwischen Fließkomma- und Ganzzahlen aufgrund des Aufbaus der Zahl im Code, sondern stellen beim Übersetzen des Programms auch die Größe der jeweiligen Zahl fest und wählen für diese dann den passenden Typ. Steht im Code z.B. die Zahl 1000 wird hierfür UINT als Typ genutzt, bei -1000 entsprechend INT, bei einer 100000 würde als Typ UDINT genutzt werden. Lediglich bei der Wahl des Typs zur Ablage des Ergebnisses unterscheiden sich die beiden Systeme. Als Typ für das Ergebnis einer Rechnung wird bei Siemens dabei der Typ der Variable genommen die an dem jeweiligen Teil der Rechnung beteiligt ist, ist diese vom Typ INT ist das Ergebnis auch vom Typ INT. Bei Codesys basierten Entwicklungsumgebungen wird für das Ergebnis immer die größte Variante des jeweiligen Typs gewählt, bei Integer-Werten wäre das LINT.
An einem Beispiel das auf obiger Formel basiert soll hier aufgezeigt werden was für ein Ergebnis beim jeweiligen System herauskommt.
Der Wert der Variable i16_Messwert beträgt in diesem Beispiel 9000. Als Ergebnis würde man einen Wert von rund 2,75 mit einem Taschenrechner erhalten. Die Siemens CPU ermittelt jedoch ein Ergebnis von 0 und bei der Beckhoff CPU kommt ein Wert von 2,0 raus. Was lief hier jetzt schief?
Betrachten wir zunächst die Siemens-Seite. Als erstes wird der Messwert mit 10 multipliziert, wie erwähnt nimmt Siemens für die Speicherung des Ergebnisses den Typ der bei der Berechnung beteiligten Variable, in diesem Falle also INT. Hier kommt es nun schon zum ersten Fehler, 9000 * 10 würde als Ergebnis 90000 ergeben, was den Bereich eines INTs (32767) überschreitet, dadurch kommt es zum Überlauf und das errechnete Ergebnis beträgt stattdessen 24464. Dieses (falsche) Ergebnis wird nun durch 32767 geteilt, was ein Ergebnis eigentlich von <1 zur Folge hätte. Da das Ergebnis aber wieder eine Ganzzahl ist gehen die Nachkommastellen sozusagen verloren und das Ergebnis ist 0. Anschließend wird das Ergebnis aufgrund der oben erwähnten impliziten Typkonvertierung zwar in eine Fließkommazahl gewandelt, aber auch dadurch kann nichts anderes als 0 herauskommen.
Da bei Beckhoff für das Zwischenergebnis immer die Variante mit dem größten Bereich eines Typs genommen wird kommt es bei der ersten Rechnung nicht zu einem Überlauf und zumindest das Zwischenergebnis (90000) stimmt hier noch, bei der anschließenden Division kommt es allerdings zum selben Problem wie bei Siemens. Die Rechnung 90000 / 32767 müsste ja eigentlich, wie oben erwähnt, ein Ergebnis von rund 2,75 ergeben, dadurch das das Ergebnis auch eine Ganzzahl ist, gehen auch hier die Nachkommastellen verloren und es bleibt 2 über, die dann durch die implizite Typkonvertierung in einer Fließkommavariable gespeichert wird.
Hier mal ein Einzeiler, der richtig rechnet:
Code:
#r32_Drehzahl := INT_TO_REAL(#i16_Messwert) * 1000.0 / 32767.0;