EIA232 (RS232) - String senden und Rückgabe ausgeben

  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von Dodo.

    EIA232 (RS232) - String senden und Rückgabe ausgeben

    Moin,

    ich programmiere gerade eine Steuerungssoftwäre für einen Lock-In Amplifier (muss niemand wissen was es ist). Dieser lässt sich via EIA-232 steuern und auslesen.
    Nun habe ich mir zunächst ein kleines Terminal Programm geschrieben um erstmal zu testen und funktioniert auch prima. Es werden Strings übergeben und mir Strings zurück geschickt, wenn ich z.B. "Q1" schicke wird mir der Spannungswert von Ausgang 1 zurückgegeben, also normaler ASCII.
    Soweit so gut, nun möchte ich jedoch, da ich einige Werte auslesen möchte, eine Funktion machen an die ich den Steuerbefehl übergebe und als Rückgabe die Rückgabe des Gerätes haben.

    Momentan habe ich es so, dass ich das DataReceived Event des SerialPorts nutze, nur das funktioniert ja nun nicht mit einer Funktion.

    Also hier ma die Event Routine:

    VB.NET-Quellcode

    1. Private Sub LockIn_DataReceived(ByVal sender As System.Object, ByVal e As SerialDataReceivedEventArgs) Handles LockIn.DataReceived
    2. Dim rxString As New StringBuilder
    3. Dim LoopEnd As Boolean = False
    4. Do Until LoopEnd
    5. rxString.Append(LockIn.ReadExisting())
    6. If rxString.Length > 2 Then
    7. LoopEnd = (Asc(rxString.ToString.Substring(rxString.Length - 1)) = 13)
    8. End If
    9. Loop
    10. Invoke(New LockInCallback(AddressOf Callback), rxString.ToString())
    11. End Sub


    Der StringBuilder ist deswegen, da die Zeichen zum teil einzelnt kommen. Könnte es auch kürzer mit Thread.Sleep machen aber das find ich nicht so gut. Mit einer Schleife bis e.EventType.Eof funktioniert leidernicht, da der das Eof nicht erkennt.

    Nunja also wie mache ich das nun wenn ich eine Funktion habe:

    VB.NET-Quellcode

    1. Private Function LockIn_Send(ByVal Command As String) As String
    2. LockIn.WriteLine(Command & vbNewLine) ' LockIn ist der SerialPort
    3. ' Daten empfangen?!?!?!?
    4. return empfangendeDaten
    5. End Function


    Mein Problem ist halt jetzt wie ich an die Daten komme, die ja in einem extra Event reladen werden.
    Man könnte natürlich eine Do Schleife machen und warten bis in der Variablen was drin ist, aber das erachte ich als nicht performant.
    thäoretsch:
    Den Aufruf von Send schon in einen eigenen Thread packen, dann nach dem Senden ein WaitHandle setzen und im receive wieder zurücksetzen.
    Musst halt nur in der aufrufenden Funktion darauf achten, kein Control direkt anzusprechen, sondern ggfs invoken.
    Im eigenen Thread ist es bereits. Aber wenn ich mir das durchlese ist WaitEvent und meine Do While Schleife ähnlich. Also es wird einfach gewartet bist das Handle DataReceived ausgeführt wurde und die Datenempfangen wurden, das prüfe ich momentan in meiner Funktion

    VB.NET-Quellcode

    1. Private Function LockIn_Send(ByVal Command As String) As String
    2. LockIn.WriteLine(Command & vbNewLine)
    3. CallbackString = String.Empty
    4. Do Until CallbackString.Length > 0
    5. Application.DoEvents()
    6. Loop
    7. CallbackString = CallbackString.Replace(vbLf, "")
    8. CallbackString = CallbackString.Replace(vbCr, "")
    9. Return CallbackString
    10. End Function


    Der Callback String ist eine Globale Variable die von der Invokten Funktion Callback gefüllt wird nachdem das DataReceived Event alles empfangen hat.
    Ja okay, stimmt hast recht.

    Nunja habe ein Beispiel gefunden aber irgendwie blick ich da nicht durch *g* bzw. weiß nicht wie ich es auf mein Vorhaben anwenden soll

    java2s.com/Code/CSharp/Thread/…WaitingwithWaitHandle.htm

    Also ich habe die Sub Routine die über Invoke ausgeführt wird wenn der String empfangen wurde

    VB.NET-Quellcode

    1. Private napDone As New AutoResetEvent(False)
    2. Private Sub Callback(ByVal Text As String)
    3. CallbackString = Text
    4. napDone.Set()
    5. End Sub


    Nun weiß ich aber nicht weiter wie ich dieses Function DoSleep() bei mir umsetzten soll. Dort wird ja noch ein Thread gestartet der eine bestimmte Zeit wartet. Nur mir würde da auch nur wieder die Lösung einfallen ein Thread mit einer Schleife zu starten O.o

    Aber er soll ja irgendwie in der Funktion warten

    VB.NET-Quellcode

    1. Private Function LockIn_Send(ByVal Command As String) As String
    2. LockIn.WriteLine(Command & vbNewLine)
    3. CallbackString = String.Empty
    4. WaitHandle.WaitAll(??) ' woher bekomme ich nun den Wait auf den gewartet werden soll?
    5. CallbackString = CallbackString.Replace(vbLf, "")
    6. CallbackString = CallbackString.Replace(vbCr, "")
    7. Return "<< " & CallbackString
    8. End Function
    So hatte ich es bereits, dann hängt sich mein Programm auf

    VB.NET-Quellcode

    1. Private napDone As New AutoResetEvent(False)
    2. ' Event welches im Thread gestartet wird wenn Daten eingehen
    3. Private Sub LockIn_DataReceived(ByVal sender As System.Object, ByVal e As SerialDataReceivedEventArgs) Handles LockIn.DataReceived
    4. Dim rxString As New StringBuilder
    5. Dim LoopEnd As Boolean = False
    6. Do Until LoopEnd
    7. rxString.Append(LockIn.ReadExisting())
    8. If rxString.Length > 2 Then
    9. LoopEnd = (Asc(rxString.ToString.Substring(rxString.Length - 1)) = 13)
    10. End If
    11. Loop
    12. Invoke(New LockInCallback(AddressOf Callback), rxString.ToString())
    13. End Sub
    14. Private Sub Callback(ByVal Text As String)
    15. CallbackString = Text
    16. napDone.Set() ' Thread freigeben
    17. End Sub
    18. Private Function LockIn_Send(ByVal Command As String) As String
    19. LockIn.WriteLine(Command & vbNewLine)
    20. CallbackString = String.Empty
    21. napDone.WaitOne() ' warten
    22. CallbackString = CallbackString.Replace(vbLf, "")
    23. CallbackString = CallbackString.Replace(vbCr, "")
    24. Return "<< " & CallbackString
    25. End Function


    Die Funktion Send is nun nicht im extra Thread, aber sollte doch trotzdem funktionieren oder nicht? Zuerst ist AutoResetEvent auf False, dann wird etwas an EIA232 gesendet und auch das Event DataReceived ausfegührt, welches über Invoke die Sub Callback aufruft in der der Variablen Callback der empfangende Wert zugeweisen wird und der AutoResetEvent auf True gesetzt wird.

    Edit: ach klar, weil Callback im gleichen Thread ist und der wurde ja eingefrohren, deswegen zieht das Invoke nicht oder?

    Edit2: So nu habe ichs, ich brauch gar kein Invoke, beim DataReceive Event packe ich den empfangenen String einfach in die Variable CallbackString und setzte das AutoResetEvent, danach kann ich aus der Funktion heraus ohne Probleme auf die Variable zugreifen.
    Danke schön!

    Edit3: Problem habe ich nur noch wenn ein Befehl keine Rückgabe auslöst, da gibts auch welche die bestimmte Einstellungen im Gerät setzten, aber ich denke mal dafür wird das Optionale Argument Timeout der funktion WaitOne() da sein. Unschön hier dann 1000 sek zu warten aber anders gehts ja leider nicht.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Dodo“ ()