TIA Hex Wert in Real Holding Register abfangen

JoGi65

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

CPU S7-1515 – Tia 17

Ich hab ein Phänomen, dass Holdingregister vom Wechselrichter, die normal REAL Daten liefern sollen, ab und zu einen HEX Wert drinnen stehen haben.


Bild 1 – Variable HR – normal ein REAL Wert - HR ist direkt der Real Wert vom Holding Register

Umwandlung OK.jpg


Bild 2 – Variable HR - ab und zu ein HEX Wert (DWORD)

Fehler Umwandlung.jpg


Mir fällt momentan nur ein, die Werte in einen String zu wandeln und auf die Länge zu prüfen, da die Werte eine Länge von 7 nicht übersteigen.
<> funktioniert nicht, da der HEX Wert dazwischen liegt, oder anders Interpretiert wird.

Gibt’s hier eine bessere Idee?
 
Ich hab ein Phänomen, dass Holdingregister vom Wechselrichter, die normal REAL Daten liefern sollen, ab und zu einen HEX Wert drinnen stehen haben.
Könnte dieses Problem evtl. durch nicht konsistente Datenübertragung kommen? So dass du ab und zu inkonsistente Daten erhälst, welche nicht als REAL interpretiert werden können.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
16#7fc0_0000 ist ein "NAN" Wert.

Siehe https://www.h-schmidt.net/FloatConverter/IEEE754de.html
1685020178591.png


NAN steht für "Not a number".
Siemens zeigt in dem Fall den HEX Wert an.
Twin-Cat z.B. zeigt in dem Fall als Aktualwert "NAN" an.

Manche Geräte setzen einen Wert bewusst auf NAN (kein Bug!).
Kenne das z.B. vom Wirkungsgrad, wenn nichts läuft.
Ist auch irgendwie Logisch. Was ergibt den für einen Wirkungsgrad einer Anlage, wenn Sie ausgeschaltet ist.
Richtig, gar keiner. Und das kann mit "NAN" signalisiert werden.
Ich weiß nicht ob so ein Fall in deinem Szenario sein kann (oder Sinn gibt).

So jetzt noch wie man abfragen kann ob ein real "NAN" ist:

Code:
FUNCTION "RealIsNan" : Bool
   { S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
      iReal : Real;
   END_VAR

   VAR_TEMP
      tmpDword : DInt;
   END_VAR


BEGIN
    (*https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html
    Infinity and NaNs
    
    The IEEE standard specifies a variety of special exponent and mantissa values in order to support the concepts of plus and minus infinity and “Not-a-Number” (NaN).
    
    Infinity (∞)
    
    Arithmetic involving infinity is treated as the limiting case of real arithmetic, with infinite values defined as those outside the range of representable numbers, or
    
    −∞ < representable numbers < +∞
    
    With the exception of the special cases discussed below (NaNs), any arithmetic operation involving infinity yields infinity. Infinity is represented by the largest biased exponent allowed by the format and a mantissa of zero.
    
    NaNs
    
    A NaN (Not-a-Number) is a symbolic entity encoded in floating-point format. There are two types of NaNs:
    
    Signalling NaN
    signals an invalid operation exception
    
    Quiet NaN
    propagates through almost every arithmetic operation without signalling an exception
    
    NaNs are produced by these operations:
    
    ∞ − ∞,   −∞ + ∞,   0 × ∞,   0 ÷ 0,   ∞ ÷ ∞
    
    Both types of NaNs are represented by the largest biased exponent allowed by the format (single- or double-precision) and a mantissa that is non-zero.
    
    The bit pattern of the mantissa for a signalling NaN has the most significant digit set to zero and at least one of the remaining digits set to one.
    The bit pattern of the mantissa for a quiet NaN has the most significant digit set to one
    For single-precision values:
    
    Positive infinity is represented by the bit pattern 7F800000
    Negative infinity is represented by the bit pattern FF800000
    A signalling NaN (NANS) is represented by any bit pattern
    between 7F800001 and 7FBFFFFF or between FF800001 and FFBFFFFF
    A quiet NaN (NANQ) is represented by any bit pattern
    between 7FC00000 and 7FFFFFFF or between FFC00000 and FFFFFFFF
    For double-precision values:
    
    Positive infinity is represented by the bit pattern 7FF0000000000000
    Negative infinity is represented by the bit pattern FFF0000000000000
    A signalling NaN is represented by any bit pattern
    between 7FF0000000000001 and 7FF7FFFFFFFFFFFF or
    between FFF0000000000001 and FFF7FFFFFFFFFFFF
    A quiet NaN is represented by any bit pattern
    between 7FF8000000000000 and 7FFFFFFFFFFFFFFF or
    between FFF8000000000000 and FFFFFFFFFFFFFFFF
    *)
    #tmpDword := REAL_TO_DWORD(#iReal);
    IF #tmpDword >= 16#7F800001 AND #tmpDword <= 16#7FBFFFFF
        OR #tmpDword >= 16#FF800001 AND #tmpDword <= 16#FFBFFFFF
        OR #tmpDword >= 16#7FC00000 AND #tmpDword <= 16#7FFFFFFF
        OR #tmpDword >= 16#FFC00000 AND #tmpDword <= 16#FFFFFFFF THEN
        
        #RealIsNan := true;
    ELSE
        #RealIsNan := false;
    END_IF;
    
    
    
    
END_FUNCTION
 
Wie holst Du das Registerpaar, wo ein Real drin sein soll?
Wenn in HR 4513.509 drin steht, dann ist das korrekt?
Überschreibst Du irgendwo in Deinem Programm manchmal das zweite Word von HR (Adress-Überlappung)?
Warum heißen manche Variablen ..._DINT, sind aber Real?

Harald
 
Könnte dieses Problem evtl. durch nicht konsistente Datenübertragung kommen? So dass du ab und zu inkonsistente Daten erhälst, welche nicht als REAL interpretiert werden können.

Der MB Client liefert keinen Fehler. Tritt auch nur beim Symo auf und nicht beim GEN24. Ich glaube mal irgendwo gelesen zu haben, dass man die Werte nicht pollen soll, da es dann manchmal zu Fehlern kommt. Liegt mit fast 100% am WR.


16#7fc0_0000 ist ein "NAN" Wert.

Danke, das hilft mir weiter, auch mit der Auswertung, wobei die LEN Abfrage nach String Wandlung ja fast einfacher wird.

Wie holst Du das Registerpaar, wo ein Real drin sein soll?
Wenn in HR 4513.509 drin steht, dann ist das korrekt?
Überschreibt Du irgendwo in Deinem Programm manchmal das zweite Word von HR (Adress-Überlappung)?
Warum heißen manche Variablen ..._DINT, sind aber Real?
Zeilenweise Antwort

MB Client - lauft auch durch ohne sichtbaren Fehler.
Ja, HR Wert 4513.509 ist korrekt.
Nein, wird nicht überschrieben. Nur gelesen.
Sind alles nur Hilfsvariablen um den Fehler zu erkennen. DINT heißt sie, weil es nach der DINT_to_Real usw. Wandlung auf ein Komma ist. Hatte auch die Wandlung in Verdacht, aber wie es sich zeigt, wars das nicht.

Habs die letzten Jahre ignoriert, weil ich von noch immer nicht funktionierender Web Übertragung der SPS ausgegangen bin. Aber da sich der Fehler jetzt auf einer Seite öfter gezeigt hat. wollte ich schauen wo's liegt.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
wobei die LEN Abfrage nach String Wandlung ja fast einfacher wird.
Das sehe ich anders.
Die Abfrage würde so ausehen
Code:
IF "RealIsNan"(HR) THEN
...

einfacher gehts doch garnicht...

Außerdem wäre eine Lösung mit der String länge nur in bestimmten Fällen richtig und nicht allgemein richtig.
Und man muss auch mit den Stellen hinterm Komma und nicht genau darstellbaren REALs aufpassen...


EDIT:
Real_to_String gibt ja auch NAN zurück
1685025998010.png
In dem Fall habe ich keine Ahnung wie und was du mit der String Länge auswerten willst???
 
Zuletzt bearbeitet:
MB Client - lauft auch durch ohne sichtbaren Fehler.
(...)
Nein, wird nicht überschrieben. Nur gelesen.
Mit "wie holst Du das Registerpaar" meinte ich, holst Du einzelne Register nacheinander oder gleich mehrere, pufferst Du vielleicht Empfangsdaten in Temp für mehrere Durchläufe, wie sieht der Code aus, wie/wann bastelst Du aus 2 Registern einen Real, beachtest Du das DONE vom MB_CLIENT, ...

"wird nicht geschrieben, nur gelesen" kann nicht sein. Du musst ja bei DONE den empfangenen Wert in eine Variable umkopieren. Benutzt Du da indirekte Adressierung? Ist die vielleicht fehlerhaft, so daß eventuell auf Adressen ungewollter Variablen geschrieben wird?

Wie oft pollst Du die Daten?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In dem Fall habe ich keine Ahnung wie und was du mit der String Länge auswerten willst???
Ist mir auch schleierhaft. Der Umweg und die Gefahr, zusätzliche Probleme/Unterschiede durch bestimmte Eigenschaften der Formatierung (die man möglicherweise nicht im Detail kennt bzw. die in Zukunft durch Updates erst noch entstehen könnten) scheint mir in keinerWeise gerechtfertigt zu sein.
Das scheint leider eher ein verzweifelter WorkAround zu sein, möglichst schnell, aber nicht möglichst sinnvoll, möglichst nachvollziehbar eine NAN-Erkennung zu basteln.

Grundsätzlich halte ich es für durchaus legitim und oft auch für sinnvoll, der CPU diverse aktive Einstellungen zu entlocken, indem man sie etwas Definiertes in den DatenTyp String konvertieren lässt. Z.B., um zur Laufzeit herauszufinden, ob DezimalKomma oder DezimalPunkt oder welches DatumsFormat angesagt ist.
Aber welche Schlüsse ich aus der Anzahl Vor- oder NachKommaStellen ziehen sollte, geschweigedenn aus der GesamtZahl produzierter Stellen ... keine Ahnung. Da will mir einfach nichts einfallen. Ich müsste doch bei [L]REAL-Zahlen zunächst klären, ob die Darstellung in der ExponenzialForm geschehen ist oder nicht, ob es 0 oder 1 oder 2 Vorzeichen gibt. Ich mag jetzt gar nicht weiter darüber nachdenken, was noch alles zu berücksichtigen wäre, weil mir momentan der Blick auf die vermeintliche/erhoffte Vereinfachung versperrt zu sein scheint. ;)
 
In dem Fall habe ich keine Ahnung wie und was du mit der String Länge auswerten willst???

Bei einer normalen Zahl, ist die Länge nach der Wandlung maximal 7 Zeichen lang.
Wenn das NaN so gewandelt wird LEN(UDINT_TO_STRING(REAL_TO_UDINT("DB_Fronius".WR1.P_W_DC_G))) ist die Länge immer größer, jedenfalls nach meinen Tests.
Siehe erster Beitrag P_DC_max_String.
Hab es auch so gefunden, das es kommt. Es passiert ja nur sehr selten. meistens > 10min, also ca. bei jeder 1000sten Abfrage.

Aber Danke. Ihr habt mich schon überzeugt! Werde es lt. Beitrag 3 umsetzen. (y)


Die Frage ist, ob es sich nicht eventuell vermeiden läßt, dass ein NaN überhaupt kommt, wobei ich das Abfangen trotzdem einbauen werde.
Mit "wie holst Du das Registerpaar" meinte ich, holst Du einzelne Register nacheinander oder gleich mehrere, pufferst Du vielleicht Empfangsdaten in Temp für mehrere Durchläufe, wie sieht der Code aus, wie/wann bastelst Du aus 2 Registern einen Real, beachtest Du das DONE vom MB_CLIENT, ...

"wird nicht geschrieben, nur gelesen" kann nicht sein. Du musst ja bei DONE den empfangenen Wert in eine Variable umkopieren. Benutzt Du da indirekte Adressierung? Ist die vielleicht fehlerhaft, so daß eventuell auf Adressen ungewollter Variablen geschrieben wird?

Wie oft pollst Du die Daten?

Der Wechselrichter stellt die Register als "float" zur Verfügung.
Es werden 38 Register abgefragt und in ein Real Array (Temp) gelegt.
Mit der Flanke von Done - werden die Werte aus dem Array gelesen, und gleichzeitig auf ein Komma beschränkt.
zB: "DB_Fronius".WR1.P_W_DC_G := DINT_TO_REAL(REAL_TO_DINT("DB_MB_Client_PV1".Holdingregister[18] * 10)) / 10;

Dannach wird, gestartet mit dem Done vom ersten Bereich, - EDIT: nicht im gleichen Zyklus! sondern erst im nächsten! - ein weiterer Bereich des WR abgefragt, wobei der andere Bereich uint liefert, und somit die Register in ein anderes Array gehen. Damit kann es keine Überschneidung des Arrays geben. Ich schreibe immer alles in Datenbausteine, da kann nix schief gehen, soweit ich das verstehe.

Und das Done vom zweiten Bereich, startet wieder den ersten.
Ich versuche jetzt einmal einen oder mehrere Pausezyklen zwischen den Abfragen einzuziehen.

Danke für die Anstöße.
 
werden die Werte aus dem Array gelesen, und gleichzeitig auf ein Komma beschränkt.
zB: "DB_Fronius".WR1.P_W_DC_G := DINT_TO_REAL(REAL_TO_DINT("DB_MB_Client_PV1".Holdingregister[18] * 10)) / 10;
Du meinst vermutlich "auf eine Nachkommastelle" begrenzt. Das ist bei Real/Float aber mehr oder weniger sinnfrei, weil bei der letzten Division durch 10.0 wird das Ergebnis auf den nächsten als Real darstellbaren Wert gerundet und es entstehen wieder Nachkommastellen. Außerdem wird bei Deiner Manipulation der Wert verfälscht, weil Du immer abrundest.
Nur bei der Anzeige von Real/Float-Werten kann man auf nur eine Nachkommastelle formatieren.

Wenn Du fehlerhafte Verarbeitung der Modbus-Empfangswerte in Deinem Programm ausschließen kannst: Was sagt denn der Hersteller des Wechselrichters dazu, daß sein Gerät manchmal NaN liefert? Ist das ein Bug, oder gibt es Hinweise in der Dokumentation, oder muß generell langsamer gepollt werden oder weniger Register auf einmal?

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Da ist es ja recht einfach, die ungültig/NaN-Codierung zu erkennen:
Code:
#invalid := REAL_TO_DWORD("DB_MB_Client_PV1".Holdingregister[#i]) = 16#7FC00000;

Habs jetzt so ähnlich umgesetzt und funktioniert einwandfrei! (y)


Ansonsten mal die Firmwareversion prüfen, da gibt es auch einige Bugfixes ( auch einen in Bezug auf NaN ):

Quelle: Gen24 Changelog
Anhang anzeigen 69114

Das Problem hat nur der Symo. Beim GEN24 kommt es nicht vor. Der funktioniert perfekt.


Wenn Du fehlerhafte Verarbeitung der Modbus-Empfangswerte in Deinem Programm ausschließen kannst: Was sagt denn der Hersteller des Wechselrichters dazu, daß sein Gerät manchmal NaN liefert? Ist das ein Bug, oder gibt es Hinweise in der Dokumentation, oder muß generell langsamer gepollt werden oder weniger Register auf einmal?

Ich hab alles versucht. Pause > 1 sec. nach jeder Abfrage, usw..
Bezüglich der NaNs hatte ich noch keinen Kontakt mit Fronius, aber da das abfangen funktioniert ist es für mich ok.

Du meinst vermutlich "auf eine Nachkommastelle" begrenzt. Das ist bei Real/Float aber mehr oder weniger sinnfrei, weil bei der letzten Division durch 10.0 wird das Ergebnis auf den nächsten als Real darstellbaren Wert gerundet und es entstehen wieder Nachkommastellen. Außerdem wird bei Deiner Manipulation der Wert verfälscht, weil Du immer abrundest.
Nur bei der Anzeige von Real/Float-Werten kann man auf nur eine Nachkommastelle formatieren.

Ja, ich meinte "auf eine Nachkommastelle" begrenzen. Habs jetzt zwar auch rausgenommen, aber funktioniert hats schon, aus meiner Sicht.

Holdingregister 28,23.. - Wert 28,2

Umrechnung1.jpg

Holdingregister 28,25.. - Wert 28,3

Umrechnung2.jpg
 
Ja, ich meinte "auf eine Nachkommastelle" begrenzen. Habs jetzt zwar auch rausgenommen, aber funktioniert hats schon, aus meiner Sicht.
(...)
Holdingregister 28,25.. - Wert 28,3

Anhang anzeigen 69128
Code:
1. ...Holdingregister...         : 28.25323
2. * 10 (genaugenommen: * 10.0)  : 282.5323
3. REAL_TO_DINT                  : 283       <-- REAL_TO_DINT rundet AUF
4. DINT_TO_REAL                  : 283.0
5. / 10 (genaugenommen: / 10.0)  : 28.3      <-- hier rundet TIA die Anzeige, wirkliches Ergebnis ist 16#41E26666 = 28.2999992371


Das vermeintliche Reduzieren von Nachkommastellen zur "Verschönerung" der Werte ist trotzdem unsinnig, verbraucht nur Programmspeicher und Rechenzeit und spart nichts. Ein Real-Wert mit 5 Nachkommastellen und ein Real-Wert mit vermeintlich oder tatsächlich nur 1 Nachkommastelle belegen beide gleich viel Platz - nämlich 32 Bit :cool: Wieviele Nachkommastellen der Empfänger des Real-Wertes anzeigen will, würde ich ihm überlassen.
Wenn Du auf einem HMI ein Ausgabefeld mit dem Format 999,9 hast, dann wird es 28,3 anzeigen, auch wenn Du den unbehandelten Rohwert 28.25323 übergibst. Überlegst Du Dir, den Wert doch besser mit 2 Nachkommastellen anzuzeigen, dann wird das EA-Feld 28,25 anzeigen, aber nicht, wenn Du vorher auf 28.29999... gerundet hast - da würde es 28,30 anzeigen.


Außerdem wird bei Deiner Manipulation der Wert verfälscht, weil Du immer abrundest.
OK, diese Aussage von mir ist falsch. :oops: Ich hatte übersehen, daß REAL_TO_DINT in SCL rundet.

Harald
 
Zuletzt bearbeitet:
Bei Janitza UMG96RMP Messgerät habe ich das beim Cosinus-Phi auch schon gehabt, dass dort NaN übertragen wird. Ganz schlecht wird es, wenn so ein Wert in einem PI(D) Regler oder einen anderen Baustein mit Rückkopplung verwendet wird. Da jede arithmetische Operation mit NaN wieder NaN ergibt, kommt dieser Wert von selber nicht mehr aus dem Algorithmus heraus.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
.. Aber Danke. Ihr habt mich schon überzeugt! Werde es lt. Beitrag 3 umsetzen. (y) ..

Herzlichen Glückwunsch!

Ein simpler Vergleich des Wertes mit sich selbst, so wie ich es in #7 angerissen hatte, hätte es auch getan. Oder habe ich mal wieder irgend etwas falsch verstanden?
 
OK, diese Aussage von mir ist falsch. :oops: Ich hatte übersehen, daß REAL_TO_DINT in SCL rundet.
Keine Panik , Harald. Du wusstest es längst. Z.B. O-Ton PN/DP anno 2010:
Wegen REAL_TO_DINT wird der REAL-Wert explizit in einen DINT-Wert umgewandelt (ganz anderes Format auf Bit-Ebene!) und dabei auf eine ganze Zahl gerundet (Nachkommastellen verschwinden).
gefunden in, hast es nur vorübergehend verdrängt! ;)

Ein simpler Vergleich des Wertes mit sich selbst, so wie ich es in #7 angerissen hatte, hätte es auch getan.
Das ist leider das Schicksal aller Lösungen, die zu einfach aussehen, Dagobert. Sie werden achtlos zur Seite geschoben und ignoriert, statt geachtet und gründlich untersucht und ernst genommen zu werden. ;) Ich möchte nicht wissen, wie oft z.B. Haralds geniale Lösungen diesem Phänomen zum Opfer fallen.
Aber Dir, Dagobert, passiert das ja auch dauernd, wie das 'mal wieder' in Deinem folgenden Satz durchblicken lässt.
Oder habe ich mal wieder irgend etwas falsch verstanden?
 
.. Das ist leider das Schicksal aller Lösungen, die zu einfach aussehen, Dagobert. Sie werden achtlos zur Seite geschoben und ignoriert, statt geachtet und gründlich untersucht und ernst genommen zu werden...
Jaja, so wie der Gral eines Zimmermanns. Ich habe auch schon oft festgestellt, dass kurze und knappe Hinweise einfach ignoriert werden, da sie zu simpel erscheinen, um wahr zu sein. Manch Einer verdient aber auch eine zweite Chance.
 
Zurück
Oben