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!
Beide enden mit 120 Ohm Terminiert ? RS485 Adapter auf Seriell oder USb Vorhanden ?
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 |
Hallo, danke für die Antworten, habs getestet mit 111,2 , gleiches Problem.. USB-Adapter hab ich aktuell keinen da, werd ich vml bestellen müssen..
Du hast aber schon einen RS485-Treiber IC irgendwo in deiner Schaltung?
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..
Stefan B. schrieb: > Der Bus sollte funktionieren, wenn ich mit den Oszi schauen kommt wenn > ich die > Adresse 33 anspreche nach dem senden sofort eine Antwort, Man kann sich die Antwort auch selber dekodieren. Was steht denn drin?
Ich mache abends ein Bild von den Daten welche auf dem Bus unterwegs sind.
Frage & Antwort auf dem Bus wären wirklich hilfreich. senden solltest du: [Modbus_ID][Funktionscode][Registernummer][CRC] @Harald Dieser Offset hat mich, als ich mich in das Thema eingearbeitet habe, wahnsinnig gemacht. Gruß Anselm
Anselm 6. schrieb: > Frage & Antwort auf dem Bus wären wirklich hilfreich. Als Hexdump. Kann man auch ohne Logikanalysator angezeigt bekommen, z.B.mit Portmon https://learn.microsoft.com/en-us/sysinternals/downloads/portmon
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!
Welchen Pin du für Rx/Tx nimmst kannst du frei entscheiden. Du musst schon vor den senden den Port setzen und danach zurück. (Je nach Polarität des RE/TE deines RS485 Transceivers. Anselm
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 | }
|
Stefan B. schrieb: > Ich muss mich jetzt noch mit den zusammensetzten der beiden Register zu > einem Spannungswert beschäftigen, Welche Werte kommen denn?
Reg 30111 : 65280 Reg 30112 : 2205 , diese ändert sich immer etwas da die Netzspannung nicht konstant ist. 2205 ergibt 220,5V
Register 30111 ist Hex 0xFF00 So einen Wert finde ich immer verdächtig. Anselm btw.: 220V ist schon lange her, bist du sicher dass der Wert stimmt?
Ja, die 220 Stimmen schon, Zähler ist aktuell an einem Regeltrenntrafo angeschlossen, im Display wird auch der gleiche Wert angezeigt , wie im Datenstrom, Werte ändern sich auch beide wenn ich die Spannung ändere
Mal das Bild im Eröffnungsposting ansehen. Da steht was von "Datatype T5", was eine Finder-spezifische Erweiterung sein dürfte und in den obersten acht Bit codiert ist. Gibt es mehr Unterlagen zum Zähler?
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?
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.
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.
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 | }
|
Da geht's weiter (inkl. Lösung): https://forum.arduino.cc/t/modbus-zahler-auslesen-mit-arduino-uno/1119155
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.