Serielle Daten von Spektrometer

  • VB.NET

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von DTF.

    Serielle Daten von Spektrometer

    Ich habe mir einen Spektrometer gebaut, der die Daten eines linearen Photodiodenchips über eine Teensy 4.1 per USB an den PC schickt.
    Leider bin ich noch nciht so firm im Programmieren von diesem C++, aber es funktioniert zumindest.
    Teensy sendet andauernd, ohne Handshake Daten per USB als Text in etwa dieser Form:

    +Diodennummer 12Bit-Messwert-
    also
    +3648 1047-

    Das klappt, und ich kann die Daten auch mittels VB.Net einlesen und als Spektrum darstellen.
    Bisher mache ich das in einer Schleife, in der auch alles andere passiert.
    Die Daten kommen nicht in einer fortlaufenden Reihenfolge, sondern (weil ich es nicht schneller kann) zufällig
    Es wird also nicht jede Diode nach der Reihe ausgelesen, sondern immer einen zufälligen Zeitabschnitt gewartet,
    bis irgend eine Diode messbar war.
    Im VB-Programm wird ein Array gefüllt. Die Position im Array ist die Diodennummer, die ja übertragen wird,
    und der Inhalt ist der Messwert. Nach einer unbestimmten Zeit sind alle Arraypositionen neu gefüllt.
    (Leider ist mir noch keine schnellere Methode eingefallen)

    Nun dachte ich daran, das Auslesen der Schnittstelle mit einem Backgroundworker? zu erledigen.

    Ist das sinnvoll?
    Es gibt doch inzwischen auch einige andere Methoden, um einen weitgehend unabhängigen
    aber schnellen Ablauf der Programmteile zu bekommen.

    Was würdet ihr dazu vorschlagen?
    @Lightsource Backgroundworker ist out, async ist in.
    Bei einer Hardware-Kommunikation über USB kannst Du vielleicht den Empfänger als SerialPort konfigurieren (bei BarcodeScannern geht das problemlos).
    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 schrieb:


    Bei einer Hardware-Kommunikation über USB kannst Du vielleicht den Empfänger als SerialPort konfigurieren (bei BarcodeScannern geht das problemlos).


    Das ist tatsächlich schon der Fall. Die Teensy hängt zwar am USB-Port, wird aber vom PC (auch) als serieller Port erkannt.
    Allerdings dann mit utopischen Bauraten (hier 4608000) das ist natürlich erst mal ausreichend.

    Zum Async:
    Heißt das, ich schreibe das Auslesen in einer Sub als Dauerschleife. (Diese liest die Schnittstelle aus und schreibt in das Array)
    Und starte diese Schleife dann als Async-Prozedure?
    Dann habe ich eine Zeichenroutine, die ich auch als Dauerschleife laufen lasse. Diese holt sich immer den Inhalt des Arrays.
    Und zeichnet lustig vor sich hin.

    Im Hauptteil des Programms wartet das Programm dann nur noch auf Buttons, die beispielsweise alles beenden,
    oder diverse Skalierungen oder Verschiebungen an die Zeichenroutine übergeben können?

    Hättest du einen Link parat, wo ich mir so etwas anschauen könnte?

    Lightsource schrieb:

    wird aber vom PC (auch) als serieller Port erkannt.
    Wnn das so ist, kannst Du doch das Einlesen ganz easy asynchron machen, indem Du im SerialPort.DataReceived-Event die vorhandenen Daten abholst und Dein Array befüllst.
    Dann sensest Du ein Event an die GUI, dass neue Daten darzustellen sind.
    Feddich.
    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 hatte mich bisher immer davor gescheut, DataReceived zu verwenden.
    Irgendwo hatte ich mal gelesen Microsoft hätte das nicht so richtig implementiert, oder es würde immer wieder Probleme auftreten.
    Aber stimmt, probieren kann ich es mal.



    Mit DataReceived bekomme ich mehr verkorkste Werte, als verwendbare Daten. Das geht so nicht.

    VB.NET-Quellcode

    1. Private Sub SP_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles SP.DataReceived
    2. Dim SerPort As SerialPort = CType(sender, SerialPort)
    3. Dim Linie As String
    4. Dim Wert As Integer
    5. Dim Diodennummer As Integer
    6. Linie = SerPort.ReadLine()
    7. Debug.Print(Linie)





    +1132 132 2615-

    +2093+2+202092093 2487-

    +3+3089 2343-

    +1035 2640-
    +1035 2640-

    +2129 2++1++1943 2516-

    +2+2938 2379-

    +2033 +2033+2033 2496-

    ++2+207+2075 2502-

    +292 +292 26+292+2+2+2+292 2692 26992 2699-

    +359+3592 2231-

    +1753 2553-

    ++368 2694-

    ++1+1++1805 2528-

    +10+1084 2619-
    +1084 +1084 26+1+1+1+1+1084 2619-

    ++150 2690-

    +15+1512 2543-

    +64+647 2+647 +647 2683-

    Beiträge zusammengefügt. ~Thunderbolt



    Ich habe es jetzt doch noch mit DateReceived geschafft. Man kann nicht ReadLine verwenden, obwohl ich immer den Puffer gelöscht hatte.
    Mit ReadExisting muss man den ganzen Wust abrufen, und dann an den CRLFs splitten.

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

    Man kann nicht ReadLine verwenden, obwohl ich immer den Puffer gelöscht hatte.
    Mit ReadExisting muss man den ganzen Wust abrufen, und dann an den CRLFs splitten.


    Das Standard Zeilenendezeichen bei der seriellen Schnittstelle ist LF.

    Für CrLf musst du bei der Schnittstellen Konfiguration die Zeile
    SerialPort.NewLine = Chr(13)& Chr(10)
    einfügen.
    @Eierlein Jou.

    Lightsource schrieb:

    VB.NET-Quellcode

    1. Dim SerPort As SerialPort = CType(sender, SerialPort)
    Wenn Du nur ein SerialPort im Einsatz hast, kannst Du die in der Klasse abgelegte Instanz verwenden, da musst Du nicht sender casten.
    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!

    Haudruferzappeltnoch schrieb:

    Warum sollte ein Zeilenende LF also nicht funktionieren?
    Weil das SerialPort dann falsche Zeilen liefert.
    Mit SerialPort.NewLine kannst Du die Gegenstelle parametrieren.
    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
    Tatsächlich habe ich vor, zwei Schnittstellen anzusprechen. Im Moment ist die Steuerung und die Datenübertragung noch auf zwei Programme verteilt.

    Mit den LFs und CRs habe ich eigentlich keine Probleme.

    Probleme liegen nach meiner bisherigen Erkenntnis eher bei der Implementierung der Seriellen Schnittstelle in der Teensy.
    (Das ist eine USB Schnittstelle, die sich im PC als serielle Schnittstelle zu erkennen gibt)
    Normalerweise würde ich annehmen, dass wenn man keinen Handshake macht so wie hier, die Senderseite einfach immer weiter sendet.
    Selbst dann , wenn der Eingangspuffer voll ist. Stimmt ihr mir da zu?
    Die ganze Zeit, als ich mit Readline gearbeitet hatte, wurden die Daten sehr langsam gelesen.
    Es dauerte ca. 20 Sekunden, bis ich 1000 verwertbare Messdaten hatte.

    Nun, mit DataReceived, bekomme ich 4000 Mess-Werte in 7 Sekunden.
    Allerdings nicht auf Dauer. Ich sehe die Livedaten des Chips, aber nach einiger Zeit kommen immer weniger Daten durch.
    Ich habe schon mehrfach mit dem Eingangspuffer gespielt, oder den Puffer beim Start des Programms gelöscht.
    Auch manches mal beim Starten des Programms rastet der Empfang nicht richtig ein, obwohl die Daten
    richtig erkannt werden. Wenn die Schnittstelle außer Takt wäre, müsste sich das doch in falsch erkannten Werten zeigen.
    Oder sich irgendwann von selbst wieder synchronisieren. Schließlich werden ja auch StopBits verwendet.
    Im Moment stehe ich da auf dem Schlauch, woran das hängt.



    VB.NET-Quellcode

    1. Private Sub SP_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles SP.DataReceived
    2. Dim SerPort As SerialPort = CType(sender, SerialPort)
    3. Dim Linie As String
    4. Dim Zeile As String
    5. Dim Wert As Integer
    6. Dim Diodennummer As Integer
    7. Zeile = SerPort.ReadExisting
    8. For n As Integer = 0 To UBound(Zeile.Split(vbCrLf))
    9. 'Debug.Print(UBound(Zeile.Split(vbCrLf)).ToString)
    10. Linie = Zeile.Split(vbCrLf)(n)
    11. If (Linie.StartsWith("+"c) = True And Linie.Contains(" "c) And Linie.Length <= 11) Then
    12. Wert = Zahl(Linie.Split(" ")(1).Replace("-", ""))
    13. Diodennummer = Zahl(Linie.Split(" ")(0))
    14. Dioden(Diodennummer) = Wert
    15. End If
    16. Next
    17. '
    18. If SerPort.IsOpen Then
    19. Debug.Print(SerPort.BytesToRead.ToString)
    20. SerPort.DiscardInBuffer()
    21. End If
    22. End Sub

    Bilder
    • Linie.PNG

      10,26 kB, 623×71, 22 mal angesehen
    • Zeile.PNG

      19,18 kB, 2.199×83, 26 mal angesehen

    Lightsource schrieb:

    Stimmt ihr mir da zu?
    Was steht im Handbuch des Senders?
    Ich würde davon ausgehen, dass Du pro Datenzeile ein DataReceived-Event bekommst.
    Verifiziere das.
    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!
    Was steht im Handbuch des Senders?


    Kommt drauf an, was du unter Sender verstehst.
    Wenn du das meinst, was Teensy sendet, dann ist das dieser Code:

    C-Quellcode

    1. void lesen() {
    2. // cnt ist der Counter durch die Dioden
    3. // Alle 4 Impulse gibt es die nächste Diode
    4. // Um also an die Diodennummer zu kommen muss man cnt durch 4 teilen
    5. int Diode = int(cnt / 4); //
    6. int Zwischenwert; // Zwischenwert ist erst mal das was der ADC liefert
    7. if ((Diode >= start) && (Diode <= Numberdiodes)) { // All starts with dummy pixels (start). (0->29520) / 2 >= 16
    8. Zwischenwert = adc->adc0->analogRead(A8); // Hier bekommen wir den neuesten Messwert
    9. // if ((Zwischenwert != Dioden[Diode]) && (Zwischenwert > 0)) { // Der Messwert sollte unterschiedlich zum letzten Messwert dieser Diode und nicht gleich Null sein
    10. Dioden[Diode] = Zwischenwert; // Das Messwertarray wird gefüllt. Das Array wird nur dazu benutzt, zu sehen, ob der Messwert schon mal gelesen wurde.
    11. Serial.print("+"); // Zu Beginn der Übertragung senden wir ein "+" Zeichen
    12. Serial.print(Diode); // Dann kommt die Diodennummer
    13. Serial.print(" "); // Ein Leerzeichen als Trennung
    14. Serial.print(Dioden[Diode]); // Der ermittelte Messwert
    15. Serial.println("-"); // Am Ende kommt noch ein "-" Zeichen und ein Zeilenabschluss
    16. delayMicroseconds(random(10, 80)); // Wir warten einen zufälligen Zeitabschnitt, um den Messungen Gelegenheit zu geben, nicht dauernd die
    17. // gleichen Dioden auszulesen. Zudem soll es für die serielle Schnittstelle von Vorteil sein, gemächlich zu senden.
    18. // }
    19. }


    Also alle 10-80ms wird eine ganze Zeile gesendet.

    Falls du mit Sender aber den ganzen USB nach Seriell-Wust meinst, dann wird es wohl schon etwas komplizierter.
    Da bin ich noch am Forschen, was Teensy da wirklich macht. In wie weit ein Handshake überhaupt verwendbar ist, wenn
    das System Teensy-PC doch sowieso per USB kommuniziert.

    Ich hatte auch schon in Verdacht, dass Teensy-USB, die eigene Messung am ADC beeinträchtigt.
    Zumindest hatte ich auch schon am Oszi gesehen, dass es da Zusammenbrüche des Timings nach einiger Zeit gibt.
    Ich hab von dem Thema keine Ahnung, aber es kommt mir mit den ganzen C++-print-Anweisungen so vor, als könnte jede print-Anweisung zu einem DataReceived-Ereignis führen. Der Code sieht selbstgeschrieben aus. Kannst Du die print-Anweisungen zu einer zusammenschmelzen? Also die Daten in einer Variable sammeln und deren Gesamtwert per println schicken?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Also die Daten in einer Variable sammeln und deren Gesamtwert per println schicken?


    Stimmt, das hatte ich auch mal vor.


    ______________________________________

    Ausprobiert:
    Hat nichts bewirkt.

    Ich müsste vielleicht ab und zu den Eingangspuffer explizit leeren.

    Was ich auch schon überlegt habe, ob die Stringzerlegung eventuell zu viel Zeit kostet.
    Theoretisch könnte ich die Daten auch als Bytes übertragen, dann müsste ich aber irgendwie die Datenstruktur so zusammenbauen, dass ich
    die Diodennummer vom Wert unterscheiden könnte. Als String ist das natürlich schon etwas einfacher.

    Was mich auch irritiert ist, dass Prozessor auf >10% Last hoch geht.



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

    Lightsource schrieb:

    Kommt drauf an, was du unter Sender verstehst.
    Die Gegenseite.
    Wenn Du die Quellen beider Seiten bearbeitest, ist es doch absolut kein Problem, da ein funktionierendes Protokoll hinzubekommen.
    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 Sache (Protokol) funktioniert doch, nur leider nicht auf Dauer.
    Ich weiß noch nicht, ob es Teensy oder PC ist.
    Teensy läuft eigentlich dauernd. Die hängt am USB-Port, und sendet lustig Daten (ins Leere)
    Immer wenn ich das VB Programm am PC starte bekomme ich ganz normal Daten, die ich auch grafisch anzeigen kann.
    Das können nicht nur die Daten, die bereits im Eingangspuffer liegen, sein, sondern auch aktuelle.
    Irgendwann, ich weiß nicht, ob es an irgendeinem Puffer, oder an irgend etwas anderem liegt, ruckelt es nur noch
    vor sich hin.

    Lightsource schrieb:

    Teensy
    Das mit dem Teensy hab ich noch nicht ganz verstanden.
    Sendet dieses Dimg AndAlso sendest Du mit dem obigen Code?
    Senden da ZWEI Programmteile?
    Es kann nur einen Herrn über die zu sendenden Daten geben!
    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!
    Teensy sendet nur Daten vom Photochip. Das ist die "Problemzone". Selbst programmiert auf Basis von C++ wie ein Arduino
    Es gibt noch eine Schrittmotortreiber-Platine. Diese arbeitet unabhängig auf einem anderen Port. Diese funktioniert einwandfrei.

    Ich habe jetzt mal an jede Zeile zusätzlich ein EOF (Null; 0) beim Senden angehängt, und verfolge nun, wie lange das klappt.
    Denn in der Beschreibung zum DataReceived steht, dass EOF ein spezieller Trigger sei.

    _____________________________________________________________________________________________
    Weitere Stunden später...


    Inzwischen funktioniert alles.
    Es kamen viel mehr Daten an, als VB verarbeiten konnte.
    Nun habe ich ReceivedBytesThreshold auf 4000 gesetzt.
    Alles was nach einer Auswertung im DateReceived nicht ausgewerted wurde wird verworfen.

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

    Lightsource schrieb:

    Es kamen viel mehr Daten an, als VB verarbeiten konnte.
    Genau da musst Du ansetzen.
    Wahrscheinlich werden immer alle Daten gesendet, Redundanz pur.
    Sorge dafür, dass nur neue Daten gesendet werden.
    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!