TIA S7-1500 wandelt WORD falsch zu INT um?

Ueribu95

Level-2
Beiträge
12
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich habe folgendes Problem. Ich bekomme per Modbus ein WORD mit dem Wert 16#800A zurück. Das wäre also 2#1000 0000 0000 1010 (Bit 15 links, Bit 0 rechts). Bei Siemens ist das in INT -32758. Laut der TIA-Hilfe hat das Bit 0 den Wert 2^0, das Bit 1 den Wert 2^1 usw., bis Bit 14 (2^14). Das Bit 15 ist das Vorzeichenbit (0=positiv, 1=negativ).
So, wie ich das ganz klar verstehe, müsste die 8 vom 16#800A das Bit 15 sein, also das Vorzeichen "-", und das A ist das Bit 1 und 3, also 2+8 = 10. Insgesamt sollte das also den Wert -10 haben, das wäre auch der Wert, der korrekt ist. Aber warum interpretiert die SPS das 16#800A als -32758 ?

Ich bin schon kurz davor, die Berechnung erstmal selbst zu programmieren, wenn Siemens das nicht gebacken bekommt... Das hätte ich so gemacht, funktioniert auch so wie es eigentlich sollte:

Code:
IF #iEmpfangswert < 0 THEN
    #ikorrigierterWert := #iEmpfangswert* - 1; // wandle negative Zahl in positive Zahl um
    #ikorrigierterWert.%X15 := TRUE; // Setze Vorzeichen Minus
ELSE
    #ikorrigierterWert := #iEmpfangswert;
END_IF;

Den Siemens-Hilfeartikel habe ich mal mit angehängt.

Frohe Ostern
Feiert heute schön ;)

Ueribu
 

Anhänge

  • Siemens Hilfe zu INT.PNG
    Siemens Hilfe zu INT.PNG
    32,5 KB · Aufrufe: 23
Zuviel Werbung?
-> Hier kostenlos registrieren
Hex Dezimal
--------!--------
16#0001 = 1
16#0002 = 2
.....
16#7FFE = 32.766
16#7FFF = 32.767
16#8000 = -32.678
16#8001 = -32.767
16#8002 = -32.766
.....
16#FFFE = -2
16#FFFF = -1
 
Das Bit 15 ist das Vorzeichenbit (0=positiv, 1=negativ).
So, wie ich das ganz klar verstehe, müsste die 8 vom 16#800A das Bit 15 sein, also das Vorzeichen "-", und das A ist das Bit 1 und 3, also 2+8 = 10.
Bit 15 ist aber nicht einfach ein Vorzeichenbit, wie so oft falsch behauptet wird, sondern es hat eine Wertigkeit, durch die sich in Summe ein negativer Wert ergibt.

Zum Vergleich:
bei UINT ist die Wertigkeit von Bit 15 = 2^15 = +32.768 und bei INT ist sie -(2^15) = -32.768.
 
Zuletzt bearbeitet:
Das Bit 15 ist das Vorzeichenbit (0=positiv, 1=negativ).
So, wie ich das ganz klar verstehe, müsste die 8 vom 16#800A das Bit 15 sein, also das Vorzeichen "-", und das A ist das Bit 1 und 3, also 2+8 = 10. Insgesamt sollte das also den Wert -10 haben, das wäre auch der Wert, der korrekt ist. Aber warum interpretiert die SPS das 16#800A als -32758 ?
Vooorsicht!!! Hier lauert anscheinend die Tücke, den Begriff "VorzeichenBit" falsch zu interpretieren.
Der Begriff VorzeichenBit ist nur insofern korrekt, als sich an diesem Bit das Vorzeichen ablesen lässt (ist das Bit 1, so ist die Zahl negativ).
Aaaber:
man kann nicht aus einer negativen Zahl eine positive Zahl desselben Betrags machen (oder umgekehrt), indem man nur das "VorzeichenBit" negiert!!! Insofern ist nämlich der Begriff "VorzeichenBit" total irreführend und absolut falsch!

Entscheidend und in der SiemensHilfe auch korrekt genannt ist "einem Zahlenwert im ZweierKomplement", aber "einem Vorzeichen und einem Zahlenwert im ZweierKomplement" ist ein (leider) weitverbreiteter Unsinn.
Das höchstwertige Bit, dass gerne als separates "VorzeichenBit" missverstanden wird, ist nichts Separates, sondern ein fester Bestandteil des ZweierKomplementes, das sämtliche Bits (z.B. 8 oder 16 oder 32 oder 64 Bits ...) der Zahl umfasst.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hinzu kommt, dass der Themenstarter schreibt er bekommt ein Word per Modbus.
Aber Word ist keine genaue Angabe. Word sagt nur, dass es 16 Bit sind. Es kann ein Bitmuster, ein 16 Bit SInt oder ein 16 Bit UInt sein. Bei einem SInt passt es schon, dass Bit 15 das Vorzeichenbit ist. Ist Bit 15 bei einem SInt High, dann ist es eine negative Zahl.
Also muss er als erstes wissen, was sich hinter dem Word verbirgt.
 
Es kann ein Bitmuster, ein 16 Bit SInt oder ein 16 Bit UInt sein. Bei einem SInt passt es schon, dass Bit 15 das Vorzeichenbit ist. Ist Bit 15 bei einem SInt High, dann ist es eine negative Zahl.
Also muss er als erstes wissen, was sich hinter dem Word verbirgt.
Na klar. Um korrekt dekodieren zu können, muss natürlich bekannt sein, wie kodiert wurde.
Und das Verständnis des Begriffs "VorzeichenBit" muss natürlich auch richtig sein.
Und es muss z.B. bei SINT auch bekannt sein, ob das 'S' die Abkürzung für "signed" oder "short" ist! ;)

Bei einem SInt passt es schon, dass Bit 15 das Vorzeichenbit ist. Ist Bit 15 bei einem SInt High, dann ist es eine negative Zahl.
Nicht, wenn 'S' für short steht. Dann hätte die komplette Zahl nur 8 Bit und das höchstwertige (nämlich Bit 7) wäre dennoch das "VorzeichenBit".
Eine Vorzeichen-lose 8-bit-Zahl wäre dann vom Typ USINT (unsigned short integer).
 
Zuletzt bearbeitet:
Nicht, wenn 'S' für short steht. Dann hätte die komplette Zahl nur 8 Bit und das höchstwertige (nämlich Bit 7) wäre dennoch das "VorzeichenBit".
Eine Vorzeichen-lose 8-bit-Zahl wäre dann vom Typ USINT (unsigned short integer).
Dann wäre aber ein Byte ausreichend.
Und korrekter Weise wird in der Regel in der Beschreibung der Modbusregister angegeben, in welchem Bereich der Wert liegt.
Und bei einem Unsigned short integer in Word könnte bein 16 Bit dann Bit 15 nie High werden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich bin schon kurz davor, die Berechnung erstmal selbst zu programmieren, wenn Siemens das nicht gebacken bekommt...
Glaubst Du, daß Du als erster TIA Anwender einen kapitalen Bug in der Software entdeckt hast? ;)
(zum Glück wirkt sich die katastrophale Qualität der TIA-Dokumentation nicht auf die erstellten SPS-Programme aus)

Was meint denn das Handbuch Deines Modbus-Gerätes, was der Wert 16#800A bedeuten soll? Hast Du mal ein Bild von der Beschreibung des Registers?

Harald
 
Hallo Leute,

vielen Dank für die vielen Antworten (und das an einem Feiertag).

Was meint denn das Handbuch Deines Modbus-Gerätes, was der Wert 16#800A bedeuten soll? Hast Du mal ein Bild von der Beschreibung des Registers?

Ja hier ist ein Ausschnitt der Doku:

1680942021658.png


Hier ist es so beschrieben, wie ich die Bitinterpretation mit dem Vorzeichen anfangs verstanden habe.

Danke für eure Aufklärung mit dem Zweierkomplement, eure Erklärungen und auch der Wikipediaartikel zum Zweierkomplement helfen da sehr.
Dann muss ich jetzt eben den Zahlenwert, der über Modbus kommt, wie im Bild der Doku interpretieren, heißt ich muss selbst ein bisschen Code dafür schreiben, das ist aber kein Problem.

Vielen Dank für eure Hilfe

Schöne Feiertage / Ostern

Ueribu
 
Das ist aber eine interessante Auslegung von deinem Lieferanden ...
Anscheinend ist eine Normung dann doch eher etwas für "Weicheier" ... :unsure:

Naja ... aber wenn es denn so ist dann bräuchtest du ja nur durch wortweises Verunden das Vorzeichenbit ausblenden, dann wandeln und schließlich, wenn es ein Vorzeichenbit gab, den Endwert mit -1 multiplizieren - auch nicht sooooo die Aufgabe ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hier ist es so beschrieben, wie ich die Bitinterpretation mit dem Vorzeichen anfangs verstanden habe.
Tja, leider kann man hier nicht entscheiden, welche Interpretation richtig ist und welche falsch.
Fest steht, dass die eine Interpretation (ZweierKomplement) sehr üblich ist und leider trotzdem sehr oft so beschrieben wird, dass man zu der nicht zutreffenden Interpretation (separates VorzeichenBit plus BetragsZahl) getrieben bzw. verleitet wird.
Fest steht aber auch, dass (fast?) immer die Interpretation als ZweierKomplement gemeint ist und verwendet wird, obwohl die Beschreibung etwas anderes vorgaukelt.
Fest steht aber auch, dass die unübliche Interpretation durchaus denkbar und möglich ist/wäre.
Niemand von uns kann ausschliessen, dass nicht doch jemand tatsächlich mal die unübliche Variante benutzt und vielleicht sogar eine Schnittstelle definieren darf. Da hilft nur testen. Selbst feststellen bzw. prüfen, was bzw. wie es gemeint ist.
Die Trennung in Vorzeichen und Betrag kenne ich eigentlich nur bei BCD-Zahlen.

Aus meiner persönlichen Erfahrung kann ich nur berichten, dass ausnahmslos immer (ich weiss, das ist doppelt gemoppelt, aber genau so meine ich es auch ;o) die ZweierKomplementVariante gemeint, aber viel zu oft die Beschreibung irreführend war.

Du bist nicht der erste, der darauf hereinfällt und wirst auch nicht der letzte sein. Du wirst aber auch nicht mehr einer der vielen sein können, die gar nicht merken, dass sich hier eine unsinnige Beschreibung eingeschlichen hat, die fast immer anstandslos hingenommen und nur viel zu selten beanstandet wird.

Immer schön kritisch bleiben und nicht alles einfach abnicken, nur weil es irgendwo so geschrieben steht. Es gibt nicht nur Druckfehler, sondern auch Missverständnisse und Oberflächlichkeiten bei Menschen, die es eigentlich besser wissen müssten. Und, man glaubt es kaum, es gibt auch "Mythen". Weisheiten, die sich irgendwie eingebürgert haben. Dinge die als unumstössliche Wahrheiten dargestellt und wahrgenommen werden ... und keiner weiss, warum.
Dazu zähle ich das Phänomen, das Thema dieses Threads ist.
Dazu zähle ich auch so manche Darstellung/Abhandlung zum Thema einer korrekten Auswertung von "AB-Signalen" (um 90° versetzte Signale von z.B. DrehGebern).
Dazu zähle ich aber auch, wie in ErdkundeBüchern oder von Lehrer[inne]n i.A. die Gezeiten erklärt werden.
Spätestens, wenn man eine Erklärung nicht versteht, sollte man in Erwägung ziehen, dass es an der Erklärung liegen könnte! ;)
 
Zuletzt bearbeitet:
Das hätte ich so gemacht, funktioniert auch so wie es eigentlich sollte:

Code:
IF #iEmpfangswert < 0 THEN
    #ikorrigierterWert := #iEmpfangswert* - 1; // wandle negative Zahl in positive Zahl um
    #ikorrigierterWert.%X15 := TRUE; // Setze Vorzeichen Minus
ELSE
    #ikorrigierterWert := #iEmpfangswert;
END_IF;
So umständlich muß man die Wandlung des "Selfmade"-Int zu Standard-Zweierkomplement-Int gar nicht machen.
Nachfolgender Code funktioniert einfacher und besser, weil so liefert der Code auch 0, falls der Kommunikationspartner in seinem Format ein 16#8000 = -0 sendet:
Code:
IF #iEmpfangswert < 0 THEN
    #ikorrigierterWert := 16#8000 - #iEmpfangswert;
ELSE
    #ikorrigierterWert := #iEmpfangswert;
END_IF;

PS: wenn man die Formel so herum schreibt: #ikorrigierterWert := -#iEmpfangswert + 16#8000; sieht man vermutlich besser, was da gemacht wird, nur der SCL-Compiler wird es vermutlich uneffizienter übersetzen. :cool:

Harald
 
Zuletzt bearbeitet:
Fest steht, dass die eine Interpretation (ZweierKomplement) sehr üblich ist und leider trotzdem sehr oft so beschrieben wird, dass man zu der nicht zutreffenden Interpretation (separates VorzeichenBit plus BetragsZahl) getrieben bzw. verleitet wird.
Fest steht aber auch, dass (fast?) immer die Interpretation als ZweierKomplement gemeint ist und verwendet wird, obwohl die Beschreibung etwas anderes vorgaukelt.
Für TIA hatten wir das Anfang 2019 schon einmal thematisiert, doch in der katastrophal schlechten und oft falschen TIA-Dokumentation halten sich solche falschen Beschreibungen leider für immer... oder an der TIA-ToDo-Post-it-Wand ;) ... es ist ja leider so teuer, etwas korrekt zu beschreiben, und hinterher nochmal jemandem mit Ahnung zur Prüfung/Überarbeitung vorzulegen...

Das geile an der Zweierkomplement-Codierung von Ganzzahlen ist, daß es keine zusätzliche Vorzeichen-Information benötigt, und man sich den Wertebereich quasi als ein als Ring geschlossenes Band vorstellen kann, auf dem man sich mit + nach rechts und mit - nach links bewegt.

Wie kann man einen Int-Wert i negieren, z.B. 200 ---> -200?
- mit fertiger Negierfunktion, in SCL: neg_i := -i;
- von 0 subtrahieren: neg_i := 0 - i;
- mit -1 multiplizieren: neg_i := i * -1;
Das mit -1 multiplizieren ist bei manchen CPU die uneffizienteste Methode, doch gerade die wird von vielen Programmierern wohl als am einfachsten verständlich angesehen und verwendet.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
wenn es denn so ist dann bräuchtest du ja nur durch wortweises Verunden das Vorzeichenbit ausblenden, dann wandeln und schließlich, wenn es ein Vorzeichenbit gab, den Endwert mit -1 multiplizieren
Was/wie "wandeln"?
Bei positiven Werten braucht man kein Vorzeichenbit entfernen und nichts wandeln.
Bei negativen Werten braucht man nur das Vorzeichenbit entfernen und dann mit -1 multiplizieren.

Harald
 
Ich hab noch gelernt: alle Bits invertieren und 1 addieren. Das sollte auch heute noch funktionieren ;)
Das funktioniert auch heute noch, wenn man das ZweierKomplement zu einer Zahl berechnen will
UND die erforderlichen DatenTypKonvertierungen richtig auf die Reihe kriegt.

Aber würdest Du wirklich ...
Code:
x := WORD_TO_INT(INT_TO_WORD(x) XOR 16#FFFF) + 1 ;
... oder sogar ...
Code:
x := WORD_TO_INT(INT_TO_WORD(x) XOR INT_TO_WORD(-1)) + 1 ;
... eintippen, wenn auch ...
Code:
x := -x ;
... zum Ziel führt? ;) :unsure:
 
Zuletzt bearbeitet:
Aber würdest Du wirklich ...
Code:
x := WORD_TO_INT(INT_TO_WORD(x) XOR 16#FFFF) + 1 ;
(...)
... eintippen, wenn auch ...
Code:
x := -x ;
... zum Ziel führt? ;) :unsure:
Heinrich, Du musst nicht zur Abschreckung mit XOR invertieren ... ;)
Aber x := WORD_TO_INT(NOT INT_TO_WORD(x)) + 1; lädt auch nicht gerade zum eintippen ein, um ausführlich das zu machen, was das Minus in x := -x ; (sehr wahrscheinlich) eh intern macht.

Harald
 
Heinrich, Du musst nicht zur Abschreckung mit XOR invertieren ... ;)
Niemand ist überflüssig, er kann zumindest als abschreckendes Beispiel dienen. So auch das vielfach ungenutzt herumliegende XOR. :ROFLMAO:

Aber sooo abschreckend finde ich das XOR eigentlich nicht. Fühle mich sogar gelegentlich verpflichtet, an seine Existenz zu erinnern, zumal es schon oft gute Dienste geleistet hat. ;)
 
Zurück
Oben