Serieller Datenempfang mit Startbyte STX (02h) und Endbyte ETX (03h)

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von prinzip.

    Serieller Datenempfang mit Startbyte STX (02h) und Endbyte ETX (03h)

    Hallo,

    ich lese mit meiner Anwendung permanent Daten und kenne die Zusammensetzung der Informationen welche wie folgt aussieht.
    ​<STX>D19:54<SP><SP>1<SP><SP>022011210<SP><SP><SP><SP><ETX><CRC>
    Die <SP> sind Leerzeichen und enthalten ggf. auch Daten.

    Empfangen wird lesbar folgendes
    ​ uD 4:46
    oder
    ​ÑD 4:46 1 2 00


    Da ich nur per SerialPort1.ReadExisting Daten empfange und diese in ungleichmäßigen Blöcken bis etwa 15 Zeichen liest, prüfe ich den Datenstream bei jedem Empfangsblock auf das Zeichen 'D' im String und schneide davor alles ab.

    VB.NET-Quellcode

    1. If received.Contains("D") Then
    2. Dim SearchWithinThis As String = received
    3. Dim SearchForThis As String = "D"
    4. Dim FirstCharacter As Integer = SearchWithinThis.IndexOf(SearchForThis)
    5. If FirstCharacter > 0 Then
    6. received = received.Remove(0, FirstCharacter) ' erste stellen bis zum D abschneiden
    7. ReceivedOld = received
    8. DatenTyp = "D"
    9. End If
    10. Else
    11. If DatenTyp = "D" AndAlso ReceivedOld <> "" Then
    12. received = ReceivedOld & received
    13. ReceivedOld = ""
    14. DatenTyp = ""
    15. Else
    16. DatenTyp = ""
    17. received = ""
    18. End If
    19. End If


    So kann ich mit Trim(Mid(received, 2, 2)) u.a. die Stunden und mit Trim(Mid(received, 5, 2)) die Sekunden an ihrer festen Position als String erfassen. Grunsätzlich funktioniert es so erstmal Das ganze ist aber alles andere als optimal und Informationen im hinteren Teil können nur durch weitere umständliche Verarbeitungsmethoden erfasst werden.

    Gibt es eine Möglichkeit den Stream sozusagen fliegend zu erfassen und die Informationen an den festen Positionen zu verarbeiten?
    Am Ende wird zudem die Checksumme <CRC> (xxh) übertragen. Da die Daten aber etwa alle 100 ms neu übertragen werden, ist die Prüfung Checksumme aber nicht so wichtig.

    TIA
    Definiere Stream.

    prinzip schrieb:

    den Stream ... fliegend ... erfassen
    Zunächst könntest Du natürlich VB.NET-Code schreiben und mit .IndexOf() und .SubString() arbeiten.
    Eine Alternative wäre, das ganze per RegEx zu machen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Oder den Stream zeichenweise auslesen und bei STX einen neuen Record anlegen, den du bei ETX abschliesst und dann verarbeitest.
    Beim Empfang über eine serielle Schnittstelle könnte es auch vorkommen, dass der Puffer inmitten eines Records aufhört und der Rest im nächsten Puffer steht.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    RodFromGermany schrieb:

    Zunächst könntest Du natürlich VB.NET-Code schreiben


    Das wurde schon an anderer Stelle richtig angemahnt. :|
    Es kann so einfach sein mit .IndexOf() und .SubString(). :)

    petaod schrieb:

    Oder den Stream zeichenweise auslesen und bei STX einen neuen Record anlegen

    Statt Zeichenweise überlege ich gerade, ob ich jeweils ab dem <STX>D die Daten mit fullreceived &= received sammle, bis im neuen Block <ETX> steht, dann weiter auswerte und verarbeite und abschließen fullreceived für den nächsten Datenblock mit <STX>D leere.

    petaod schrieb:

    Beim Empfang über eine serielle Schnittstelle könnte es auch vorkommen, dass der Puffer inmitten eines Records aufhört und der Rest im nächsten Puffer steht.

    Die einzelnen Puffer enthalten nie einen vollständigen Datensatz vom <STX> bis zum <ETX>. Der relevante Teil ist etwa 28 Byte groß und ca. 15 sind jeweils im Puffer. Erst mit dem zweiten oder dritten Pufferblock wird der Datensatz vervollständigt.

    Mir ist noch nicht ganz klar, wie ich nach dem Start- und Stopbyte suchen kann. Gefunden habe ich dazu string.char(0x02) als STX und string.char(0x03) als ETX und werde es mal probieren. Leider steht mir die Hardware zum Test nicht täglich zur Verfügung. :(

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „prinzip“ ()

    Vielen Dank noch mal für die Hilfe. :thumbup:

    Ich konnte es jetzt wie folgt umsetzen:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. If received.Contains(System.Convert.ToChar(2) & "D") AndAlso StringKomplett Then
    2. Dim FirstCharacter As Integer = received.IndexOf(System.Convert.ToChar(2) & "D")
    3. StringKomplettText &= received.Substring(FirstCharacter + 2)
    4. StringKomplett = False
    5. ElseIf Not StringKomplett Then
    6. StringKomplettText &= received
    7. If received.Contains(System.Convert.ToChar(3)) Then
    8. 'TextBox1.Text &= vbCrLf & StringKomplettText ' Zur Kontrolle
    9. StringKomplett = True
    10. MM = StringKomplettText.Substring(0, 2).Trim()
    11. SS = StringKomplettText.Substring(3, 2).Trim()
    12. TorHeim = StringKomplettText.Substring(5, 3).Trim()
    13. TorGast = StringKomplettText.Substring(8, 3).Trim()
    14. TimerRun = StringKomplettText.Substring(17, 1).Trim()
    15. Period = StringKomplettText.Substring(15, 1).Trim()
    16. Windows_Form.Label1Minuten.Text = MM
    17. Windows_Form.Label2Sekunden.Text = SS
    18. If TimerRun = "0" Then 'Zeit angehalten oder abgelaufen
    19. Windows_Form.Label3TimerRun.Visible = True
    20. Windows_Form.Label4TimerRun.Visible = True
    21. ElseIf TimerRun = "1" Then 'Zeit läuft
    22. Windows_Form.Label3TimerRun.Visible = False
    23. Windows_Form.Label4TimerRun.Visible = False
    24. End If
    25. Windows_Form.Label1TorHeim.Text = TorHeim
    26. Windows_Form.Label2TorGast.Text = TorGast
    27. Windows_Form.Label3Period.Text = Period
    28. StringKomplettText = ""
    29. End If
    30. End If​