Forum: Digitale Signalverarbeitung / DSP / Machine Learning RS232 ASCII Signal zu Modbus RTU RS485 umwandeln


von Markus (markus_schi)



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

von S. M. (lichtmensch)


Lesenswert?

Als fertiges gerät hab ich so was noch nie gesehen. Es müsste ja auch 
die Spezielle Kommunikation der Waage kennen.

Mit Arduino sollte das in wenigen Minuten umgesetzt sein.

von Markus (markus_schi)


Lesenswert?

Hallo Lichtmensch

Danke für die Antwort, da ich von Arduino kein Ahnung habe frag ich mal 
einfach ob Sie mir die Bauteile die ich benötigen würde nennen können, 
welches Board und welche Bauteile für die RS-232 und RS-485 
Schnittstelle.

M.f.G. Markus

von Εrnst B. (ernst)


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...

von Rüdiger B. (rbruns)


Lesenswert?

Achte drauf das die Werte konsistent sind, also einen 2 Werte Ringpuffer 
verwenden z.B.
Sonst wind aus zwei aufeinanderfolgenden Werten 4,99und 5,01 plötzlich 
5,99.

von Markus (markus_schi)


Angehängte Dateien:

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();

}

von Εrnst B. (ernst)


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?

: Bearbeitet durch User
von Markus (markus_schi)


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

von Εrnst B. (ernst)


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.

: 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
Noch kein Account? Hier anmelden.