Serielle Datenvberbindung

Hi

Ich Baue mir zurzeit ein Kleines Arduino Netzwerk basierend auf einer RS485 Schnittstelle auf.

Im Netzwerk soll es einen Master und mehrere Slaves geben, welche Messdaten Ermitteln und diese an den Master senden sollen, sobald der Master Sie dazu auffordert.
Soweit zur Theorie , da ich allerdings wenig bis gar keine Kenntnisse von Serieller Datenverbindung habe, scheitert es bei mir gerade ein wenig :roll_eyes:

Meine Grundidee war Folgende : Der Slave misst die Daten und Speichert sie in ein Array ab, wenn dann die Aufforderung vom Master kommt soll er das Array Senden, Der Master Wartet dann darauf , liest es ein und Speicher es in Einzelnen Int. Und Genau daran scheitere ich zurzeit das Senden ist keinerlei Problem nur weiß ich nicht genau wie ich die Komplette "Sendung" abfangen soll und dann Separieren soll.

Bin Beim Googlen dann auf mehrere Ähnlich vorhaben gestolpert allerdings keine in denen der Vorhanden Code ein wenig erklärt worden ist.
Da es mir Wichtig ist bei dem Projekt was zu lernen und den Code auch zu verstehen hoffe ich das ich den ein oder anderen hier vielleicht finde der mir ein bisschen unter die Arme greift.

Gruß Yannic ;D

Warum willst Du das Array an den Master senden und dort in einen Integer umwandeln (Mittelwert? ) Das kann doch der Slave selbst machen und das Ergebnis übertragen. Suche mal nach gleitendem Mittelwert.

Ansonsten als Zeile mit Zeilenende ('\n') senden, wenn mehrere Werte, dann mit Trennzeichen (z.B. :wink: trennen.
Bis zum Zeilenende einlesen, mit '\0' abschließen. Wenn mehrere Werte, die über strtok trennen und die Teile / den einzelnen Wert mit atoi oder atof (float) in Zahl umwandeln.

Gruß Tommy

Der Master

  • müsste zunächst mal an Slave A senden "A - schick was"
  • danach sofort wieder auf "Empfangsbereitschaft" gehen

Der Slave A

  • müsste nun was senden sobald er den Befehl am Bus bekommen hat "A - schick was"

Der Master

  • da empfangsbereit jedes Zeichen das nun von Slave A reinkommt zu einem c string zusammenbauen.
  • wenn fertig - den c-string mit strtok zerteilen.

Du sollst auf alle Fälle mal die Serial Input Basics lesen
https://forum.arduino.cc/index.php?topic=396450.0

Fürs Verständnis ist das eine gute Einführung.

Dann überlegst dir ein Protokoll
z.B.

Ein Startzeichen (z.B. 0xFF)
Ein Sender Zeichen (= wer schickt z.B. 'M' für den Master)
Ein Empfänger Zeichen (= wer soll reagieren z.B. 'A' für den Slave A)
deine Payload ( "123;44;33")
Ein Ende Zeichen (z.B. LF oder CR damit du das auch bequem am Serial Monitor testen kanns.

Zeichne dir selber auf was du alles hin und her schicken musst, dann kannst du dein Protokoll von Anfang an gut planen.

Oder verwende Industriestandards - da brauchst aber zum einarbeiten vermutlich noch länger.

Jedenfalls ist das nichts was an einem Nachmittag fertig sein wird.

Hallo
zeige Deinen Sketch, dann können wir Dir besser helfen.
BTW:
RS485 ist nur eine Verpackung in der die Daten versendet werden. Für den Labortisch langen zwei Arduinos mit gekreutzen RX/TX Leitungen.

Vielen Dank schonmal für die ganzen Rückmeldungen

RS485 ist nur eine Verpackung in der die Daten versendet werden. Für den Labortisch langen zwei Arduinos mit gekreutzen RX/TX Leitungen.

ist mir bewusst , habe die Arduinos zurzeit auch so Verbunden, bis das Programm steht

Der Master

  • müsste zunächst mal an Slave A senden "A - schick was"
  • danach sofort wieder auf "Empfangsbereitschaft" gehen

Der Slave A

  • müsste nun was senden sobald er den Befehl am Bus bekommen hat "A - schick was"

Der Master

  • da empfangsbereit jedes Zeichen das nun von Slave A reinkommt zu einem c string zusammenbauen.
  • wenn fertig - den c-string mit strtok zerteilen.

Genau so habe ich mir das in etwa vorgestellt .
Der Sender prüft aktuell ob die vom Master empfangende Datei mit der Internen Adresse übereinstimmt und sendet dann das Array mit den Daten. Das kann ich Soweit auch am Master Über den Seriellen Monitor Auslesen allerdings bekomme ich es wie gesagt nicht gescheit Strukturiert in einzelne INT Geschrieben.

Dann überlegst dir ein Protokoll
z.B.

Ein Startzeichen (z.B. 0xFF)
Ein Sender Zeichen (= wer schickt z.B. 'M' für den Master)
Ein Empfänger Zeichen (= wer soll reagieren z.B. 'A' für den Slave A)
deine Payload ( "123;44;33")
Ein Ende Zeichen (z.B. LF oder CR damit du das auch bequem am Serial Monitor testen kanns.

Bezüglich Protokoll war mein Plan folgendes:

  1. Master Sendet Auf dem BUS Die Adresse 1-256
  2. Der Slave Prüft die Adresse und Sendet Falls sie Übereinstimmt das Zeichen "X" als Bestätigung
  3. Der Master Liest dies und Weis das er auf die Daten warten muss die der Slave direkt Nach dem Bestätigungszeichen Sendet.

Ein "Start", "End" . "für wenn ist die MSG" Zeichen würde Natürlich auch noch Sinn machen oder würde es mit meiner Minimal Ausführung auch schon hinhauen?

Das dass kein Programm bzw. Projekt wird was welches ich an einem Tag machen kann, ist mir völlig bewusst.
Mir ist es bei dem Projekt nur wichtig das ich die Sache recht Professionell löse und am ende des Tages auch verstehe was ich da überhaupt Programmiert habe um das Projekt problemlos erweitern zu können.

Gruß Yannic

der würde es mit meiner Minimal Ausführung auch schon hinhauen?

nein.

wenn das "Startzeichen" nur ein byte ist - dann würde ein Slave jedes zufällig passende Zeichen als sein Startzeichen interpretieren und losquatschen. Du kannst dir nun ausmalen was passieren wird wenn du mal mehrere Slaves am Bus hast.

Da RS485 ein halb-duplex Bus ist, braucht man da für einen sicheren Betrieb schon ein kleines Protokoll. Sonst ist auch bei mehreren Byte 'Identifikation' nicht ausgeschlossen, dass sowas zufällig mal in den Daten vorkommt.
Also z.B. blockweise Übertragung mit eindeutigen Anfangs- und Endekennungen. Oder Identifikation ist 128...255, und Daten sind nur Standard-Ascii, bei denen das Bit7 immer 0 ist.
Irgendwas muss man sich da überlegen und festlegen.

paulpaulson:
BTW:
RS485 ist nur eine Verpackung in der die Daten versendet werden. Für den Labortisch langen zwei Arduinos mit gekreutzen RX/TX Leitungen.

Das ist dann genau das Testszenario, wo man die oben angesprochenen Probleme nicht erkennt. Es ist eben nicht nur eine andere 'Verpackung'. Das Besondere ist der halb-duplex Busbetrieb, und der muss per Protokoll organisiert werden. Wie man das macht, legt die RS485 aber nicht fest.

Hi

Habe mich heute mal hingesetzt und anhand eurer Hilfe einen ersten Empfänger Grund Gerüst geschrieben.

Der Schematische Ablauf ist folgender:
Der Empfänger bekommt ein Startbit "0xFF" Sobald dieses erkannt wird Speichert er alle Empfangen Daten in ein Array. Nach dem das End Bit gekommen ist (0xEE), überprüft das Programm ob die
Empfänger Adresse richtig ist (erstes Gespeicherte Array (0-255). Falls dieses Richtig ist könnte man jetzt die Empfangen Nachricht weiterverwerten.

Nun weiß ich gerade leider nicht so genau wie ich die Array daten wieder in Einzelne INT bekomme um diese Separat zu verwenden.

Hier mal meinen Aktuellen Code

const byte zeichen = 32;


int speicher[zeichen];
boolean SerialCode = false;





void setup() {
  Serial.begin(9600);
  Serial.println("Hochgefahren");
}



void loop() {
  DatenEingang();
  showNewData();
}

void DatenEingang() {
  static boolean speichern = false;
  static byte ndx = 0;
   int Rx;


  while (Serial.available() > 0 && SerialCode == false) {
      Rx = Serial.read();
      if (speichern == true) { Serial.print("Start");


              if (Rx != 0xEE) {                                                 // Endzeichen ereicht 
             speicher[ndx] = Rx;
              ndx++;
              if (ndx >= zeichen) {ndx = zeichen - 1;         }


          }


              else {
              speichern = false;                                                 // Deaktiviert Progreamm
              ndx = 0;
              SerialCode = true;                                                    // öffnet Weiter vorgehensweiße  
          }      }





      else if (Rx == 0xFF) {


          speichern = true;


      }


  }


}

void showNewData() {
  if (SerialCode == true) {
      if(speicher[0] == 0xAA) { 
                    Serial.print("ADresse Koreekt"); 
                    SerialCode = false;
  }
  SerialCode = false;
}}

ist meine Vorgehensweiße bis jetzt so ok oder habe ich schon einen Grundlegende Fehler gemacht?

Gruß

Ändere bitte mal die quote (=Zitat) in code Tags. Bei der Gelegenheit kannst Du auch gleich die unnötigen Leerzeilen entfernen.

Gruß Tommy

Ändere bitte mal die quote (=Zitat) in code Tags. Bei der Gelegenheit kannst Du auch gleich die unnötigen Leerzeilen entfernen.

Mein Fehler sry :confused:

Ich hatte Vorhin vergessen zu erwähnen für welches Protokoll Muster ich mich entschieden habe.

Mein Code Soll Sich Aus Folgendem Zsm. Setzen
Startbyte -> Adressenbyte -> Aufgabenbyte 1 -> Aufgabenbyte 2 -> 5 Datenbytes -> Wertbytes -> Endbyte

Startbyte (0xFF)
Adressenbyte 0x01-0xEE
Aufgabenbytes ( W;R;S) je nachdem ob der Slave Was machen was senden oder ins Setting Menü gehen soll
Beide Aufgabenbytes müssen Identisch sein
Datenbytes: Zum übermitteln von aus /an zuständen oder simplen werten.
Wert Byte Zum übermitteln von Großen zahlen bzw. Werte mit Kommastellen. Soll mit Trennzeichen übermittelt werden und dann wieder Auseinandergezogen werden.
Endbyte (0xEE);

An sich habe ich die Grund Funktionen schon implementiert, nur Scheitere ich schon die Ganze zeit dran aus dem Empfangsarray Buffer die Werte wieder zu trennen.
Ist das überhaupt möglich oder ist meine Vorgehensweiße schonmal komplett falsch?

Gruß

Schau Dir strtok an.

Gruß Tommy

Gib noch ein Mustertelegramm in hex an inkl was du gern herausgelesen hättest dann schau ich in der Nacht mal drüber.

Was genau meinst du mit Mustertelegramm.

Gesendet werden daten wie Temperatur / Luffteuchte / Co2 Werte etc.
Typische Float werte.

Womit trennst Du die Werte?

Gruß Tommy

Aktuell mit einem '/' macht für mich irgendwie am meisten Sinn

Dann wäre es gut, wenn Du vor dem Endebyte ein 0-Byte einfügen würdest oder bei Erkennung des Endebytes eine 0 ins Array am Ende einträgst. Dann kannst Du das mit strtok problemlos zerlegen und mit atof wieder in Fließkommawerte umsetzen. Hier mal ein paar Infos dazu.

Gruß Tommy

yandor:
Was genau meinst du mit Mustertelegramm.

Gesendet werden daten wie Temperatur / Luffteuchte / Co2 Werte etc.
Typische Float werte.

du schreibst oben

Startbyte (0xFF)
Adressenbyte 0x01-0xEE
Aufgabenbytes ( W;R;S) je nachdem ob der Slave Was machen was senden oder ins Setting Menü gehen soll
Beide Aufgabenbytes müssen Identisch sein
Datenbytes: Zum übermitteln von aus /an zuständen oder simplen werten.
Wert Byte Zum übermitteln von Großen zahlen bzw. Werte mit Kommastellen. Soll mit Trennzeichen übermittelt werden und dann wieder Auseinandergezogen werden.
Endbyte (0xEE);

und jetzt hätt ich gern von dir eben eine klare Spezifikation und reichlich Beispiele die zu dieser Spezifikation passen

nur zum Beispiel:

FF 01 77 AA 00 00 00 00 EE
FF                            Startbyte
   01                         Addresse
      77                      w für write???, r für read?, s für schmeck's?
         AA                   Datenbyte heißt was? Ist das ein Identifer/Tag für den nachfolgenden Wert?
             00 00 00 00      ein int32, oder ein float, irgend ein 4byte typ halt, oder willst das abhängig vom Datenbyte?
                         EE   das Endbyte

Ich Saß gestern Abend noch recht lang am Programm und habe mir gedanken gemacht nun bin ich auf folgendes Resultat gestoßen .

FF 01 77 00 00 00 00 00 EE
FF                            Startbyte
   01                         Addresse 01-FF ( Abzüglich FF,EE,DD
      54                      G / T / S / D / Z  G/T/S bedeutet immer das eine Naricht von Master für Slave kommt 
                              G = Give Slave weis er muss was ausführen; 
                              T = take Slave Weiß er muss was Senden  
                              S-Setting Slave geht in einen Einsetllungsmodus 
                              D und Z bedeutet das eine NAricht vom Slave zum Master geht
                              d = Data Kündigt dem Master an das gleich daten kommen 
                              z = Dient einfach nur als Rückmeldung famit der Master weiß das der Slave alles Richtig gemacht hat 

           00 00 00 00 00      Beim Protokoll sollen immer 5 Bytes mitgeschickt werden welche Simple Zustände Übertragen 
                              EE   das Endbyte

                              Falls nun aber auch Werte wie Floats gesendet werden müssen ( Im falle eines Slave Sensors zbs)
                              Wird anstelle des Endytes ein DD Byte gesendet welches Die String abfragen einschaltet.

Ich habe das dann gestern versucht mal das ganze als code niederzuschreiben :

void DatenEingang() {
    static boolean SaveModus = false;
    static byte ndx = 0;
     int Rx;
    
    while (Serial.available() > 0 && SerialCode == false) {
        Rx = Serial.read();
              
              if (SaveModus == true) { 
                         
                if (Rx != 0xEE) {                                                 // wenn Endzeichen nicht ereicht 
               BufferEingang[ndx] = Rx;
                ndx++;
                if (ndx >= BufferSize) {ndx = BufferSize - 1; }
                if (BufferEingang[ndx] == 0xDD) {SaveModus = false; SerialCode = true; Serial.println("Stringbereit"); StringEmpfang();ndx = 0;}       
                }
                 else {
                Serial.println("ende");                                             // Debug
                SaveModus = false;                                                 // Deaktiviert Progreamm
                ndx = 0;
               SerialCode1 = true;       } 
                
            }
        else if (Rx == 0xFF) {                                                      // Start Code Bekommen
            SaveModus = true;                                                         
            Serial.println("Start"); }                                              // Debug
       }}
void StringEmpfang(){
  
String Werte = Serial.readStringUntil('/');         //Falsch Wert 
String Werte1 = Serial.readStringUntil('/');        
String Werte2 = Serial.readStringUntil('/');
String Werte3 = Serial.readStringUntil('/');
String Werte4 = Serial.readStringUntil('/');
String Werte5 = Serial.readStringUntil('/');
Values1 = Werte1.toFloat();
Values2 = Werte2.toFloat();
Values3 = Werte3.toFloat();
Values4 = Werte4.toFloat();
Values5 = Werte5.toFloat();
Serial.println(Values1);                  // Debug
Serial.println(Values2);                  // Debug
Serial.println(Values3);                  // Debug
Serial.println(Values4);                  // Debug
Serial.println(Values5);                  // Debug    
  
Serial.println("Fertig");                 // Debug
 SerialCode = false;
 SerialCode1 = true;
}
void EingansSplitter() {
    if (SerialCode1 == true) {
        
        if(BufferEingang[0] == Adresse) { 
                      Serial.println("ADresse Koreekt"); 
                       SerialCode = false;
    }                 
   if (BufferEingang[1] == 'T' && BufferEingang[2] == 'T') {Serial.print("Take mode: ");take(); }
   if (BufferEingang[1] == 'G' && BufferEingang[2] == 'G') {Serial.print("give mode: ");senden();}
   if (BufferEingang[1] == 'S' && BufferEingang[2] == 'S') {Serial.print("Settingmode: ");setting();}
    
    SerialCode = false;
    SerialCode1 = false;
}}

Wo sind jetzt Deine zu trennenden Floatwerte abgeblieben?

Gruß Tommy

Also der Aktuelle Sendercode sieht zur Test Phase noch so aus :

void setup() {
 serial.begin(9600);  

}

void loop() {

  Serial.write(0xFF);       // Start 
  Serial.write(0x1D);       //Adresse
  Serial.write('D');       //Überprüfungsbyte
  Serial.write(0);            
  Serial.write(0);
  Serial.write(1);              
  Serial.write(1);
  Serial.write(1);
  Serial.write(0xDD);     // Startbyter für flaot werte
  Serial.write(23,545);
  Serial.write('/');
  Serial.write(1,231);
  Serial.write('/')
  Serial.write(123,123);
  Serial.write('/')

  
  Serial.write(0xEE);   //Endbyte  
}

Das wäre jetzt ein Beispiel für eIn Slave der Sendet