Finder Zähler mit ModBus auslesen

OP #7399003
Lesenswert?

Hallo, hab ein Problem mit Modbus, zugegeben Modbus ist nicht mein ding.. ich bin eher in der Leistungselektronik zuhause.. Vorhaben: im Endausbau sollen 3 Zähler Type Finder 7M.38.8.400.0212 per Modbus mit einem µC ausgelesen werden. Aktuell spiele ich mit einem Zähler und einem Arduino UNO als test.

Zähler ist eingestellt auf ID 33, 19200Baud, 8N1;

lt. Anleitung sollte in Adresse 30111 und 30112 die Spannung an L3 auszulesen sein. Ich habe die Schaltung aufgebaut, lt. Oszi werden Daten auf dem Bus gesendet, und der Zähler sollte auch antworten, da ich immer 2 Datenpakete sehen. Wenn ich die Zähleradresse ändere, ist nur 1 Paket sichtbar, ich gehe also davon aus dass der Bus an sich OK sein sollte, (Buslänge 30cm).

Ich bekomme jedoch die Spannung nicht angezeigt,

ich verwende folgenden Code:

#include <ModbusMaster.h> // Modbus Master Library #include <SoftwareSerial.h> // SoftwareSerial Library

SoftwareSerial modbusSerial(4, 5); // RX, TX for Modbus ModbusMaster node; // ModbusMaster Objekt

void setup() { Serial.begin(9600); // Serielle Kommunikation mit der Baudrate 9600 für Debugging modbusSerial.begin(19200); // Serielle Kommunikation mit der Baudrate 19200 für Modbus node.begin(33, modbusSerial); // ModbusSlave ID und Serielle Objekt initialisieren }

void loop() { uint16_t registerValue; uint8_t result;

// Senden einer Modbus-Anfrage an Slave-Adresse 33, Funktion 04, Register 30111 (2 Register lesen) result = node.readInputRegisters(30111, 2); // Lesen von 2 Input-Registern ab Adresse 30111

if (result == node.ku8MBSuccess) { // Überprüfen, ob das Lesen erfolgreich war registerValue = node.getResponseBuffer(0); // Wert des ersten Registers in der Antwort Serial.print("Register 30111: "); Serial.println(registerValue); registerValue = node.getResponseBuffer(1); // Wert des zweiten Registers in der Antwort Serial.print("Register 30112: "); Serial.println(registerValue); } else { Serial.println("Fehler beim Lesen der Register!"); }

delay(1000); // Wartezeit zwischen den Anfragen }

evtl. kann mir jemand helfen, mit Bussystemen bin ich nicht wirklich vertraut, wo liegt mein Fehler?

Vielen Dank!

Angehängte Dateien:
#7399011
Lesenswert?

Irgendein Schwachkopf ist mal auf die Idee gekommen, beim Modbus-Protokoll in den Registernummern zusätzlich die Art des Zugriffs (Input Register, Holding Register, Coil, Input State) zu codieren, und dazu zur /eigentlichen/ Registernummer einen willkürlichen Offset von entweder 10000, 30000 oder 40000 zu addieren.

Das ist komplett bescheuert, weil es einseits nichts mit dem zu tun hat, was der Modbus /tatsächlich/ macht, und weil es andererseits völlig sinnlos die Anzahl der verfügbaren Register reduziert.

Tatsächlich aber werden auf dem Modbus /je Typ/ 65536 Register unterstützt, die von 0 an aufsteigend durchnumeriert werden.

Betrachtet man Dein Beispiel (findermodbus.png), so werden dort zwei Register ausgelesen, beginnend bei 0x6b (107).

Der erläuternde Text in Deinem Bild nennt dieses Register 30107.

Also ändere Dein Programm dahingehend, daß der schwachsinnige Pseudo-Offset weggelassen wird:

1
  result = node.readInputRegisters(111, 2);  // Lesen von 2
OP #7399435
Lesenswert?

Ja, Treiber IC MAX485 ist vorhanden, Abschlusswiderstände sind vorhanden, Der Bus sollte funktionieren, wenn ich mit den Oszi schauen kommt wenn ich die Adresse 33 anspreche nach dem senden sofort eine Antwort, wenn ich eine andere Adresse anspreche, welche es nicht gibt, kommt keine Antwort.

Kann mich leider immer nur abends hinsetzen, denk evtl. liegt es am Code..

OP #7399912
Lesenswert?

Ich habe gerade etwas rumgemessen, dabei viel mir auf:

die Umschaltung lesen/schreiben läuft nicht, DE/RE sind im High, damit sollte schreiben möglich sein, jedoch kein lesen.

Mit dem Oszi kann ich auf TX daten sehen welche auch nach dem Max485 vorhanden sind, auf der Busleitung kommt auch eine Antwort, diese wird jedoch nicht am RX weiter zum Arduino gegeben, da DE/RE immer auf high sind.

beide Pins sind an Pin2 des Arduinos angeschlossen, jedoch werden diese im im Programm nirgends deklariert/initiert, Ich kenne mich mit Modbus nicht aus, macht die ModBusmaster - LIB die Umschaltung schreiben/lesen nicht automatisch im Hintergrund mit?

wie kann ich die Pins zuordnen?

Danke!

OP #7400699
Lesenswert?

Danke für die Antworten, ich hab jetzt einen Code der läuft und die Spannung aus den beiden Registern ausliest, Fehler waren: DE/RE-Pin des Max485 funktionierten nicht und auch die Registeradressen stimmen so nicht wie im Datenblatt angegeben, Spannung L3 (REG 30111 und 30112) müssen wie oben von Harald K. geschrieben um den Wert von jeweils 10000/20000/30000 reduziert werden, dann kommen die Wert..

Ich muss mich jetzt noch mit den zusammensetzten der beiden Register zu einem Spannungswert beschäftigen, aber soweit läuft der Code aktuell..

1
#include <ModbusMaster.h>    // Modbus Master Library
2
#include <SoftwareSerial.h>  // SoftwareSerial Library
3

4
SoftwareSerial modbusSerial(4, 5);  // RX, TX for Modbus
5
ModbusMaster node;                  // ModbusMaster Objekt
6

7
constexpr uint8_t modbusEnablePin = 2;           // The GPIO used to control the MAX485 TX pin. Set to 255 if you are not using RS485 or a selfsensing adapter
8

9

10
void setup() {
11

12
  pinMode (modbusEnablePin, OUTPUT); //Max485 Steuerpin als Ausgang.
13

14
  Serial.begin(9600);          // Serielle Kommunikation mit der Baudrate 9600 für Debugging
15
  modbusSerial.begin(19200);   // Serielle Kommunikation mit der Baudrate 19200 für Modbus
16
  node.begin(33, modbusSerial);  // ModbusSlave ID und Serielle Objekt initialisieren
17

18
//für die ModbusLib, Steuerung des ModbusEnable Pins
19
  node.preTransmission(preTransmission);
20
  node.postTransmission(postTransmission);
21
}
22

23
// this function will be called before the client transmits data
24
void preTransmission() {
25
  digitalWrite(modbusEnablePin, HIGH);
26
}
27

28
// this function will be called after the transmission
29
void postTransmission()  {
30
  digitalWrite(modbusEnablePin, LOW);
31
}
32

33

34
void loop() {
35
  uint16_t registerValue0;
36
  uint16_t registerValue1;
37
  uint8_t result;
38

39

40
  // Senden einer Modbus-Anfrage an Slave-Adresse 33, Funktion 04, Register 30111 (2 Register lesen)
41

42

43
  result = node.readInputRegisters(111, 2);  // Lesen von 2 Input-Registern ab Adresse 30111
44

45

46
  if (result == node.ku8MBSuccess) {  // Überprüfen, ob das Lesen erfolgreich war
47
    registerValue0 = node.getResponseBuffer(0);  // Wert des ersten Registers in der Antwort
48
    Serial.print("Register 30111: ");
49
    Serial.println(registerValue0);
50
    registerValue1 = node.getResponseBuffer(1);  // Wert des zweiten Registers in der Antwort
51
    Serial.print("Register 30112: ");
52
    Serial.println(registerValue1);
53

54

55
  } else {
56
    Serial.println("Fehler beim Lesen der Register!");
57
  }
58

59
  delay(1000);  // Wartezeit zwischen den Anfragen
60
}
OP #7400925
Lesenswert?

Hallo,

https://cdn.findernet.com/app/uploads/Benutzerhandbuch_Typ_7M38_DE.pdf

hier ist alles was es über den Zähler in Bezug auf ModBus gibt, Seite 33 Modbus Kommunikation.. Seite 34 ff, alle Register

Seite 53 Entschlüsselung der Datentypen

Anruf bei Finder bleibt erfolglos, zum Thema Modbus kann mir keiner etwas sagen..

evtl. sind ja für jeden Parameter der verarbeitet wird generell 2 Register reserviert und das höhere Register bleibt dann leer?

#7400945
Lesenswert?

Na, für T5 steht da das hier:

Unsigned Measurement (32 bit) Decade Exponent(Signed 8 bit) Binary Unsigned Value (24 bit) Example: 123456*10 –3 stored as FD01 E240 (16)

Reg 30111 : 65280 Reg 30112 : 2205

das ist FF00 089D

FF ist der "decade exponent", das ist -1

00 08 9D ist der 24-Bit Wert (2205), also 2205 * 10E-1 = 220.5

Passt doch alles.

Stefan B. schrieb:

evtl. sind ja für jeden Parameter der verarbeitet wird generell 2 Register reserviert und das höhere Register bleibt dann leer?

Nein. In der Tabelle ab S. 34 steht das alles fein säuberlich drin, in der Spalte "Data" steht, wie der Wert zu interpretieren ist (für R.30111 steht da T5), und in den ersten beiden Spalten steht, ob ein oder zwei Register gelesen werden müssen.

Bei 30111 steht in der zweiten Spalte 30112, also ist logisch, daß die beiden Werte zu kombinieren und dann nach der Typbeschreibung T5 zu interpretieren sind.

Ich habe schon deutlich schlechtere Modbus-Dokumentationen gesehen.

OP #7401005
Lesenswert?

Ok ich glaub jetzt hab ich verstanden. REG 111 REG 112 FF00 2205 FF = Exponent-1 00 2205 Messwert FE = Exponent-2 FD = Exponent -3

Um den eigentlichen Wert zu ermitteln darf ich nicht direkt beide Register kpl. verknüpfen, da ich dann ja das FF (beiden höchsten stellen) mit verrechne.

OP #7401021
Lesenswert?

Dann könnte der Code unten evtl. funktionieren, kann es aber erst abends testen,

1
float convertRegistersToDecimal(uint16_t reg111, uint16_t reg112) {
2
  // beiden Registerwerte zu einer 32-Bit Ganzzahl kombinieren
3
  uint32_t regValue = ((uint32_t)reg111 << 16) | reg112;
4
  
5
  // Exponenten aus den höheren Bits (Bit 31 bis 24) extrahieren
6
  uint8_t exponent = (regValue >> 24) & 0xFF;
7
  
8
  // Wert aus den niedrigeren Bits (Bit 23 bis 0) auslesen
9
  uint32_t value = regValue & 0xFFFFFF;
10
  
11
  // Exponenten in eine vorzeichenbehaftete Ganzzahl wandeln
12
  int8_t signedExponent = (int8_t)exponent;
13
  
14
  // 24-Bit- Ganzzahl in eine Dezimalzahl wandeln
15
  float decimalValue = (float)value * pow(10, -signedExponent);
16
  
17
  return decimalValue;
18
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren