RS232 ASCII Signal zu Modbus RTU RS485 umwandeln

#7752042
Lesenswert?

Guten Tag !

Ich müsste das Gewicht einer Waage welches über eine RS-232 Schnittstelle im Sekundentakt per ASCII 5 Datenbyte und 1 Stopbyte, Screenshot vom Signal mit Hterm ist im Anhang, ausgegeben wird mittels Gateway, Konverter oder ähnliches in ein RS-485 Modbus RTU Slave umwandel das ich es mit dem vorhandenen Modbus RTU Master abfragen kann. Kennt jemand so ein Gateway bzw. Konverter der das ankommende Signal verwerten kann und es als Modbus RTU Slave zur Verfünung stellen Kann ?

Danke im Voraus

#7790215
Lesenswert?

https://github.com/CMB27/ModbusRTUSlave/tree/main/examples/ModbusRTUSlaveExample

Zeigt einen beispielhaften Hardware-Aufbau.

Dazu brauchst du noch einen RS232->TTL Wandler.

Im Beispiel-Source schmeißt du die Taster- und Analgoeingänge raus, und auch die Ausgänge brauchst du nicht, sondern nur ein Register was dein Master auslesen kann.

In der loop dann an der RS232 lauschen, und neue Werte in dein register speichern. Bei 9600 baud tut's auch Soft-Serial, damit eignet sich so gut wie jedes Platinchen, was sich "Arduino-Kompatibel" schimpft..

Nur aufpassen, dass die loop nicht zulange blockiert wird, also zeichenweise lesen, damit modbus.poll(); nicht verhungert...

#7790902
Lesenswert?

Danke für die Antworten. Ich habe einen Mega 2560 verwendet mit einem RS232 und einem RS485 Adapter.

https://www.amazon.de/dp/B07B667STP?ref=ppx_yo2ov_dt_b_fed_asin_title

https://www.amazon.de/dp/B09DYDFZRW?ref=ppx_yo2ov_dt_b_fed_asin_title

Die 2 Adapter habe ich auf Serial1 und Serial2 angeklemmt. Dann habe ich aus einer Modbus RTU Slave Vorlage einen Sketch mehr oder weniger zusammen gebastelt, der nun auch funktioniert, das blöde ist nur das nach ein paar Tagen die Verbindung mit dem Modbus RS485 RTU abbricht. Momentane Lösung ist, ich Kontrolliere mit der UVR610 den Modbus Eingang wenn der als defekt angezeigt wird, wird die Spannungsversorgung vom Mega 2560 kurz getrennt und dann läuft wieder alles normal. Ich gehe davon aus das der Sketch starken Optimierungsbedarf hat. Vielleicht kann mir jemand weiterhelfen.

#include <ModbusRTUSlave.h> #define MODBUS_SERIAL Serial1 #define MODBUS_BAUD 9600 #define MODBUS_CONFIG SERIAL_8N1 #define MODBUS_UNIT_ID 100

#if (defined(ARDUINO_NANO_RP2040_CONNECT) && !defined(ARDUINO_ARCH_MBED)) || defined(ARDUINO_NANO_ESP32) // These boards operate unsing GPIO numbers that don't correspond to the numbers on the boards. // However they do have D# values #defined to correct this. const int8_t buttonPins[2] = {D2, D3}; const int8_t ledPins[4] = {D5, D6, D7, D8}; const int8_t dePin = D13; #else // Other boards do not have D# values, and will throw an error if you try to use them. const int8_t buttonPins[2] = {2, 3}; const int8_t ledPins[4] = {5, 6, 7, 8}; const int8_t dePin = 13; #endif const int8_t knobPins[2] = {A0, A1};

ModbusRTUSlave modbus(Serial1);

const uint8_t numInputRegisters = 2;

uint16_t inputRegisters[2];

float wert; String scaleOutput;

void setup() { Serial2.begin(9600); pinMode(knobPins[0], INPUT); pinMode(knobPins[1], INPUT); pinMode(buttonPins[0], INPUT_PULLUP); pinMode(buttonPins[1], INPUT_PULLUP);

modbus.configureInputRegisters(inputRegisters, numInputRegisters);

MODBUS_SERIAL.begin(9600, SERIAL_8N1); modbus.begin(MODBUS_UNIT_ID, MODBUS_BAUD, MODBUS_CONFIG); }

void loop() { if (Serial2.available()) scaleOutput = Serial2.readStringUntil(B00001101); wert = scaleOutput.substring(1,5).toFloat();

inputRegisters[0] = (wert); inputRegisters[1] = (12345);

modbus.poll();

}

Angehängte Dateien:
#7790976
Lesenswert?

Markus schrieb:

Dann habe ich aus einer Modbus RTU Slave Vorlage einen Sketch mehr oder weniger zusammen gebastelt, der nun auch funktioniert, das blöde ist nur das nach ein paar Tagen die Verbindung mit dem Modbus RS485 RTU abbricht.

Problem, vermute ich:

Serial2.readStringUntil(B00001101);

Blockiert den Program-Ablauf, bis das Zeichen kommt. Das dauert bei 9600 Baud schon lange, noch viel länger wenn durch eine Störung auf der RS232 das Zeichen garnicht kommt.

Das ist, was ich hier meinte:

Εrnst B. schrieb:

Nur aufpassen, dass die loop nicht zulange blockiert wird, also zeichenweise lesen, damit modbus.poll(); nicht verhungert...

also in etwa:

1
String buffer;
2
void loop() {
3
  if (Serial2.available()) {
4
     int zeichen=Serial2.read();
5
     if (zeichen=='\r') {
6
         wert =  buffer.trim().toFloat();
7
         buffer = String();
8
         if (wert ist plausibel) 
9
            inputRegisters[0]=wert;
10
     } else {
11
         buffer += (char)zeichen;
12
     }
13
   }
14
   modbus.poll();
15
}

ggfs. timeout&Abbruch einbauen (wenn zulange kein weiteres Zeichen kommt, während schon eins im Buffer steht, oder buffer > 5 Zeichen hat, buffer wieder leeren)

PS: warum "toFloat"? Sind da Nachkomma-Stellen?

#7791026
Lesenswert?

Hallo Ernst danke für die Antwort

Das mit dem

Serial2.readStringUntil(B00001101);

habe ich eingebaut, weil die Waage den Wert ca. alle 200ms schickt und ich ohne das "Until(B00001101)" falsche Werte bekommen habe. Ohne hat es nur bis zu einem Intervall von ca. 500ms funktioniert.

Float brauch ich eigentlich nicht, es wird kein Komma Zeichen gesendet, ich habe das in einem anderen Waagen Sketch gelesen und eingebaut und da es funktioniert hat nicht mehr geändert. Es kann nur sein das die Waage ein Minus Vorzeichen sendet, also z.B. Leerzeichen, Leerzeichen, Leerzeichen, Minus, Zwei, und das Stopzeichen "00001101"

Ich werde mal einen Zweiten Aufbau machen und es mit deiner Änderung versuchen .

Aber jetzt habe ich noch eine Frage wie wird bei deinem Sketch das Stopzeichen ausgewertet, wird das mit if (zeichen=='\r') erledigt ?

Danke im Voraus

#7791043
Lesenswert?

Markus schrieb:

Aber jetzt habe ich noch eine Frage wie wird bei deinem Sketch das Stopzeichen ausgewertet, wird das mit if (zeichen=='\r')

ja, 0b00001101 ist 0x0D ist 13 ist der "Wagenrücklauf" '\r'.

Kannst du auf alle 4 Arten reinschreiben, ich persönlich finde '\r' übersichtlicher. Da erkenne ich gleich, dass das ein Zeilenende sein soll...

Markus schrieb:

Leerzeichen, Leerzeichen, Leerzeichen, Minus, Zwei,

dafür hab ich das "buffer.trim()" drinnen. Das entfernt Leerzeichen am Anfang und Ende von einem String.

Hab den Code aber "blind" getippt, da sind noch Fehler drinnen. z.B. kann es gut sein dass du statt

buffer.trim().toInt(); Zwei Zeilen, buffer.trim(); wert=buffer.toInt();

bauchst.

Und es kann sein, dass "String.toInt()" bei Arduino keine negativen Zahlen kennt... Insofern ist der weg über toFloat vielleicht einfacher. Für ungenutzten Flash-Speicher & Rechenzeit gibt's ja kein Geld zurück.

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