[VB 2017] Fehler bei Auswertung von Arduino-Daten über Serielle Schnittstelle in VB

  • VB.NET

Es gibt 3 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    [VB 2017] Fehler bei Auswertung von Arduino-Daten über Serielle Schnittstelle in VB

    Hallo, ich bin neu hier im Forum und Anfänger sowie Autodidakt was Programmierung angeht. Also bitte nicht gleich steinigen, wenn ich in ein Fettnäpfchen trete. ;)
    Ich arbeite in Visual Studio 2017. Leider kann ich euch nicht sagen, ob ich "VB6" oder "VB.net" nutze.

    Ziel meines Programms:
    Die Werte mehrerer Sensorsen am Arduino werden über das USB-Kabel und die virtuelle serielle Schnittstelle gesendet und sollen am PC ausgewertet werden. Um die Werte der einzelnen Sensoren am PC unterscheiden zu können, setzt der Arduino vor die jeweiligen Werte einen festgelegten Buchstaben. Aus „180“ wird „P180“ beim Drucksensor und bei der Abstandsmessung wir aus „0“ ein „D0“ gesendet. Im Programm prüfe ich dann den ersten Buchstaben und lasse dann den Wert ohne den Buchstaben „P“ oder „D“ entsprechend in ComboBox1 oder ComboBox2 ausgeben. Insofern der Arduino die Werte alle 200ms schickt, funktioniert alles bestens.
    Auf dem Bild seht ihr, was der Arduino sendet:


    Hier seht ihr, wie es sein soll und bei 200ms Delay auch funktioniert:


    Problem:
    Reduziere ich das Delay in der Loop des Arduino, stelle ich Fehler im Eintrag in der ComboBox fest. Scheinbar schafft es mein Programm nicht, die Buchstaben „schnell genug“ zu entfernen. Die Einträge in den Comboboxen haben nun die „P“ und „D“ vorangestellt. Je schneller ich den Arduino die Daten schicken lassen (also je geringer das Delay), desto häufiger treten die Fehler auf.


    Ich lasse im Programm folgendes mit den eingehenden Werten anstellen:

    Visual Basic-Quellcode

    1. Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    2. receivedData = ReceiveSerialData()
    3. If receivedData.Length > 0 Then If receivedData.Substring(0, 1) = "D" Then Dist(receivedData)
    4. If receivedData.Length > 0 Then If receivedData.Substring(0, 1) = "P" Then Pres(receivedData)
    5. End Sub
    6. Private Sub Dist(D As String)
    7. D = D.Remove(0, 1)
    8. RichTextBox1.Text &= D
    9. If IsNumeric(D) Then
    10. dldo = Int(D)
    11. If DDState Then DDout(Int(D)) Else DDin(Int(D))
    12. End If
    13. End Sub
    14. Private Sub Pres(P As String)
    15. P = P.Remove(0, 1)
    16. RichTextBox2.Text &= P
    17. If IsNumeric(P) Then
    18. dldo = Int(P)
    19. If DDState Then DDout(Int(P)) Else DDin(Int(P))
    20. End If
    21. End Sub
    22. Private Sub DDin(vl As Integer)
    23. If vl < DDInVAL.Value Then
    24. DDState = True
    25. BlowTM.Enabled = False
    26. BlowTM.Enabled = True
    27. End If
    28. End Sub
    29. Private Sub DDout(vl As Integer)
    30. If vl > DDoutVal.Value Then
    31. DDState = False
    32. BlowTM.Enabled = False
    33. BlowTM.Enabled = True
    34. End If
    35. End Sub


    Das Erhöhen der Baudrate hat keine Veränderung gebracht, ist m.E. auch irrelevant, wenn ich mit Delay arbeite, oder?
    Ich kann mir kaum vorstellen, dass mein Core i7 zu langsam ist, um die paar Operation schnell genug auszuführen? Wie oben geschrieben, ich bin kein gelernter Programmierer. Könnt ihr mir weiterhelfen und/oder einen Tipp geben? Schon mal vielen Dank für eure Hilfe!

    Falls ihr dafür noch wissen müsst, wie ich den seriellen Port eingebunden habe:

    Visual Basic-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles connect_BTN.Click
    2. If (connect_BTN.Text = "Connect") Then
    3. If (comPORT <> "") Then
    4. SerialPort1.Close()
    5. SerialPort1.PortName = comPORT
    6. SerialPort1.BaudRate = 115200
    7. SerialPort1.DataBits = 8
    8. SerialPort1.Parity = Parity.None
    9. SerialPort1.StopBits = StopBits.One
    10. SerialPort1.Handshake = Handshake.None
    11. SerialPort1.Encoding = System.Text.Encoding.Default
    12. SerialPort1.ReadTimeout = 10000
    13. SerialPort1.Open()
    14. connect_BTN.Text = "Dis-connect"
    15. Timer1.Enabled = True
    16. Timer_LBL.Text = "Timer: ON"
    17. Else
    18. MsgBox("Select a COM port first")
    19. End If
    20. Else
    21. SerialPort1.Close()
    22. connect_BTN.Text = "Connect"
    23. Timer1.Enabled = False
    24. Timer_LBL.Text = "Timer: OFF"
    25. End If
    26. End Sub
    Bilder
    • ArdSend.jpg

      25,22 kB, 117×368, 117 mal angesehen
    • Fehler.jpg

      41,68 kB, 466×244, 119 mal angesehen
    • klappt200ms.jpg

      27,97 kB, 528×203, 102 mal angesehen
    @Burkov Willkommen im Forum. :thumbup:
    Du programmieerst mit VB.NET. 8o

    Burkov schrieb:

    VB.NET-Quellcode

    1. SerialPort1.Open()
    Das Port bleibt für die Laufzeit des Programms geöffnet, falls das nicht so ist.
    Was bezweckst Du mit

    VB.NET-Quellcode

    1. BlowTM.Enabled = False
    2. BlowTM.Enabled = True
    ?
    Und:
    Schmeiß den Timer zum Datenempfang raus, nutze das DataReceived-Event des SerialPorts, es sagt Dir, dass Daten da sind, und da sollten sie auch vollständig sein.
    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!
    @RodFromGermany: Vielen Dank für deine Hinweise

    Das Port bleibt für die Laufzeit des Programms geöffnet, falls das nicht so ist.

    --> was willst du mir damit sagen?

    Was bezweckst Du mit


    VB.NET-Quellcode

    BlowTM.Enabled = False
    BlowTM.Enabled = True



    ?


    Damit starte ich den laufenden Timer neu. Soweit ich gelesen habe, läuft er mit "start" und "stop" immer an der aktuellen Position weiter. Diese Variante habe ich mir ergoogelt, um den Timer neu zu starten. Ich finde sie zwar einerseits logisch, andererseits aber auch umständlich.

    Schmeiß den Timer zum Datenempfang raus, nutze das DataReceived-Event des SerialPorts, es sagt Dir, dass Daten da sind, und da sollten sie auch vollständig sein.

    --> ok, das habe ich jetzt gemacht. Jetzt wo du es schreibst, ist es auch absolut logisch. Da habe ich ein Tutorial wahrscheinlich zu unreflektiert übernommen. Ich habe nun also die Codezeilen aus Timer1.Tick in das DataReceived-Event des SerialPorts übernommen. Allerdings bekomme ich jetzt folgende Fehlermeldung:

    "System.InvalidOperationException: "Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement RichTextBox1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.""

    Jetzt kommt die Anfängerfrage: Hat das etwas damit zu tun, dass ich etwas "invoken" muss?
    Zumindest steht das hier wohl so: msdn.microsoft.com/de-de/libra…tareceived(v=vs.110).aspx
    Falls dem so ist, verstehe ich nicht, WAS ich WO invoken muss!? In dem Beispiel bei dem Link kommt "invoke" nämlich zum Beispiel nicht vor.
    Ich habe mal gegoogelt, hat das etwas mit "Delegate" zu tun?
    Leider verstehe ich es trotz dem Studium anderer Threats hier im Forum nicht. Kann mit das vielleicht jemand von euch für einen "Anfänger" erklären?

    Vielen Dank

    p.s.: Vielleicht ist folgende Funktion für euer Verständnis noch wichtig (auch ein Teil, dass ich von einem Tutorial übernommen habe):

    VB.NET-Quellcode

    1. Function ReceiveSerialData() As String
    2. Dim Incoming As String
    3. Try
    4. Incoming = SerialPort1.ReadExisting()
    5. If Incoming Is Nothing Then
    6. Return "nothing" & vbCrLf
    7. Else
    8. Return Incoming
    9. End If
    10. Catch ex As TimeoutException
    11. Return "Error: Serial Port read timed out."
    12. End Try
    13. End Function

    Burkov schrieb:

    --> was willst du mir damit sagen?
    Das Port wird im Programm nicht mehrfach geschlossen und geöffnet, sondern je genau ein Mal.
    Ungültiger threadübergreifender Vorgang

    Quellcode

    1. Sub DataReceived(...) Handles ...
    2. Dim txt = MyPort.ReadExisting
    3. BeginInvoke(Sub() DoIt(txt))
    4. End Sub
    5. Sub DoIt(txt As String)
    6. MessageBos(txt)
    7. End Sub

    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!