Möchte gerne Modbus RTU auslesen

Guten Abend zusammen:

Ich bin neu hier im Forum und möchte mich gerne kurz vorstellen:
Mein Name ist Stefan, ich bin 32 und beschäftige mich seit einem Jahr mit dem Arduino.
Mein Ziel ist es, die Materie zu verstehen und mir das was ich brauche selber zusammenzubasteln.
Daher habe ich zunächst den dicken Schinken von Brühlmann - Arduino Praxiseinstieg durchgearbeitet.

Da ich mich schon immer hobbymäßig mit dem Wetter beschäftige ist natürlich das Hauptthema der Bau einer Wetterstation ganz nach meinen Wünschen.

Das ganze funktioniert auch schon. Ich bin in der Lage, Sensoren über I2C und SPI auszulesen, per Funk (433 MHz) ins Haus zu übertragen und dort auf einem I2C Display mit MIN/MAX darzustellen.

Parallel dazu im Moment ist ein HTML - Webserver und eine Speicherung auf SD - Karte in Bearbeitung. Hier gehts gut vorwärts.

Jetzt zu eigentlichen Thema: Es besteht für mich die Möglichkeit "günstig"an einen Profisensor mit ventilierter Wetterhütte dranzukommen nach DWD - Standard.
Leider unterstützt er nicht I2C sondern nur Modbus RTU auf dem RS485 Bus.
Das Protokoll ist mir bekannt da ich beruflich in der Leittechnik tätig bin.

Ich habe hier einen Elsner Modbus Temperaturfühler herumliegen, welcher auch Modbus RTU liefert.
Diesen möchte ich nun auslesen und am Arduino blinkt nur die TX Lampe, die RX bleibt aus:

  • Spannung am Sensor liegt an und wurde auch gemessen
  • Der Sensor wurde am PC mit QModbus Master erfolgreich ausgelesen

Im seriellen Monitor erscheint im Takt der Anfrage immer nu ein q

Kann hier mir jemand helfen. Ich wäre sehr dankbar darüber. Ist es überhaupt möglich einen Modbus Sensor mit dem Arduino auszulesen?

Vielen Dank im Voraus

#include <ModbusMaster.h>

// Pin DI auf TX/Pin R0 auf RX
#define MAX485_DE      3
#define MAX485_RE_NEG  2

//Angeschlossen wird ein Elsner TH - AP Modbus
//Funktion 04: Read input registers
//Register 0: Temperatur
//Register 1: Feuchte
//Register 2: Taupunkt
//Slave Adresse 1

ModbusMaster node;

void setup() {
  // set pins to output
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  // Baudrate des Modbus Sensors: 19200
  Serial.begin(19200);
  // slave ID 1
  node.begin(1, Serial);
}

void loop() {
  //Vor Übertragung auf High
  digitalWrite(MAX485_RE_NEG, HIGH);
  digitalWrite(MAX485_DE, HIGH);
 
  uint8_t result;
  // read 1 Input Register bei Adresse 1, Funktion 04
  result = node.readInputRegisters(1, 1);
  delay(1000);
 
  // Nach Übertragung auf LOW
  digitalWrite(MAX485_RE_NEG, LOW);
  digitalWrite(MAX485_DE, LOW);

  if (result == node.ku8MBSuccess)
  {
    Serial.print("Feuchte: ");
    //Anzeige eines Registers im Seriellen Monitor
    Serial.println(node.getResponseBuffer(1));
  }
  delay(1000);
 
}

Ich habe die wichtigsten Zeilen beschriftet um das ganze besser zu verstehen
Gruß Stefan

Ist es überhaupt möglich einen Modbus Sensor mit dem Arduino auszulesen?

das geht bestimmt.

Was mich an deinem Sketch stört: du verwendest Hardware-Serial für die Ausgabe deiner Ergebnisse und für die Kommunikation mit dem Slave. Aus meiner Sicht wird das nicht gut klappen.

Bitte zeichne einen Schaltplan von deinem Aufbau und mach ein Echtbild in dem wir klar erkennen können was du wie angeschlossen hast.

Guten Abend,

also ich habe es mal gezeichnet. A, B, gehen dann entsprechend auf die Klemmen am Sensor. Der Abschlusswiderstand 120 Ohm ist auch gesetzt.
Kann es sein dass der USB evtl stört? Er liegt ja auf dem gleichen Port.
Ich versuche mal etwas mit der Software Serial Bibliothek zusammen zu basteln.

Gruß Stefan

Hallo zusammen,

ich habe das ganze jetzt mit SoftwareSerial erweitert. Funktionieren tut es immer noch nicht. Daher gehe ich davon aus dass ich das Thema wohl begraben muss :slightly_frowning_face:
Vielleicht ist der Arduino für solche Zwecke einfach nicht geeignet obwohl ich gehört habe dass sich Leute damit schon Zähler ausgelesen haben. Das Protokoll ist ja eigentlich das gleiche.

Im Rhytmus der 2000ms blinkt auf dem UNO immer nur die RX Leuchte, was ja eigentlich nicht richtig ist. Zunächst sollte ja die TX und anschließend bei der Antwort die RX Leuchte aufleuchten.

Was heißt diese uint8_t unter void_loop? Das habe ich aus der Libary übernommen, weiß aber nichts damit anzufangen. Evtl. 8Bit Zahlen? Laut Handbuch liefert der Sensor 16Bit. Vielleicht liegt hier das Problem.

Stimmt die Adressbezeichnung in der Funktion read.Inputregisters? Es beginnt bei Register 0 und soll drei Register auslesen. Reicht es da einfach die 0 reinzuschreiben???

#include <ModbusMaster.h>
#include <SoftwareSerial.h>

#define MAX485_TX_ENABLE  7  // EIA-485 transmit control pin
#define EIA485_RX         9  // EIA-485 serial receive pin
#define EIA485_TX        10  // EIA-485 serial transmit pin

ModbusMaster node;
SoftwareSerial RS485Serial(EIA485_RX, EIA485_TX); // Hier wird der serielle Port beschrieben

void preTransmission() {
  digitalWrite(MAX485_TX_ENABLE, true);// Vor der Übertragung wird Pin 7 auf High gesetzt.
}

void postTransmission() {
  digitalWrite(MAX485_TX_ENABLE, false);// Nach der Übertragung wieder auf Low
}


void setup() {
  pinMode(MAX485_TX_ENABLE, OUTPUT);
  digitalWrite(MAX485_TX_ENABLE, false);

  Serial.begin(19200);
  RS485Serial.begin(19200); //Baudrate des Sensors auf 19200

  node.begin(1, RS485Serial);//Start der seriellen Schnittstelle, Slave ID 1
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);

  Serial.print("Elsner TH-AP Modbus");// Bezeichnung meines Sensors
}


void loop() {
  uint8_t result;
//  uint16_t data[6];

  result = node.readInputRegisters(0, 3);//Funktion : Read Input Registers, Modbus Adressen 0 bis 2
  if (result == node.ku8MBSuccess)
  {
    Serial.print("Reg 0: ");
    Serial.println(node.getResponseBuffer(0));//Temperatur, Datentyp laut Handbuch Signed 16Bit

    Serial.print("Reg 1: ");
    Serial.println(node.getResponseBuffer(1));//Feuchte, Datentyp laut Handbuch Signed 16Bit

    Serial.print("Reg 2: ");
    Serial.println(node.getResponseBuffer(2));//Taupunkt, Datentyp laut Handbuch Signed 16Bit
  }
  else {
  Serial.print("Fehler beim Auslesen des Sensors\n");
  }

  delay(2000);
}

Guten Abend.

Es gibt leider keinen Link, da ich mir alles aus verschiedenen Librarys zusammengebastelt habe.

Auf jeden Fall funktioniert es jetzt und ich freue mich richtig :slight_smile:

Auf dem DIP - Schalter des Sensors musste diese Parität auf “None” gestellt werden. Sie stand auf “Even”
Ich habe den Datenverkehr mit Device Monitoring Studio auf dem Bus mitgelesen und festgestellt dass die Anfrage sauber war, der Slave aber nicht geantwortet hat.

Das ganze hab ich nun auf ein LCD noch rausgegeben.

#include <ModbusMaster.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h> 
LiquidCrystal_I2C lcd(0x27, 20, 4);//Display hat 4 Zeilen mit jeweils 20 Zeichen


#define MAX485_TX_ENABLE  7  // EIA-485 transmit control pin
#define EIA485_RX         9  // EIA-485 serial receive pin
#define EIA485_TX        10  // EIA-485 serial transmit pin

ModbusMaster node;
SoftwareSerial RS485Serial(EIA485_RX, EIA485_TX); // Hier wird der serielle Port beschrieben

void preTransmission() {
  digitalWrite(MAX485_TX_ENABLE, true);// Vor der Übertragung wird Pin 7 auf High gesetzt.
}

void postTransmission() {
  digitalWrite(MAX485_TX_ENABLE, false);// Nach der Übertragung wieder auf Low
}


void setup() {
  lcd.init(); //Starten des LCD 
  lcd.noBacklight();//kein Hintergrundlicht
  
  pinMode(MAX485_TX_ENABLE, OUTPUT);
  digitalWrite(MAX485_TX_ENABLE, false);

  Serial.begin(19200);
  RS485Serial.begin(19200); //Baudrate des Sensors auf 19200

  node.begin(1, RS485Serial);//Start der seriellen Schnittstelle, Slave ID 1
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);

  Serial.print("Elsner TH-AP Modbus");// Bezeichnung meines Sensors
}


void loop() {
  float result;
//  uint16_t data[6];


  result = node.readInputRegisters(0, 3);//Funktion : Read Input Registers, Modbus Adressen 0 bis 2
  if (result == node.ku8MBSuccess)
  {
    
    Serial.print("Temperatur: ");
    Serial.println(node.getResponseBuffer(0)*0.1,1);//Temperatur, Datentyp laut Handbuch Signed 16Bit
    Serial.println(" °C");
    
    Serial.print("Luftfeuchte: ");
    Serial.println(node.getResponseBuffer(1)*0.1,1);//Feuchte, Datentyp laut Handbuch Signed 16Bit
    Serial.println(" %");
    
    Serial.print("Taupunkt: ");
    Serial.println(node.getResponseBuffer(2)*0.1,1);//Taupunkt, Datentyp laut Handbuch Signed 16Bit
    Serial.println(" °C");

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Modbus RS485 Sensor");
    lcd.setCursor(0, 1); 
    lcd.print("Temperatur: ");
    lcd.print(node.getResponseBuffer(0)*0.1,1); // Ausgabe auf eine Nachkommastelle genau.
    lcd.print("\337");
    lcd.print("C");
    lcd.setCursor(0, 2);
    lcd.print("rel.Luftfeuchte: ");
    lcd.print(round(node.getResponseBuffer(1)*0.1),0); // Gerundet auf eine ganze Zahl
    lcd.print("%");
    lcd.setCursor(0, 3);
    lcd.print("Taupunkt: ");
    lcd.print(node.getResponseBuffer(2)*0.1,1); // Ausgabe auf eine Nachkommastelle genau.
    lcd.print("\337");
    lcd.print("C");
  }
  else {
  Serial.print("Fehler beim Auslesen des Sensors\n");
  }

  delay(10000);//Aktualisierung alle 10 Sekunden
}

Die ModbusMaster.h hast Du Dir selbst gebastelt?

Gruß Tommy