Go Down

Topic: Serielles Telegramm lesen und verarbeiten (Read 298 times) previous topic - next topic

fylw

Hallo zusammen,

ich habe hier ein altes Messgerät das mir Messwerte als ein serielles Telegramm sendet (9600 bps) die ich weiter verarbeiten möchte. (Sollen auf einem Display angezeigt und alle 30 sek in eine SQL DB gespeichert werden)

Display und SQL DB sind kein Thema, das habe ich bereits hinbekommen. Allerdings nur festen Werten  ;D

Das Telegramm ist immer gleich lang (740 Byte) und wird jede Sekunde gesendet.
Es beginnt mit einem Header "01 01 01 01 3F 3F 3F 3F" und dann kommen die Nutzdaten - relevant sind für mich 4 Werte die ich mir, nachdem ich das volle Telegramm in einem Array hab einfach raushol und verarbeite. (Die stellen habe ich bereits)

Mein Problem ist momentan:
Wie erkenne ich den Header und fange erst dann an das Telegramm in ein Array zu speichern?
Mir fehlt da irgendwie der Ansatz  :-X

Danke.



wno158

Ein ähnliches Problem hatten wir im Mai hier schon mal.

Musst halt die gelesenen Bytes testen, ggf. ignorieren oder aber mitzählen.
Typischer Fall von einem Apparat Programm mit mindestens drei Zuständen (0x01 lesen, 0x3F lesen, Nutzbytes lesen).

StefanL38

740byte ist noch eine handhabbare Größe. Gibt es ein bestimmtes Zeichen mit dem das "Telegramm" abschließt?
Das würde sich gut zur Erkennung "Telegramm fertig" eignen.
Die andere Variante ist ein Timeout. Wenn die 740 byte wirklich immer ohne Zwischenpausen hereingesaust kommen
dann könnte man auch einen Timeout verwenden. 740 Byte bei 9600 Baut benötigt ca 78 millisekunden. Wenn das Telegramm nur einmal pro Sekunde kommt. Müsste man mit einem Timeout von 200 bis 500 Millisekunden gut himkommen.
Die Zeichen werden einfach in einem Array of char eingelesen.
Vielleicht eignet sich dafür auch PString. Das ist eine Library die etwas mehr Komfort bietet wie array of char aber keinen Speicherüberlauf produzieren kann wie bei global definierten Strings ( Der Datentyp mit dem großgeschreibenen "S".

Wenn die Werte in jedem Telegramm an absolut feststehende Positionen stehen kann man dann einfach die einzelnen Zeciehn von zum Beispiel Array-Element 17 bis Array-Element 29 in eine andere PString-Variable kopieren (durch fortlaufendes Anhängen des nächsten bytes und dann diese Variablen weiterverarbeiten

viele Grüße Stefan

agmue

string.h bietet Vergleiche beispielsweise mit strncmp.

Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

noiasca

Quote
ein altes Messgerät
Bitte schreibe genau Marke und Typ dazu damit der nächste der danach sucht, das Ergebnis hier auch findet!

Wie endet deine Serielle Nachricht? CR, LF. Endsequenz?
Stell uns hier eine komplette Musternachricht ein - die kompletten 740 Byte!

Ein ähnliches Problem hatten wir im Mai hier schon mal.
ja, im Prinzip könntest du den Sketch von Post 18 anpassen. Bei dir sinds einfach zwei Eingangs-Kontroll If die jeweils die Stellen 0-3 bzw. 4-7 auf 01 und 3F prüfen,



how to react on postings:
- post helped: provide your final sketch, say thank you & give karma.
- post not understood: Ask as long as you understand the post
- post is off topic (or you think it is): Stay to your topic. Ask again.
- else: Ask again.

fylw

#5
Jul 06, 2020, 08:38 am Last Edit: Jul 06, 2020, 08:55 am by fylw
Danke für die Infos erstmal. Werde ich mir anschauen und wenn ich nicht weiterkomme oder die Lösung hab schreib ichs hier rein :-)

Volles Telegramm kann ich heute Abend posten.

@StefanL38
Das Telegramm endet mit 3F 3F 3F 3F FF FF

@noiasca
Gibt leider weder Marke noch Typ. Es ist ein selbst gebautes Messgerät um Düsenverwirbelungen zu testen.

agmue

#6
Jul 06, 2020, 01:03 pm Last Edit: Jul 06, 2020, 01:04 pm by agmue
ja, im Prinzip könntest du den Sketch von Post 18 anpassen.
Das Telegramm endet mit 3F 3F 3F 3F FF FF
Darauf basierend mal ein Vorschlag:

Code: [Select]
const uint16_t erw = 740; // Anzahl erwartete Zeichen
const uint16_t numChars = 750;
byte receivedChars[numChars];

boolean newData = false;

void setup() {
  Serial.begin(115200);
  Serial.println("\n<Arduino is ready>");
  Serial1.begin(9600);
}

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

void recvWithStartEndMarkers() {
  static uint16_t ndx = 0;
  byte rc;

  while (Serial1.available() > 0 && newData == false) {
    rc = Serial1.read();
    Serial.print(ndx); Serial.print('\t'); Serial.println(rc, HEX);
    receivedChars[ndx] = rc;
    if (ndx > 5 && receivedChars[ndx - 5] == 0x3F && receivedChars[ndx - 4] == 0x3F && receivedChars[ndx - 3] == 0x3F && receivedChars[ndx - 2] == 0x3F && receivedChars[ndx - 1] == 0xFF && receivedChars[ndx] == 0xFF) {
      if (ndx == (erw-1) && receivedChars[ndx - erw+1] == 0x01 && receivedChars[ndx - erw+2] == 0x01 && receivedChars[ndx - erw+3] == 0x01 && receivedChars[ndx - erw+4] == 0x01 && receivedChars[ndx - erw+5] == 0x3F && receivedChars[ndx - erw+6] == 0x3F && receivedChars[ndx - erw+7] == 0x3F && receivedChars[ndx - erw+8] == 0x3F ) {
        newData = true;
      }
      ndx = 0;
    } else {
      ndx = (1 + ndx) % numChars;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("\nDaten zur Auswertung: ");
    for (uint16_t i = 0; i < erw; i++)
    {
      if (receivedChars[i] < 0x10) Serial.print("0");
      Serial.print (receivedChars[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
    newData = false;
  }
}
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

noiasca

#7
Jul 06, 2020, 05:35 pm Last Edit: Jul 06, 2020, 08:34 pm by noiasca
DU hättest aber den ersten If vereinfachen können oder ;-)


edit (ich machs neu)
how to react on postings:
- post helped: provide your final sketch, say thank you & give karma.
- post not understood: Ask as long as you understand the post
- post is off topic (or you think it is): Stay to your topic. Ask again.
- else: Ask again.

agmue

DU hättest aber den ersten If vereinfachen können oder ;-)
Wenn Du mich meinst: Ich sehe verschiedene Verbesserungsmöglichkeiten, andererseits auch die Gefahr, mit Zeigern und dergleichen zu verwirren. Also gebe ich eine Anregung und bin dann gespannt, wie diese aufgenommen wird. Wenn der anschließende Dialog aus bleibt, ist das dann halt so.

Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

fylw

Ihr seid der Hammer  :D

Hab mich leider vertan, das Telegramm endet nicht mit 3F3F3F3FFFFF sondern mit 2 Werten die sich ständig ändern.

Ich hab ein Telegramm jetzt aufgezeichnet.:

Code: [Select]

010101013F3F3F3F = Header
44554553454E544553545354415254 = DUESENTESTSTART ASCII
FFFFFFFF = Keinen Plan, ändert sich nie
0101003B0201003B0301003B0102003B0202003B0302003B0103003B0203003B0303003B0104003B0204003B0304003B0105003B0205003B0305003B0106003B0206003B0306003B0107003B0207003B0307003B0108003B0208003B0308003B0109003B0209003B0309003B010A003B020A003B030A003B010B003B020B003B030B003B010C003B020C003B030C003B010D003B020D003B030D003B010E003B020E003B030E003B010F003B020F003B030F003B0110003B0210003B0310003B0111003B0211003B0311003B0112003B0212003B0312003B0113003B0213003B0313003B0114003B0214003B0314003B0115003B0215003B0315003B0116003B0216003B0316003B0117003B0217003B0317003B0118003B0218003B0318003B0119003B0219003B0319003B011A003B021A003B031A003B011B003B021B003B031B003B011C003B021C003B031C003B011D003B021D003B031D003B011E003B021E003B031E003B011F003B021F003B031F003B0120003B0220003B0320003B0121003B0221003B0321003B0122003B0222003B0322003B0123003B0223003B0324003B0124003B0224003B0324003B0125003B0225003B0325003B0126003B0226003B0326003B0127003B0227003B0327003B0128003B0228003B0328003B0129003B0229003B0329003B012A003B022A003B032A003B012B003B022B003B032B003B012C003B022C003B032C003B012D003B022D003B032D003B012E003B022E003B032E003B012F003B022F003B032F003B0130003B0230003B0330003B0131003B0231003B0331003B0132003B0232003B0332003B = Nutzdaten (Sind jeweils 4 Byte, 0 = Ring (1,2,3) 1=Loch (1-50) 2 = Durchfluss 0/1 3=Trennzeichen

518AC0F12B28028114F070968F34F5C51C6CF34F095D89F614FB9DF88839CDBEA9C6C3A657976F24E6A6B421614A4511632017FF4B2EE8257832411C381722FA4CB2BDC7FD72F68FEF784316E1F163DB503262DC7FE3AB77DED6FD31D1D9CEA6DFD336BD8CB4052925 = Immer gleich lang und ändern sich mit jedem Übertrag aber keine Ahnung was da drin steht, da aber oben alle Relevanten Daten drin stehen ists mir egal.

3F3F3F3FFFFF = Endsequenz, immer gleich.
A1FD = Bei jeder Übertragung unterschiedlich, könnte eine Prüfsumme sein


Melde mich später nochmal... :)

noiasca

#10
Jul 06, 2020, 08:33 pm Last Edit: Jul 06, 2020, 08:42 pm by noiasca
Das war jetzt ein K(r)ampf.
Code: [Select]

/*
    Serial Receive 740 byte telegram
   
     0  1  2  3  4  5  6  7
    01 01 01 01 3F 3F 3F 3F     8 Startbytes fix
    Nutzdaten                   740-8-6= 736 Bytes

     -6  -5  -4  -3  -2  -1
    734 735 736 737 738 739
    3F   3F  3F  3F  FF  FF     6 Endbytes fix
    740 bytes ingesamt fix

    by noiasca
    https://forum.arduino.cc/index.php?topic=694031.0

    basierend auf: https://forum.arduino.cc/index.php?topic=682436
*/

const uint16_t numChars = 740;
byte receivedChars[numChars + 1];

boolean newData = false;

void setup() {
  Serial.begin(9600);
  Serial.println(F("<Arduino is ready>"));
}

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

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static uint16_t ndx = 0;                    // index
  byte rc;                                    // received character

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    if (recvInProgress == false)
    {
      //Serial.println(F("\nD041: reset buffer"));
      memset(receivedChars, 0, numChars);
      ndx = 0;
      recvInProgress = true;
      receivedChars[ndx] = rc;
      Serial.println();
    }
    else if (recvInProgress)
    {
      //Serial.println(F("\nD050: ok"));
      ndx++;
      receivedChars[ndx] = rc;
    }
    //Serial.print(ndx); Serial.print(" "); Serial.println(rc, HEX); // debug output received ndx and character

    // Prüfungen
    // Start 01
    if (recvInProgress && ndx <= 3 && rc != 0x01)
    {
      Serial.print(ndx); Serial.println(F(" reset: start not 0x01"));
      ndx = 0;
      recvInProgress = false;
    }
    // Start 3F
    if (recvInProgress && (ndx >= 4 && ndx <= 7) && rc != 0x3F)
    {
      Serial.print(ndx); Serial.println(F(" reset: start not 0x3F"));
      ndx = 0;
      recvInProgress = false;
    }
    // Ende
    if (recvInProgress && (ndx >= numChars - 6 && ndx <= numChars - 3) && rc != 0x3F)  // 734 - 737
    {
      Serial.print(ndx); Serial.println(F(" reset: end not 0x3F"));
      ndx = 0;
      recvInProgress = false;
    }
    if (recvInProgress && (ndx >= numChars - 2 && ndx <= numChars - 1) && rc != 0xFF)  // 738 - 739
    {
      Serial.print(ndx); Serial.println(F(" reset: end not 0xFF"));
      ndx = 0;
      recvInProgress = false;
    }
    // CR and LF will stop receiver with an error
    if (recvInProgress && (rc == 0x10 || rc == 0x13))
    {
      Serial.println(F("reset CR / LF "));
      ndx = 0;
      recvInProgress = false;
    }

    if (ndx >= numChars - 1)   // 739
    {
      Serial.println(F("\n char limit reached without error"));
      ndx = 0;
      newData = true;          // we have received enough new data
      recvInProgress = false;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print(F("\nThis just in:"));
    for (uint16_t i = 0; i < numChars; i++)
    {
      if (receivedChars[i] < 0x10) Serial.print("0");
      Serial.print (receivedChars[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
    newData = false;
  }
}



im Musterfile ist eine 740byte Nachricht mit den startbytes/endbytes so wie du es ursprünglich definiert hast.

Imho funktioniert es.
Schön ist es nicht.

Da jetzt deine Anforderung anders geworden ist, musst das halt selber umändern.
Hab jetzt keinen Bock mehr.

ps
Quote
Ich hab ein Telegramm jetzt aufgezeichnet
stell das als file zur Verfügung, weil dein zerissenes Beispiel will keiner Zusammenkopieren und konvertieren müssen...
how to react on postings:
- post helped: provide your final sketch, say thank you & give karma.
- post not understood: Ask as long as you understand the post
- post is off topic (or you think it is): Stay to your topic. Ask again.
- else: Ask again.

agmue

Das war jetzt ein K(r)ampf.
...
Hab jetzt keinen Bock mehr.
Da hilft süßer Schlaf :smiley-sleep:

Gute Nacht!

Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Go Up