zwei 16bit uint verschieben und verbinden zu float

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
kiaralle
User
Beiträge: 132
Registriert: Donnerstag 19. August 2021, 19:11

Hallo,

ich habe zwei Werte welche 16bit uint sind. Die rufe ich mit minimalmodbus aus einen Wechselrichter ab,
Das Abrufen funktioniert.

Es gehören immer eine High und eine Low-Wert laut zusammen.
Beispiel PV-Leistung = Ppv1_High und Ppv1_Low
Ich beobachte eigentlich immer, das der High-Wert Null ist.
Denke der Aufwand wird zum Schluss nicht nötig sein. :lol:

Als Ergebnis möchte ich float haben.
Kann das so funktionieren?

Code: Alles auswählen

float(growatt_1.read_register(18, 1, 4, False) << 16 | growatt_1.read_register(18, 1, 4, False))
So ähnlich habe ich es in Arduino im Code mal gelöst.

Den Code möchte ich in einen dictionary ablegen und später in einer Schleife aufrufen und berechnen lassen.

Danke, Ralf
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sieht falsch aus, weil zweimal das gleiche Register gelesen wird, oder nicht? Aber wenn es zwei Register sind, und die Reihenfolge stimmt (also das erste auch wirklich die höherwertigen Bytes beinhaltet), dann passt das so.
kiaralle
User
Beiträge: 132
Registriert: Donnerstag 19. August 2021, 19:11

@ _deets_

Gut aufgepasst. Ja copy und paste :-)

Danke für die schnelle Antwort.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1206
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Ich glaube nicht, dass es das ist, was du willst. Das Schieben und Verodern bringt nichts. Du hast dann immer noch einen Integer und nicht die Repräsentation eines Floats in Bytes.

Du musst zuerst die beiden Wörter in Bytes aufteilen und z.B. einem bytearray übergeben.
Dann kann man struct verwenden, um einen 32 Bit Float aus dem bytearray zu erzeugen.

Ich habe mal zwei Beispiele geschrieben. Keine Garantie auf Richtigkeit.

Code: Alles auswählen

from __future__ import annotations
from enum import StrEnum

class Endianess(StrEnum):
    big = "big"
    little = "little"

def float2word(value: float, endianess:Endianess="little") -> tuple[int,int]:
    if endianess is Endianess.big:
        data = struct.pack(">f", value)
        return data[2] | data[3] << 8, data[0] | data[1] << 8
    else:
        data = struct.pack("<f", value)
        return data[0] << 8 | data[1], data[2] << 8 | data[3]

def word2float(word0: int, word1: int, endianess:Endianess="little") -> float:
    buffer = bytearray()
    if endianess is Endianess.big:
        buffer.append(word1 & 0xFF)
        buffer.append(word1 >> 8)
        buffer.append(word0 & 0xFF)
        buffer.append(word0 >> 8)
        return struct.unpack(">f", buffer)[0]
    else:
        buffer.append(word0 >> 8)
        buffer.append(word0 & 0xFF)
        buffer.append(word1 >> 8)
        buffer.append(word1 & 0xFF)
        return struct.unpack("<f", buffer)[0]

word0, word1 = float2word(3.14, Endianess.little)
value = word2float(word0, word1, endianess=Endianess.little)
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich bezweifele sehr, dass der TE einen 4-Byte-IEEE754-Wert vorliegen hat, der irgendwie auf zwei Wort-Register abgebildet ist. Das waere ein ziemlich bescheidenes Design.
Benutzeravatar
__blackjack__
User
Beiträge: 13937
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Kann aber vorkommen wenn das über eine API geht die nur 16-Bit-Integer-Werte für die Übertragung vorsieht.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Koennen tut vieles, klar. Aber modbus kennt prinzipiell Byte-Transfers, auch mehrere. Warum man da jetzt nun auf zweimal zwei Bytes geht, wenn es am Ende doch ein 4-Byte-Wert sein soll, ist erstmal keine schluessige Annahme.
kiaralle
User
Beiträge: 132
Registriert: Donnerstag 19. August 2021, 19:11

Hilft dass euch weiter.
Ihr fachsimpelt hier so schön, ich bin noch nicht soweit :D
Der Link geht zur Modbus-Tabelle meines Wechselrichters

https://www.google.com/url?sa=t&rct=j&q ... i=89978449
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nicht besonders aussagekraeftig, und ja auch komlpett andere Registerwerte als von dir da angegeben. Aber *wenn* ist das eben doch einfach ein 32-Bit-Wert, den man mit der Einheit (0.1W) multiplizieren muss, um den eigentlichen Wert zu bekommen. Damit hast du schonmal 6.5KW Wertebereich nur mit dem low-Wert, da haengt's jetzt von deinem Setup ab, ob du ueberhaupt jemals Werte jenseits davon siehst, die dann in das hi-word laufen.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1206
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

__deets__ hat geschrieben: Mittwoch 30. August 2023, 10:50 Ich bezweifele sehr, dass der TE einen 4-Byte-IEEE754-Wert vorliegen hat, der irgendwie auf zwei Wort-Register abgebildet ist.
Ich aber nicht und genau deswegen habe ich das Beispiel geschrieben. Es gibt Geräte, die einen Float so übertragen.
Beim Modbus-Protokoll gibt es keine Funktion, um Gleitkommazahlen zu übertragen.

Ob das nun so richtig ist, kann nur der TE sagen.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
kiaralle
User
Beiträge: 132
Registriert: Donnerstag 19. August 2021, 19:11

Man bekommt von Growatt auch sehr wenig Hilfe.

Die Modbuss-Tabelle scheint eine Tabelle zu sein, welche schon oft geändert wurde und auch bei andere Growatt-Typen verwendet wurde. Also ein Sammelsurium von Registern die nie belegt werden.

Wie oben geschrieben, sind die High-Werte bei meinem Wechselrichter immer 0.
Da könntet ihr mit dem nie erreichten Überlauf in den High-Wert recht haben.
Dafür ist die PV-Leistung des Umrichters zu gering. Es darf nicht mehr wie 6kW sein.

Außer wenn es um die Fließrichtung der Leistung aus dem Batteriespeicher geht.
Da ist High einmal 65535 und dann mal 0.
Low schwankt dann immer je nach Leistung von 65535 bei wenig Leistung in Richtung 0 bei viel Leistung.
Daraus ergibt sich dann der negative oder positive Wert.
Wert = High - Low... wenn ich jetzt richtig liege. Muss ich noch mal schauen.

Bei diesen Registern steht dann
(signed int 32)
Positive:Battery Discharge Power;
Negative:Battery Charge Power;

Danke für eure guten Gedanken. Hat mir trotzdem geholfen.

Warum Werte auslesen, welche eh nie erreicht werden. Ich sperre die High-Register einfach aus.
Rechenzeit ist kostbar :wink:

Gruß Ralf
Sirius3
User
Beiträge: 18227
Registriert: Sonntag 21. Oktober 2012, 17:20

@DeaD_EyE: warum verwendest Du für die float pack, für die ints aber nicht???

Du definierst als Typannotation von endiness Endiness, weist dann aber als default-Argument einen String zu. Das ist Quatsch und zeigt mal wieder, das Typannotationen in den meisten Fällen falsch sind und auch falsch verwendet werden.
Und die Prüfung innerhalb der Funktionen ist damit auch fehlerhaft.
Du mischst die Endinessen codierst das float in big und decodierst die words als little, bzw. umgekehr. Warum tauschst Du bei Big-Endian auch noch die beiden Wörter aus? Damit sind die beiden Endinesse identisch.

Code: Alles auswählen

import struct
from enum import StrEnum

class Endianess(StrEnum):
    big = "big"
    little = "little"

def float2word(value, endianess=Endianess.little):
    op = ">" if Endianess(endianess) is Endianess.big else "<"
    data = struct.pack(op + "f", value)
    return struct.unpack(op + "HH", data)

def word2float(word0, word1, endianess=Endianess.little)
    op = ">" if Endianess(endianess) is Endianess.big else "<"
    data = struct.pack(op + "HH", word0, word1)
    return struct.unpack(op + "f", data)[0]
@kiaralle: das 65535 liegt ja daran, dass Du signed int32 hast. Und wenn man das als zwei 16bit-Werte vorliegen hat, arbeitet man auch am besten mit struct.pack und unpack.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1206
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Sirius3 hat geschrieben: Mittwoch 30. August 2023, 20:26 @DeaD_EyE: warum verwendest Du für die float pack, für die ints aber nicht???
Die Lösung ist natürlich schöner. Kennst Du das mit dem Wald und den Bäumen?
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten