Kommunikationsprobleme mit Datenempfang über RS232

  • VB.NET

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von VB-MD.

    Kommunikationsprobleme mit Datenempfang über RS232

    Guten Morgen,

    ich habe einige Probleme mit dem Datenempfang über USB-RS232- Adaptern.
    Vor einigen Jahren habe ich mir ein Projekt erstellt mit dem ich über die RS232-Schnittstelle
    Daten (nur Zahlen, wahlweise Word und Byte) senden und empfangen kann. Dies war zunächst nur
    zum Testen der Datenverbindung gedacht und wurde dann genutzt zum Auslesen von EProms (U555).

    Nun wollte ich dafür USB zu RS232 Adapter nutzen, da die echte UART an den meisten PCs nicht
    mehr vorhanden ist. Das Senden funktioniert weiterhin ohne Probleme. Nur beim Empfangen von 2 Bytes
    gibt es Schwierigkeiten. Bei einem älteren Adapter (wird mit USB- ... CH340 erkannt) wird nur ein Byte
    empfangen. Deshalb habe ich mir probehalber einen FTDI-Adapter zugelegt. Dort funktioniert es fast
    wieder nur dass sporadisch auch manchmal nur ein Byte ankommt. Nehme ich HTerm geht es immer
    problemlos. Deshalb denke ich, dass in meinem Programm wohl noch etwas unzureichend ist. Ich werde
    aber demnächst mal eine Verbindung mit einem Arduino aufbauen. Zur Zeit werkelt auf der anderen Seite
    ein ATMega48 mit einem LCD-Display.

    Hänge mal das Projekt als zip-Datei an. Vielleicht könnt ihr mal drüber schauen. Ich habe das Projekt
    mit Visual Studio 15 erstellt und benutze einen PC mit Win7 Prof.!

    Es eilt aber nicht.
    Danke und Gruß aus MD
    Jürgen

    VB.NET-Quellcode

    1. Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    2. Dim ZBytes As Integer = SerialPort1.BytesToRead 'Anzahl der Bytes im Empfangspuffer
    3. Dim MyMSB As Byte
    4. Dim MyLSB As Byte
    5. Invoke(Sub()
    6. TextBox10.Text = ZBytes.ToString() 'TexBox10 - Anzahl der Bytes im Buffer
    7. End Sub)
    8. If ZBytes = 1 Then
    9. MyLSB = CByte(SerialPort1.ReadByte())
    10. ZEmpf8 = MyLSB
    11. Invoke(Sub()
    12. TextBox5.Text = ZEmpf8.ToString()
    13. TextBox6.Text = ""
    14. TextBox7.Text = ""
    15. TextBox8.Text = MyLSB.ToString()
    16. End Sub)
    17. End If
    18. If ZBytes = 2 Then
    19. MyLSB = CByte(SerialPort1.ReadByte())
    20. MyMSB = CByte(SerialPort1.ReadByte())
    21. ZEmpf16 = 256 * MyMSB + MyLSB
    22. Invoke(Sub()
    23. TextBox5.Text = ""
    24. TextBox6.Text = ZEmpf16.ToString()
    25. TextBox7.Text = MyMSB.ToString()
    26. TextBox8.Text = MyLSB.ToString()
    27. End Sub)
    28. End If
    29. 'Invoke(Sub()
    30. ' TextBox4.Text = ZEmpf8.ToString() 'SerialPort1.Read(MyArray, 0, 2)
    31. ' End Sub) 'BitConverter.ToUInt16(ZEmpf, 0)
    32. SerialPort1.DiscardInBuffer() ' Zum löschen des Eingangspuffers
    33. 'SerialPort1.DiscardOutBuffer() ' Zum löschen des Ausgangspuffers
    34. End Sub
    Dateien
    • RS232-Komm.zip

      (155,34 kB, 22 mal heruntergeladen, zuletzt: )

    VB-MD schrieb:

    VB.NET-Quellcode

    1. Dim ZBytes As Integer = SerialPort1.BytesToRead
    Kam an dieser Stelle schon mal eine 3 zurück?
    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!
    Sorry, kann ja nur 1 oder 2 sein.
    Definiere
    "verschluckt"
    Kannst Du mal den Code der Initialisierung des Ports posten?
    ====
    In welchem Takt kommen die Daten?
    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!
    Na klar kann ich den den gesamten Code senden. Ist gar nicht mal so viel.
    Hatte aber des gesamte Projekt im Anhang. Läuft auch von einem Stick.

    Sende alle Sekunde vom Mikroprofessor. Denke wenn ich mal ein ernsthaftes
    Projekt daraus mache werde ich wohl eine Fehlermeldung generieren und
    zurückgeben.

    Ach so, alle Sekunde wird ein Word gesendet. Es wird auf der anderen Seite
    nur eine Variable hochgezählt.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Shared ZSend16 As UInt16
    3. Shared ZSend8 As Byte
    4. Shared SendArray() As Byte
    5. Shared ZEmpf16 As UInt16
    6. Shared ZEmpf8 As Byte
    7. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    8. Button5.BackColor = Color.FromArgb(180, 180, 180)
    9. TextBox3.Focus()
    10. End Sub
    11. Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    12. Dim ZBytes As Integer = SerialPort1.BytesToRead 'Anzahl der Bytes im Empfangspuffer
    13. Dim MyMSB As Byte
    14. Dim MyLSB As Byte
    15. Invoke(Sub()
    16. TextBox10.Text = ZBytes.ToString() 'TexBox10 - Anzahl der Bytes im Buffer
    17. End Sub)
    18. If ZBytes = 1 Then
    19. MyLSB = CByte(SerialPort1.ReadByte())
    20. ZEmpf8 = MyLSB
    21. Invoke(Sub()
    22. TextBox5.Text = ZEmpf8.ToString()
    23. TextBox6.Text = ""
    24. TextBox7.Text = ""
    25. TextBox8.Text = MyLSB.ToString()
    26. End Sub)
    27. End If
    28. If ZBytes = 2 Then
    29. MyLSB = CByte(SerialPort1.ReadByte())
    30. MyMSB = CByte(SerialPort1.ReadByte())
    31. ZEmpf16 = 256 * MyMSB + MyLSB
    32. Invoke(Sub()
    33. TextBox5.Text = ""
    34. TextBox6.Text = ZEmpf16.ToString()
    35. TextBox7.Text = MyMSB.ToString()
    36. TextBox8.Text = MyLSB.ToString()
    37. End Sub)
    38. End If
    39. 'Invoke(Sub()
    40. 'TextBox4.Text = ZEmpf8.ToString() 'SerialPort1.Read(MyArray, 0, 2)
    41. 'End Sub) 'BitConverter.ToUInt16(ZEmpf, 0)
    42. SerialPort1.DiscardInBuffer() ' Zum löschen des Eingangspuffers
    43. 'SerialPort1.DiscardOutBuffer() ' Zum löschen des Ausgangspuffers
    44. End Sub
    45. Private Sub TextBox1_TextChanged(sender As System.Object, e As System.EventArgs) 'COM-Port angeben > Voreinstellung = COM1
    46. End Sub
    47. Private Sub TextBox2_TextChanged(sender As System.Object, e As System.EventArgs) 'Baudrate angeben > Voreinstellung = 2400
    48. End Sub
    49. Private Sub TextBox3_TextChanged(sender As Object, e As EventArgs) Handles TextBox3.TextChanged
    50. TextBox4.Text = ""
    51. Button2.BackColor = Color.FromArgb(100, 255, 175)
    52. Button3.BackColor = Color.FromArgb(180, 180, 180)
    53. End Sub
    54. Private Sub TextBox4_TextChanged(sender As Object, e As EventArgs) Handles TextBox4.TextChanged
    55. TextBox3.Text = ""
    56. Button3.BackColor = Color.FromArgb(100, 255, 175)
    57. Button2.BackColor = Color.FromArgb(180, 180, 180)
    58. End Sub
    59. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click 'Connect-Button
    60. TextBox3.Focus()
    61. Try
    62. SerialPort1.PortName = TextBox1.Text
    63. SerialPort1.BaudRate = TextBox2.Text
    64. SerialPort1.Open()
    65. Button1.Enabled = False
    66. Button2.Enabled = True
    67. Button3.Enabled = True
    68. Button4.Enabled = True
    69. Button2.BackColor = Color.FromArgb(100, 255, 175)
    70. Button3.BackColor = Color.FromArgb(100, 255, 175)
    71. Button5.BackColor = Color.FromArgb(255, 140, 0)
    72. Catch ex As Exception
    73. MsgBox("Verbindung fehlgeschlagen!")
    74. SerialPort1.PortName = "COM1"
    75. SerialPort1.BaudRate = "9600"
    76. End Try
    77. End Sub
    78. Private Sub Button4_Click(sender As System.Object, e As System.EventArgs) Handles Button4.Click 'Disconnect-Button
    79. SerialPort1.Close()
    80. Button1.Enabled = True
    81. Button2.Enabled = False
    82. Button3.Enabled = False
    83. Button4.Enabled = False
    84. Button2.BackColor = Color.FromArgb(180, 180, 180)
    85. Button3.BackColor = Color.FromArgb(180, 180, 180)
    86. Button5.BackColor = Color.FromArgb(180, 180, 180)
    87. End Sub
    88. Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click 'Senden-Button 1Byte
    89. TextBox3.Focus() 'Fokus wird auf TextBox3 gesetzt
    90. Try
    91. ZSend8 = CInt(TextBox3.Text) 'Text in Integer umwandeln (CStr-Interger in Text)
    92. If ZSend8 > -1 And ZSend8 <= 255 Then
    93. SendArray = BitConverter.GetBytes(ZSend8)
    94. End If
    95. TextBox4.Text = ""
    96. Catch ex As Exception
    97. MsgBox("Eingabe falsch!")
    98. End Try
    99. System.Threading.Thread.Sleep(50) 'Warten 50ms
    100. SerialPort1.Write(SendArray, 0, 1)
    101. End Sub
    102. Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click 'Senden-Button 2Byte
    103. TextBox4.Focus() 'Fokus wird auf TextBox3 gesetzt
    104. Try
    105. ZSend16 = CInt(TextBox4.Text) 'Text in Integer umwandeln (CStr-Interger in Text)
    106. If ZSend16 > -1 And ZSend16 <= 65535 Then
    107. SendArray = BitConverter.GetBytes(ZSend16)
    108. End If
    109. TextBox3.Text = ""
    110. Catch ex As Exception
    111. MsgBox("Eingabe falsch!")
    112. End Try
    113. System.Threading.Thread.Sleep(50) 'Warten 50ms
    114. SerialPort1.Write(SendArray, 0, 2)
    115. End Sub
    116. Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    117. If SerialPort1.IsOpen = True Then
    118. SerialPort1.Close()
    119. End If
    120. End Sub
    121. Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click 'Beenden-Button
    122. If SerialPort1.IsOpen = True Then
    123. SerialPort1.Close()
    124. End If
    125. Close()
    126. End Sub
    127. Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
    128. End Sub
    129. Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click 'Anzeige der COM-Schnittstellen (ListBox1)
    130. For Each sp As String In My.Computer.Ports.SerialPortNames
    131. ListBox1.Items.Add(sp)
    132. Next
    133. End Sub
    134. End Class
    Ohne mir jetzt dein Code im Detail anzuschauen: RS232 ist ein bocksimples Protokoll.

    Wenn Daten verloren gehen, kann es eigentlich nur zwei Gründe haben: Crosstalk/falsche Polarität, oder die Bitrate wird nicht eingehalten.

    Wenn du in deinem Programm irgendwo eine Stelle hast, wo gewartet wird und der Puffer nicht schnell genug geleert wird (quasi eine Race-Condition), dann gehen Daten verloren.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.
    Fang an mit Option Strict On.
    Visual Studio – Empfohlene Einstellungen
    Dann lass das SerialPort1.DiscardInBuffer() mal weg, Du liest ja den Empfangsbuffer eh komplett aus.
    Und mach kein Invoke sondern ein BeginInvoke und pack da alles rein, was zu invoken ist:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    2. Dim ZBytes As Integer = SerialPort1.BytesToRead 'Anzahl der Bytes im Empfangspuffer
    3. Dim MyMSB As Byte
    4. Dim MyLSB As Byte
    5. If ZBytes = 1 Then
    6. MyLSB = CByte(SerialPort1.ReadByte())
    7. ZEmpf8 = MyLSB
    8. BeginInvoke(Sub()
    9. TextBox10.Text = ZBytes.ToString() 'TexBox10 - Anzahl der Bytes im Buffer
    10. TextBox5.Text = ZEmpf8.ToString()
    11. TextBox6.Text = ""
    12. TextBox7.Text = ""
    13. TextBox8.Text = MyLSB.ToString()
    14. End Sub)
    15. ElseIf ZBytes = 2 Then
    16. MyLSB = CByte(SerialPort1.ReadByte())
    17. MyMSB = CByte(SerialPort1.ReadByte())
    18. ZEmpf16 = 256 * MyMSB + MyLSB
    19. BeginInvoke(Sub()
    20. TextBox10.Text = ZBytes.ToString() 'TexBox10 - Anzahl der Bytes im Buffer
    21. TextBox5.Text = ""
    22. TextBox6.Text = ZEmpf16.ToString()
    23. TextBox7.Text = MyMSB.ToString()
    24. TextBox8.Text = MyLSB.ToString()
    25. End Sub)
    26. End If
    27. 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!
    Nein, hat leider nichts gebracht. Habe auch Invoke ganz weggelassen aber ...
    Es kommt halt manchmal nur ein Byte an, wie auch in der Variablen "ZBytes"
    zu sehen ist.
    Und in meinem Programm sind keine Pausen enthalten.

    Trotzdem erstmal Danke für die Hinweise
    Was genau macht die Gegenstelle?
    Wird die zum Senden aufgefordert?
    Sendet die in ihrem eigenen Takt?
    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!
    Die Gegenstelle (siehe weiter oben) sendet selbstständig alle Sekunde ein Word.
    Es wird nur eine Variable hochgezählt. Es waren aber auch schon 2 PCs miteinander
    mit dem gleichen Programm verbunden. Allerdings über die echte UART und es
    lief problemlos.
    Demnächst soll aber ein HC-12-Modul damit werkeln und per Funk die Beleuchtung
    einer Modellbahn steuern. Da das Senden ohne Probleme geht, habe ich Hoffnung!
    Ist das Port korrekt initialisiert?
    Du packst da Strings aus TextBoxen rein.
    Die verfügbaren Ports kannst Du in eine ComboBox packen:

    VB.NET-Quellcode

    1. Me.ComboBox1.Items.AddRange(IO.Ports.SerialPort.GetPortNames())
    Probier mal dies aus:

    VB.NET-Quellcode

    1. Private Sub SerialPort1_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    2. Dim txt = Me.SerialPort1.ReadExisting
    3. Me.Invoke(Sub() Me.RichTextBox1.AppendText(txt & Environment.NewLine))
    4. 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!
    Werde es mal probieren. Am Anfang hatte ich aber den COM-PORT im Programm fest zugewiesen
    und vorher im Geräte-manager nachgesehen welcher es ist. Eine ComboBox ist aber schon eleganter.
    Demnächst werde ich vielleicht meinen anderen Win10-PC mit einem aktuelleren Studio nachrüsten.
    Mal sehen ..... Bin zwar nicht der Typ, der immer alles auf dem neuesten Stand haben möchte wenn
    das alte ja noch funktioniert aber Mann wird oft dazu gezwungen. Kannst Du eins empfehlen?

    (Kann man hier keine Bilder .png oder .jpg einfügen?)

    VB-MD schrieb:

    (Kann man hier keine Bilder .png oder .jpg einfügen?)
    Erweiterte Antwort => Dateianhänge => Hochladen
    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!
    Es funktioniert jetzt!
    Ein guter Hinweis kam von Siycah. Aber es lag nicht an eventuellen Pausen im Programm
    sondern die USB-RS232-Adapter waren zu langsam.
    Ich frage nämlich den Empfangspuffer auf ein Byte oder 2 Byte ab. Kommt das Word zu
    langsam an wird zunächst nur ein Byte erkannt, verarbeitet und der Puffer gelöscht obwohl
    inzwischen das andere Byte auch schon angekommen ist. Wenn ich die Boudrate auf 9600
    erhöhe ist der Fehler fast weg. Aber bei der echten UART funktioniert es immer.
    Danke aus MD
    Jürgen

    VB-MD schrieb:

    Wenn ich die Boudrate auf 9600
    erhöhe ist der Fehler fast weg

    Das ist aber kein einseitiger Parameter.
    Die sollte auf beiden Seiten abgestimmt gleich sein.
    Wie auch Anzahl der Bits und Parity.

    Um Datenverlust zu verhindern gibt es auch Handshakes wie SI/SO oder RTS/CTS.
    Mit einem darüberliegenden Sicherungsprotokoll kannst du Datenverlust und Übertragungsfehler erkennen.
    Bei blind gesendeten Daten kannst du dir nie sicher sein, ob du richtig und vollständig empfängst.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „petaod“ ()

    VB-MD schrieb:

    Wenn ich die Boudrate auf 9600 erhöhe ist der Fehler fast weg.
    Offensichtlich hast Du Dich nicht um die korrekte Initialisierung Deines Ports gekümmert, obwohl die Aufforderung dazu und die zur Überprüfung der Parameter mehrfach im Thread gepostet wurde. X(
    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!
    Verstehe ich gerade nicht!
    Ich habe mehrfach erwähnt, daß es mit der Hardware-COM problemlos funktioniert und ich
    damit sogar fehlerlos einen U555 auslesen kann. Dann habe ich nur einen USB-RS232-Adapter
    benutzt und es hakelte. Wenn ich damit nur ein Byte versende kommt auch kein Fehler.
    Natürlich habe ich auf Senderseite und Empfängerseite den Port, die Baudrate (2400),
    8 DatenBits, 1 Stopbit und die Parität N verwendet. Sonst würden ja nur stochastische
    Zeichen ankommen. Und als ich dann mit 9600 Boud (und das auf beiden Seiten) gearbeitet
    habe hatte ich auch bei den Adaptern fast keine Fehler mehr. Natürlich wäre es mit einem
    Handshakes besser.
    Und jetzt habe ich auf die Abfrage verzichtet wo ich nur bei einem Byte im Puffer schon
    etwas mache! Dann war der Fehler auch bei 2400 Boud verschwunden. Jetzt muß ich aber
    zunächst immer 2 Bytes senden.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VB-MD“ ()

    VB-MD schrieb:

    Die Gegenstelle (siehe weiter oben) sendet selbstständig alle Sekunde ein Word.

    VB-MD schrieb:

    Jetzt muß ich aber zunächst immer 2 Bytes senden.
    Ja wie denn nun?
    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!
    Alles nochmal?
    Die Gegenstelle sendet alle Sekunde ein Word. Ich habe mir aber in meinem Programm die Freiheit erlaubt
    auch mal nur ein Byte einzulesen. Siehe im Programm selbst! Dies erkannte das Programm bisher selbstständig.
    Jetzt habe ich einen Adapter verwendet und da hatte ich wahrscheinlich dadurch die Probleme mit 2 Bytes.
    Habe mal ein Bild der Eingabe angehängt.
    Bilder
    • Eingabe.jpg

      92,52 kB, 1.632×1.224, 16 mal angesehen