SerialPort-Verzögerung

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von Tilmann.

    SerialPort-Verzögerung

    Hallo,
    ich kommuniziere mit meinem PC per UART (BAUD 56000) mit einem Mikrocontroller (ATMega8).
    Der Mikrocontroller schickt 2Zeilen mit insgesamt 96 Werten, berechnet dann was und schickt wieder 2 Zeilen mit je 96 Werten. Das geht ca. 7 mal in der Sekunde.
    Wenn ich mir das ganze mit dem HTerm anseh funktioniert alles supa.
    Nur wenn ich mein eigenes Programm benutze sind die Werte verzögert und werden immer mehr Verzögert. Sprich ich empfange Daten vom Controller was auch funktioniert, dann geb ich ihm ein signal dass er nur noch 0 schicken soll, dann dauert es aber bis zu ein paar sekudnen bis ich die 0 auch wirklich empfang, genau das selbe auch wenn ich wieder auf die realen Werte umstelle.
    Am Programm vom Mikrocontroller liegst ziehmlich sicher nicht, da es mit HTerm ja wunderbar funktioniert (ohne verzögerung).
    Hier der Code den ich derzeit verwende:

    VB.NET-Quellcode

    1. Public Class frm1
    2. Private Sub frm1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    3. End Sub
    4. Private Sub cmdConnent_Click(sender As System.Object, e As System.EventArgs) Handles cmdConnent.Click
    5. If cmdConnent.Text = "Verbinden" Then
    6. srpMain.PortName = "COM1"
    7. srpMain.BaudRate = 56000
    8. srpMain.DataBits = 8
    9. srpMain.StopBits = IO.Ports.StopBits.One
    10. srpMain.Parity = IO.Ports.Parity.None
    11. srpMain.Open()
    12. cmdConnent.Text = "Trennen"
    13. ElseIf cmdConnent.Text = "Trennen" Then
    14. srpMain.Close()
    15. cmdConnent.Text = "Verbinden"
    16. End If
    17. End Sub
    18. Private Sub txtMain_TextChanged(sender As System.Object, e As System.EventArgs) Handles txtMain.TextChanged
    19. If txtMain.TextLength > 10000 Then
    20. txtMain.Text = txtMain.Text.Remove(0, txtMain.TextLength - 10000)
    21. txtMain.SelectionStart = txtMain.TextLength
    22. End If
    23. txtMain.ScrollToCaret()
    24. End Sub
    25. Private Sub srpMain_DataReceived(sender As Object, e As System.IO.Ports.SerialDataReceivedEventArgs) Handles srpMain.DataReceived
    26. Me.Invoke(Sub() txtMain.Text = srpMain.ReadLine)
    27. End Sub
    28. End Class


    Wenn ich das ganze nicht mir readline sondern mit readchar mach geht das ganze noch um einiges langsamer von statten. Dann braucht er für eine Zeile schon um die 5 Sekunden.
    Irgendwo hab ich da einen groben Denkfehler drin. Ich hoff es kann mir wer helfen.
    mfg.skyscater
    Nimm mal das TextChange-Event ganz raus, da Du beim Invoken den Text ja vollständig reinschreibst und nicht anhängst.
    Die Boude-Rate ist so hoch, dass Du alles in Ruhe sehen können solltest.
    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!
    Ich habs jetzt hinbekommen.
    Das Problem war, dass das DataRecieved Ereignis nicht wie von mir angenommen immer dann aufgerufen wurde wenn neue Daten rein gekommen sind sonder immer irgend wann.
    Bei den vielen Daten die der Mikrocontroller geschickt hat is es vorgekommen das wenn das DataRecieved Ereignis ausgelöst wurde schon mehrere Zeilen im Buffer gelegn sind und readline gibt immer nur eine Zeile zurück, womit die andern im Buffer verfaulen....
    Wenn man das readline durch redexisting ersetzt gehts einwandfrei.
    Mit dem Eingangsbuffer war gemeint dass ich eine Art FIFO Speicher verwende wo ich immer wenn was ankommt was reinschreib und im Hauptprogramm eine Rutine durchläuft die den abarbeitet oder?
    Daweil hab ichs so, dass das Event den readexisting string an eine sub schickt die ihn in zeilen zerlegt und weitergibt. Läuft zurzeit Dadenlos :)
    mfg.skyscater

    VB.NET-Quellcode

    1. Private Sub srpMain_DataReceived(sender As Object, e As System.IO.Ports.SerialDataReceivedEventArgs) Handles srpMain.DataReceived
    2. Me.Invoke(Sub() DataRecieved(srpMain.ReadExisting))
    3. End Sub


    VB.NET-Quellcode

    1. Dim stringBuffer As String
    2. Private Sub DataRecieved(ByVal existing As String)
    3. existing = stringBuffer & existing
    4. Dim line As String = ""
    5. For Each _char In existing
    6. If _char = vbCrLf OrElse _char = vbCr OrElse _char = vbLf Then
    7. If line <> vbCrLf AndAlso line <> vbCr AndAlso line <> vbLf AndAlso line.Replace(" ", "") <> "" Then
    8. LineReceived(line)
    9. line = ""
    10. End If
    11. Else
    12. line &= _char
    13. End If
    14. Next
    15. stringBuffer = line
    16. End Sub
    Danke Skyscater, das war schonmal sehr hilfreich und ich bin auf dem richtigen Dampfer.

    Jetzt bin ich einen Schritt weiter, habe jedoch ein weiteres Problem. Immer wenn ich einen String zusammen habe, springe ich in eine Sub und das scheint zu aufwendig da ich so nicht mehr jeden String untereinander in der Listbox stehen habe. Manchmal übersieht er einfach ein CR, scheinbar (s. Screenshot)

    Das ist jetzt mein Code, vielleicht seht ihr noch was ich besser machen kann?!?!?!

    VB.NET-Quellcode

    1. Private Sub DataRecieved(ByVal existing As String)
    2. existing = stringBuffer & existing
    3. ' Dim line As String = ""
    4. For Each _char In existing
    5. If _char = vbCrLf OrElse _char = vbCr OrElse _char = vbLf Then
    6. If SerialInput <> vbCrLf AndAlso SerialInput <> vbCr AndAlso SerialInput <> vbLf AndAlso SerialInput.Replace(" ", "") <> "" Then
    7. ' If SerialInput <> vbCr Then
    8. Form_Settings.ListBox1.Items.Insert(0, "Recv: " & SerialInput)
    9. If SerialInput.Contains("|") = True Then
    10. AuswSerialInp(SerialInput)
    11. End If
    12. SerialInput = ""
    13. End If
    14. Else
    15. SerialInput &= _char
    16. End If
    17. Next
    18. stringBuffer = SerialInput
    19. ' Form_Settings.ListBox2.Items.Insert(0, "Recv: " & existing)
    20. End Sub



    VB.NET-Quellcode

    1. Public Sub AuswSerialInp(ByVal sInput As String)
    2. Try
    3. ' String in Array packen
    4. Dim sPraefix() As String = {0, 0, 0, 0}
    5. Dim iPraefix() As Integer = {0, 0, 0, 0}
    6. ' auf "|" splitten
    7. sPraefix = sInput.Split(CChar("|")) 'erster Seperator
    8. ' Integer Wert umwandeln
    9. iPraefix(0) = CInt(sPraefix(0))
    10. iPraefix(1) = CInt(sPraefix(1))
    11. iPraefix(2) = CInt(sPraefix(2))
    12. iPraefix(3) = CInt(sPraefix(3))
    13. '##############################################
    14. '##############################################
    15. 'Status vom Mikro
    16. '##############################################
    17. '##############################################
    18. Select Case iPraefix(0)
    19. '
    20. Case 79
    21. '##############################################
    22. ' Raum
    23. '##############################################
    24. Select Case iPraefix(1)
    25. '
    26. Case 1
    27. '##############################################ir
    28. '##############################################
    29. Select Case iPraefix(2)
    30. '##############################################
    31. 'Keller
    32. Case 1
    33. Select Case iPraefix(3)
    34. ' Aus
    35. Case 0
    36. Form_Keller.B_Heizung.BackColor = Color.LightCoral
    37. Form_Keller.B_Heizung.Text = "Aus"
    38. varKellerHeizungIstAn = varKellerHeizungIstAn And Not Bits.bit0
    39. End Select
    40. End Select
    41. ....
    42. ....


    @Skyscater - Bitte um nähere Erläuterung

    Hallo Skyscater,

    es wäre geil, wenn Du diesen Code näher erläutern könntest ...
    Ich beschäftige mich nämlich auch gerade mit der Prüfung von über RS232 eingegangenen Strings ...

    Gruß Tilmann


    Dim stringBuffer As String
    Private Sub DataRecieved(ByVal existing As String)
    existing = stringBuffer & existing
    Dim line As String = ""
    For Each _char In existing
    If _char = vbCrLf OrElse _char = vbCr OrElse _char = vbLf Then
    If line <> vbCrLf AndAlso line <> vbCr AndAlso line <> vbLf AndAlso line.Replace(" ", "") <> "" Then
    LineReceived(line)
    line = ""
    End If
    Else
    line &= _char
    End If
    Next
    stringBuffer = line
    End Sub