Forum: Mikrocontroller und Digitale Elektronik Modbus Daten Verstehen!


von Werner M. (werner-m)


Angehängte Dateien:

Lesenswert?

Hallo
Ich habe ein Siemens Sentron Pac3200 (Ein Messgerät) von diesem möchte 
ich Daten per Modbus Auslesen.
Ich bekomme auch Daten aber die Zusammensetzung ist mir schleierhaft
Also bei 230v am Eingang bekomme ich auf der Adresse 1 0x43 und auf 
Adresse 2 x066
bei 232 bekomme ich 0x43+x068

Das ergibt nach meiner berechnung (0x43*256)=17152+102 = 17254
Und genau das wird auch in meiner Anwendung angezeigt.
Wenn ich die Spannung trenne bekomme ich zwei mal 0. Auch auf anderen 
Adressen wie Leistung und Frequenz bekomme ich Daten aber ich finde 
nicht so recht wie ich die auswerten kann.



Das Datenblatt von dem Gerät
https://cache.industry.siemens.com/dl/files/150/26504150/att_906559/v1/A5E01168664A-04_DE_122016_201612221316291494.pdf

von -gb- (Gast)


Lesenswert?

Da steht was von Float.
Dann könnte noch sein dass die Reihenfolge vertauscht ist.

von -gb- (Gast)


Lesenswert?

Wie lang ist denn in Register? 32Bit?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Also da ist irgendwas sehr komisch.
Modbus hat immer 16Bit Register und du bekommst 2x8Bit zurück?
Wenn man jeweils die oberen 8Bit als 0 ansieht, so kommt bei online 
hex->float konvertern nur Gülle raus. (egal welche Reihenfolge)
https://www.h-schmidt.net/FloatConverter/IEEE754.html

Kannste nochmal gucken ob due da was fehlerhaft ausließt?

Werner M. schrieb:
> Das ergibt nach meiner berechnung (0x43*256)=17152+102 = 17254
Wo auch immer du das her hast, so wandelt man kein float zu int um.

von GEKU (Gast)


Angehängte Dateien:

Lesenswert?


von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Das ist dann aber ein sehr beklopptes Format wenn man sich aus 2 16Bit 
Modbusregistern einen 16Bit float zusammenbauen muss.
Dann steht da nichtmal float16, sondern float (das ist dann eigentlch 
32Bit).

Nunja ... Siemens eben ...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Die Beschreibung im Eröffnungsposting schreibt klar, daß je zwei 
Register zu einem Float-Wert zusammengefasst werden.

Modbus kennt nur zwei Datentypen, das Register, das immer 16 Bit groß 
ist, und das Bit ("Coil").

Irgendwie mag ich an 16-Bit-Float verpackt in zwei nur zur Hälfte 
genutzten Register nicht glauben. Siemens ist zwar Weltmarktführer, wenn 
es ums inkompetente Stümpern geht, aber so etwas würde dem ganzen noch 
eine Sonderlocke aufsetzen, die ich selbst denen nicht zutraue.

Ich tippe hier auf ein Interpretationsproblem.

Interessant wäre es hier, die Rohdaten der Modbustelegramme zu sehen, 
d.h. den Hexdump der kompletten empfangenen Daten, die als Reaktion auf 
das Kommando Read Input Register bzw. Read Holding Register gesendet 
werden.

Ein Tool, mit dem man Modbus-Geräten etwas auf die Schliche kommen kann, 
auch wenn es nicht die Telegramm-Rohdaten anzeigt, findet sich hier:

https://www.the-sz.com/products/medford/

Damit kann man sich den Inhalt gleich mehrer Register in einem Rutsch 
anzeigen lassen.

von GEKU (Gast)


Lesenswert?

Mw E. schrieb:
> Modbus hat immer 16Bit Register und du bekommst 2x8Bit zurück?

https://de.m.wikipedia.org/wiki/Modbus
https://www.feldbusse.de/ModbusTCP/modbustcp_protokoll.shtml

Laut der Unterlage

  https://cache.industry.siemens.com/dl/files/150/26504150/att_906559/v1/A5E01168664A-04_DE_122016_201612221316291494.pdf

bezieht sich der Offset auf die Registernummer. Das Register selbst ist 
16 Bit groß!

Man sieht es an der IP Adresse, die 2 Register benötigt. Die IP Adresse 
ist 32 Bit lang (unsigned long).

Die Daten werden im Big Endian Format gespeichert.
https://de.m.wikipedia.org/wiki/Byte-Reihenfolge

Die Frage ist was wird auf der 3. und 4. Adresse gespeichert. Es sollte 
2x die Null sein!

von GEKU (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Irgendwie mag ich an 16-Bit-Float verpackt in zwei nur zur Hälfte
> genutzten Register nicht glauben.

Es sind vermutlich 2 Bytes zu wenig ausgelesen worden.

Daher 0x4366 statt 0x43660000

0x43 ist der Vorzeichen behaftete binäre Expont, und 0x660000 die 
Mantisse.
Zwei Byte mehr einlesen, dann stimmt's.

Die zwei unteren Bytes sind vermutlich nicht mehr relevant, da unter der 
Messgenauigkeit (<1%). Es kann sein, dass diese immer Null sind.

von GEKU (Gast)


Lesenswert?

1
#include <stdio.h>
2
3
union U
4
{
5
        float f;
6
        unsigned long i;
7
}u;
8
9
10
int main(void)
11
{
12
13
        u.i = 0x43660000;
14
15
        printf("\r\n%f\r\n",u.f);
16
}

von Schorsch X. (bastelschorsch)


Lesenswert?

Manchmal ist es auch sehr verwirrend, dass die Modbus Adressen ab 1 
gezählt werden, aber dann trotzdem als eine Adresse=0 übertragen wird.
Ich hab das bisher noch nie kapiert, aber alle bisher verwendeten 
Displays am Modbus machen das so. In manchen Systemen läßt sich auch 
noch die Wort-Reihenfolge umschalten.
32bit floats funktionieren im Allgemeinen aber immer.
Kinco hat einen double Eintrag, der aber nur Unfug anstellt, bzw. 
vielleicht hab ich es einfach noch nicht geschnallt.

von GEKU (Gast)


Lesenswert?

Schorsch X. schrieb:
> In manchen Systemen läßt sich auch noch die Wort-Reihenfolge umschalten

Wort oder Bytereihenfolge (Endian)?

von Ulrich (Gast)


Lesenswert?

Wortreihenfolge

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Schorsch X. schrieb:
> Manchmal ist es auch sehr verwirrend, dass die Modbus Adressen ab 1
> gezählt werden, aber dann trotzdem als eine Adresse=0 übertragen wird.

Es gibt insgesamt drei Arten, Registeradressen auf dem Modbus anzugeben.

Zwei codieren die Art des Registers in die Registernummer, in der alten 
Variante waren so je 10000 Register je Typ möglich, und Registernummern 
begannen mit 1.

00001 - 10000 : Read/Write Coil
10001 - 20000 : Read Discrete Input
30001 - 40000 : Read Input Register
40001 - 50000 : Read/Write Holding Register

(Adressen zwischen 20001 und 30000 sind undefiniert, Adressen ab 50001 
ebenso)

Die etwas neuere Variante fügt eine zusätzliche Null in die Adresse ein, 
so daß 65536 Register je Typ möglich werden:

000001 - 065536 : Read/Write Coil
100001 - 165536 : Read Discrete Input
300001 - 365536 : Read Input Register
400001 - 465536 : Read/Write Holding Register

(diese neuere Notation soll zwingend mit führenden Nullen geschrieben 
werden, so daß bei Read/Write Coil klar ist, was gemeint ist)

Diese beiden Formen sind überbestimmt, denn die Art des Registers wird 
im Modbusprotokoll durch den Code unabhängig von der Adressierung 
festgelegt.

Zur weiteren Verwirrung wird manchmal auch der Begriff Offset 
verwendet.


Aber all das sind nur unterschiedliche Darstellungsformen für ein und 
die selbe Angelegenheit - das eigentliche Protokoll ist davon komplett 
unberührt, das adressiert jeden Registertyp mit einer bei 0 beginnenden 
16-Bit-Adresse.


Was bei Modbus nicht festgelegt ist, und jedem Hersteller selbst 
überlassen bleibt, ist das Zusammenlegen mehrerer Register, um größere 
Datentypen als 16-Bit-Int zu transportieren. Die Wortreihenfolge muss in 
der Dokumentation beschrieben werden, bei besseren Geräten ist sie das 
auch, bei weniger guten muss man das durch Ausprobieren und Vergleichen 
mit (hoffentlich anderswoher bekannter) Werte bestimmen.

: Bearbeitet durch User
von Zeno (Gast)


Lesenswert?

@TO
Ich arbeite gerade ein einer ähnlichen Sache, allerdings nicht Siemens 
sondern Entes (EPM-06CS).
Bist Du Dir sicher das in den Registern eine Floatzahl steht? Bei dem 
von mir genannten Gerät sind alle Werte integer und müssen mit einem 
Koeffizienten bewertet werden. Die Werte stehen immer in einem 16Bit 
Registerpaar (also insgesamt 32Bit)
Beispiel: Spannung L1-N steht im Register R0 und R1. R0 ist immer 0 und 
der Wert steht inh R1 als integer und muß mit 0.1 multpliziert werden. 
Dann kommt auch genau der Messwert raus.

Ausnahme sind Register wo auch negative Werte stehen können COS PHI. Bei 
positiven Werten steht dann nur ein Wert im 2. Register des Paares, 
während bei negativen Werten im ersten Register immer -1 (65535) steht 
und im zweiten Register der eigentliche Wert, natürlich dann negativ.

Google mal nach mbpoll. Das hat mir sehr weiter geholfen. Damit kann man 
für's erste die Register mal auslesen und sich ausgeben lassen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Zeno schrieb:
> Bist Du Dir sicher das in den Registern eine Floatzahl steht? Bei dem
> von mir genannten Gerät sind alle Werte integer und müssen mit einem
> Koeffizienten bewertet werden.

Das ist geräteabhängig. Der Modbus-Standard selbst sieht weder float- 
noch 32-Bit-Übertragung vor, das ist eine zusätzliche hoffentlich in 
der Gerätedokumentation beschriebene Konvention.

von Zeno (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Das ist geräteabhängig. Der Modbus-Standard selbst sieht weder float-
> noch 32-Bit-Übertragung vor, das ist eine zusätzliche hoffentlich in
> der Gerätedokumentation beschriebene Konvention.

Naja so ins Detail bin ich da erst mal nicht eingestiegen, ich wollte 
nur das von mir genannte Gerät auslesen. Die Dokumentation von Entes ist 
da nicht so9 hilfreich, wenn man neu auf dem Gebiet ist und erst mal 
sehen will ob es überhaupt funktioniert.
Das von mir genannte Programm hat dann aber sehr weiter geholfen und 
dann war auch die Dokumentation von Entes verständlich.

von Detlef H. (Gast)


Lesenswert?

Hallo Werner,

ich hatte mal eine ähnliche Aufgabe.
Dazu mussten Siemens-Profibus-Daten die jeweils ein oder zwei 
16bit-Register lang waren und dazu auch noch in verschiedenen 
Datenformaten vorlagen in 32-bit-Register einer Jetter-SPS übertragen 
und aufbereitet werden.

Im nachfolgen Task 1 des SPS-Programms sieht man,
welche 16-bit Siemens-Profibus-Daten wie zusammengesetzt und konvertiert 
werden musste, damit sinnvolle 32-bit-Daten entstehen.
Es gibt ein paar Erläuterungen am Anfang des Tasks
und anschließend ist der Programmcode kommentiert.
Zuerst kommt die Kopierroutine, danach die Datenkonvertierung.
Der Programmcode ist mit Absicht nicht auf maximale Effizienz sondern 
auf maximale Verständlichkeit ausgelegt.
Vielleicht hilft das weiter.
Ich könnte mir vorstellen, daß einige Modbus-Daten ähnlich konvertiert 
werden müssen:
------------------------------------------------------------------------ 
-----------
TASK 1          //Profibus-Daten übertragen und Formatkonvertierung

//Datenformat "BOOL" (Bit) --> keine Formatkonvertierung notwendig,
//  jedoch beachten, daß HIGH-und LOW-Byte vertauscht sind.
//--------------------------
//Datenformat "INTEGER" (Ganzzahl) --> Formatkonvertierung notwendig:
//Daten vom 16-bit-Profibus-INTEGER-Format in das 
32-bit-Jetter-INTEGER-Format konvertieren:
//Grund: Im 16-bit-Profibus-INTEGER-Format befindet sich das Vorzeichen 
auf Bit 15.
//Hinweis: Negative Zahlen werden als Zweierkomplement dargestellt.
//Um in der Jetter-SPS das Vorzeichen korrekt verarbeiten zu können muß 
folgendes gemacht werden:
// Bit 16 bis 31 mit Einsen auffüllen wenn Bit 15 (Vorzeichen Minus) 
gesetzt ist.

//--------------------------
//Datenformat "REAL" (Gleitkommazahl) --> Formatkonvertierung notwendig:
//Analogwerte im REAL-Format konvertieren:
//Siemens-32-bit-Real-Zahlen werden als zwei aufeinanderfolgende
// 16-bit-Profibus-Wörter übertragen.
//Die beiden 16-bit-Profibus-Wörter landen Jetter-Seitig in zwei 
32-bit-Registern
// und müssen anschließend wieder lagerichtig zusammengesetzt werden.
//Das Ergebnis ist ein 32-bit Integer-Register, welche die korrekte 
Bitfolge enthält.
//Diese muß anschließend noch als "Real"-Wert gemäß "IEE 754" 
interpretiert werden.
//--------------------------

LABEL 10        //Sprungmarke

//Die nachfolgende Schleife dient dazu 120 Register aus dem 
Profibusmodul in die SPS zu kopieren.
// Es werden die Register 12400 bis 12519 in die Register 400 bis 519 
kopiert.
// Da der Kopierbefehl nicht unterbrechbar ist, werden nicht alle 
Register auf einmal kopiert.
WHEN FLAG 1            //Wenn "Profibus-Konfiguration erfolgreich"
//  AND BIT_CLEAR (12100, 6)  //und gerade keine Profibus-Daten 
ausgetauscht werden
    THEN  //dann

REG 580 = 12400  //Adressregister mit der Nummer des 
Profibus-Startregisters laden
REG 581 = 400  //Adressregister mit der Nummer des SPS-Startregisters 
laden

LABEL 17    //Sprungmarke

COPY (20, @580, @581)  //Kopiere 20 Register vom Profibus-Modul in die 
SPS (indirekte Adressierung)

REG 580  = REG 580 + 20  //Erhöhe den Inhalt des 
Profibus-Adressregisters um 20
REG 581  = REG 581 + 20  //Erhöhe den Inhalt des SPS-Adressregisters um 
20

IF REG 581 > 519    //Wenn die Schleife bis zur letzten Adresse 
durchgezählt hat
  THEN GOTO 18    //dann gehe zur angegebenen Sprungmarke
  ELSE GOTO 17    //ansonsten gehe zur angegebenen Sprungmarke

LABEL 18    //Sprungmarke

//Daten im INTEGER-Format konvertieren:
//Die nachfolgende Schleife dient dazu die Register 418 bis 451 zu 
adressieren
// und dort die oben beschriebene Konvertierung durchzuführen.
REG 590 = 418  //Adressregister mit der Nummer des Startregisters laden 
(indirekte Adressierung)

LABEL 11    //Sprungmarke


IF BIT_SET (@590, 15)  //Wenn Bit 15 (Vorzeichen Minus) vom indirekt 
adressierten Register gesetzt ist,
  THEN REG @590 = REG @590  WOR 0b11111111111111110000000000000000 
//dann fülle die ersten 16 Bit mit Einsen auf
  ELSE REG @590 = REG @590 WAND 0b00000000000000001111111111111111 
//ansonsten fülle die ersten 16 Bit mit Nullen auf

THEN      //dann
REGINC 590    //Erhöhe den Inhalt des Adressregisters um 1

IF REG 590 > 451    //Wenn die Schleife bis zur letzten Adresse 
durchgezählt hat
  THEN GOTO 12    //dann gehe zur angegebenen Sprungmarke
  ELSE GOTO 11    //ansonsten gehe zur angegebenen Sprungmarke

LABEL 12    //Sprungmarke

//Alle Vorzeichen-konvertierten INTEGER-Register auf einen neuen 
Registerbereich kopieren zwecks Weiterverarbeitung.

COPY (34, 418, 618)  //kopiere die an erster Stelle genannte Anzahl von 
Registern
  //vom danach genannten Register beginnend, auf das zu Schluß genannte 
Register und folgende.
//----------------------------------------------------------------

//Daten im REAL-Format konvertieren:
//Die nachfolgende Schleife dient dazu die Register 452 bis 507 zu 
adressieren
// und dort die oben beschriebene Konvertierung durchzuführen.
REG 591 = 20000  //Adressregister mit der Nummer des Startregisters K2 
laden (indirekte Adressierung)
REG 592 = 452  //Adressregister mit der Nummer des Startregisters K1a 
laden (indirekte Adressierung)
REG 593 = 453  //Adressregister mit der Nummer des Startregisters K1b 
laden (indirekte Adressierung)

LABEL 13    //Sprungmarke

SHIFT_LEFT (@592, 16)  //Im genannten Register werden die Bits 16 
Stellen nach links verschoben
REG @591 = REG @592 WOR REG @593  //Die rechten 16 Bits vom zweiten 
Register werden in das erste
            // Register übertragen und in ein (Gleitkomma-definierbares) 
Register kopiert.

REGINC 591      //Erhöhe den Inhalt des Adressregisters um 1
REGINC 592      //Erhöhe den Inhalt des Adressregisters um 1
REGINC 592      //Erhöhe den Inhalt des Adressregisters nochmal um 1 
(also insgesamt um 2)
REGINC 593      //Erhöhe den Inhalt des Adressregisters um 1
REGINC 593      //Erhöhe den Inhalt des Adressregisters nochmal um 1 
(also insgesamt um 2)

IF REG 593 > 507    //Wenn die Schleife bis zur letzten Adresse 
durchgezählt hat
  THEN GOTO 14    //dann gehe zur angegebenen Sprungmarke
  ELSE GOTO 13    //ansonsten gehe zur angegebenen Sprungmarke

LABEL 14    //Sprungmarke

REGISTER_LOAD (2909, 20000)  //Beginn der Gleitkommaregister auf diese 
Adresse umschalten
  //Dadurch werden die Bits in diesen Registern jetzt als Gleitkommazahl 
interpretiert.

COPY (28, 20000, 65024)    //Kopiere die an erster Stelle genannte 
Anzahl von Registern
  //vom danach genannten Register beginnend, auf das zu Schluß genannte 
Register und folgende.
  //Sinn dieser Aktion ist es, die zuvor auf Gleitkomma umgeschalteten 
Registerinhalte in den
  //Standard-Gleitkommabereich zu kopieren, damit die Ursprungsregister 
wieder auf
  //Ganzzahl zurückgeschaltet werden können.

REGISTER_LOAD (2909, 65024)  //Beginn der Gleitkommaregister auf diese 
Adresse (Standard) umschalten
  //Dadurch werden die Bits in den davorliegenden Registern wieder als 
Ganzzahl interpretiert.
//----------------------------------------------------------------

//Daten im INTEGER-Format konvertieren:
//Die nachfolgende Schleife dient dazu die Register 508 bis 519 zu 
adressieren
// und dort die oben beschriebene Konvertierung durchzuführen.
REG 594 = 508  //Adressregister mit der Nummer des Startregisters laden 
(indirekte Adressierung)

LABEL 15    //Sprungmarke

IF BIT_SET (@594, 15)  //Wenn Bit 15 (Vorzeichen Minus) vom indirekt 
adressierten Register gesetzt ist,
  THEN REG @594 = REG @594  WOR 0b11111111111111110000000000000000 
//dann fülle die ersten 16 Bit mit Einsen auf
  ELSE REG @594 = REG @594 WAND 0b00000000000000001111111111111111 
//ansonsten fülle die ersten 16 Bit mit Nullen auf

THEN      //dann
REGINC 594    //Erhöhe den Inhalt des Adressregisters um 1

IF REG 594 > 519    //Wenn die Schleife bis zur letzten Adresse 
durchgezählt hat
  THEN GOTO 16    //dann gehe zur angegebenen Sprungmarke
  ELSE GOTO 15    //ansonsten gehe zur angegebenen Sprungmarke

LABEL 16    //Sprungmarke
//Alle Vorzeichen-konvertierten INTEGER-Register auf einen neuen 
Registerbereich kopieren zwecks Weiterverarbeitung.

COPY (12, 508, 708)  //kopiere die an erster Stelle genannte Anzahl von 
Registern
  //vom danach genannten Register beginnend, auf das zu Schluß genannte 
Register und folgende.

GOTO 10    //dann gehe zur Sprungmarke (Task-Anfang)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.