Guten Abend,
gleich vorab das wichtigste: Es geht um VB.net
Ich möchte die Daten, die über SerialPort1 reinkommen, in einer Textbox
anzeigen.
Am anderen Ende hängt ein Mikrocontroller.
Nun das Problem:
Normalerweise ist ein 2x 16 Zeichen LCD Display mit eigenem
Mikrcontroller ebenfalls über Seriell mit dem eigentlichen
Mikrocontroller verbunden.
In der ersten Zeile wird der aktuelle Systemzustand angezeigt, z.B.
"System bereit" oder "Batteriewarnung" etc.
In der zweiten Zeile werden die Zustände von 2 Eingängen angezeigt ("-"
wenn Eingang ohne Spannung, "+" wenn Eingang Spannung hat).
Das eigentliche Problem:
Ein Timer fragt den Zustand jede Sekunde ab. Der Mikrocontroller aber,
sendet pro Zeile (also für das 16-Zeichen Display Zeile 1) immer 2
Daten-Pakete.
Es kommt also erst im HEX Format die Hälfte an, z.B. "Batter", und im
nächsten Paket eine Sekunde später "iewarnung".
Das dann abwechselnd mit den Eingangs-Zuständen die für Zeile 2 bestimmt
sind.
So, und das eigentliche Problem des eigentlichen Problems:
Ich möchte das übersichtlich in einer TextBox darstellen (Label würde
auch gehen, aber das sollte ja keinen großen Unterschied machen).
Aktuell empfange ich mit
1
Data_received = SerialPort1.ReadExisting
2
If Len(Data_received) > 0 Then
3
TextBox1.Text = Data_received
Jetzt kommt erst die eine Hälfte des Systemzustands (zB Batter), und
dann die zweite (iewarnung). Sobald die zweite Hälfte ankommt, wird die
erste überschrieben...
Wenn ich bei "Data_received = SerialPort1.ReadExisting" vor dem "=" ein
"&" einfüge, dann sieht man manchmal mit Glück noch die zweite Hälfte
der Daten...aber dann ist die Box voll, weil ja auch noch die Zustände
der Eingänge eintrudeln...
Ich kann NICHT ändern, wie dieser uC arbeitet.
Alles was ich möchte, ist die Daten übersichtlich darstellen.
Also Zeile 1 der Textbox "Batteriewarnung"
Und Zeile 2 der Textbox "Eingang1:-, Eingang2:+"
Ich bin Anfänger beim programmieren, aber bisher hab ich alles irgendwie
hinbekommen.. aber nun könnte ich nen Tipp gebrauchen.
Anbei noch ein Screenshot, wie die empfangenen Daten ausschauen. Written
Data ist hier die Abfrage an den uC und Read die Antwort, die wie gesagt
zwei geteilt ist.
Vielleicht hat jemand eine Idee?
Danke schonmal
das passiert bei serielle Kommunikation öfters (und da wo es nicht
passiert ist einfach nur Glück)
das serielle Protokoll ist kein blockbasiertes Protokoll, grundsätzlich
kann alles Zeichenweise reintröpfeln ohne Garantie das irgendwas
zusammenhängend kommt - deswegen gibt es auch die Endekennungen
du musst (kontinuierlich) einen Puffer mit den seriellen Daten füllen
und fertige Pakete von vorne abschneiden und die an deine UI
weiterleiten (oder noch auf das nächste Paket warten)
aber irgendwie sehe ich in deinem Dump keine Ende-Kennung? im
schlechtesten Fall musst du auf "Batteriewarnung" warten
also
so
1. Datensatz
"Bat" (intern: "" -> "Bat")
2. Datensatz
"ter" (intern: "Bat" -> "Batter")
3. Datensatz
"iewarnung und was anderes" (intern: "Batter" -> "Batteriewarnung")
--> jetzt Batteriewarnung verarbeiten und den internen Puffer
am Anfang beschneiden
4. Datensatz
" mit dran" (intern: " und was anderes" -> " und was anderes mit dran")
Ist relativ einfach .
lauf = true : tx$ = ""
do while lauf = true
Data_received = SerialPort1.ReadExisting
If Len(Data_received) > 0 Then
if block = 0 then
block = 1
Tx$ = Data_received
else
tx$ = tx$ + Data_received + vb.crlf
block = 0
end if
if block = 0 then
if len(tx$) > 32.000 then print "Es gibt ein Problem" ' :)
TextBox1.Text = tx$
end if
end if
loop
ändere die Eigenschaft von Textbox1 Multiline = true
Dann wird alles aufgezeichnet und mit den Code da, werden 2 Blöcke in
eine Zeile gemacht, geschrieben und danach eine Zeilenschaltung
vorgenommen. Das bedeutet du kannst ca. 32 K an Daten in die Textbox
knallen.
Danke schonmal für die Hilfe...
Schlaumaier schrieb:> Ist relativ einfach .
Nun hätte ich mich vielleicht nicht Anfänger, sondern
"Programmier-Quereinsteiger ohne VB.net Kenntnisse" nennen sollen.
VB meckert dass "lauf" "block" und "tx" nicht declared ist...
Schlaumaier schrieb:> Tx$ = Data_received
Müsste das nicht ausreichend sein?
An sich klingt die Lösung nämlich super. Ich bin bloß zu blöd
Danke
Sk1 schrieb:>> Tx$ = Data_received>> Müsste das nicht ausreichend sein?
das überschreibt deinen Text mit dem zuletzt empfangenen - was genau
dein Problem ist - du musst anhängen nicht überschreiben
cppbert schrieb:> as überschreibt deinen Text mit dem zuletzt empfangenen - was genau> dein Problem ist - du musst anhängen nicht überschreiben
Meine eher, weil VB sagt, "lauf" "block" und "tx" sind nicht deklariert.
Sk1 schrieb:> Meine eher, weil VB sagt, "lauf" "block" und "tx" sind nicht deklariert.
Du kannst sie doch einfach deklarieren wenn du willst.
Dim tx as string
dim lauf as boolean
dim block as integer
Die alternative ist, das du die Prüfung abschaltest. Das geht, soll man
aber nicht machen als Anfänger besonders nicht. Ich code seit über 30
Jahren ich brauche die nicht, ergo bin ich dran gewöhnt es ohne zu
machen.
Ach da wäre noch was. Wenn du die DIM befehle schreibst bist und alle $
im Code entfernen.
Sk1 schrieb:
>> Tx$ = Data_received>> Müsste das nicht ausreichend sein?
Das übergibt den Empfangenen Text in eine Puffer-Variable. Im Code wird
entschieden wie es weiter geht.
Ich mag beim Coden halt saubere Strukturen. Und das bedeutet ich schlage
mich mit Übergaben nur an EINER Stelle herum. Dadurch weiß im immer
genau was wo passiert.
Ist halt altmodisches Codieren, teilweise mit mehr Variablen aber das
macht den Code für mich übersichtlicher.
Wenn du mal Codes mit 1/2 Mio Programmzeilen geschrieben hast (Der Code
des Designers zählt nicht), dann wirst du so was lieben.
In deine Fall bedeutet das : Er liest DA von der seriellen
Schnittstelle, und nicht "Wo verdammt liest der den jetzt schon wieder
was". ;)
Kleiner Nachtrag zum Debuggen.
Wenn du genau hinter der Zeile "Tx = Data_received" F9 drückst, kannst
du jedesmal die neuen Daten mitlesen, wenn du die Maus auf TX schiebst.
dann F5 und wieder die Maus auf TX. Und schon siehst du die nächsten
empfangenen Daten.
Mit "je" F8 kannst du nun Schritt für Schritt nachprüfen was der Code
mit den Empfangenen Daten macht.
Auch ein Vorteil meiner Art zu coden. ;)
Noch ein Nachtrag zum Dim-Befehl.
Der Dim-Befehl deklariert die Variablen und Array.
Aber man sollte ihn IMMER am Anfang einer Sub machen, NIE mittendrin.
Der Grund ist, das man dann eine Übersicht über seine Variablen hat. Ach
und noch was. Wenn du Codest sollest du dein Variablen Kennzeichnung.
Deshalb mag ich in den $ als Kennung. Alles was $ ist ist ein Text. Der
Rest ist was andere.
So, habe nun tx, lauf, und block deklariert...
Nun bringt der Code von Schlaumaier auch keine Fehler, aber leider
startet die Form beim Debuggen, und auch erstellt einfach nicht.
Musste
1
lauf = True : tx = ""
2
Do While lauf = True
3
If SerialPort1.IsOpen = True Then
4
Data_received = SerialPort1.ReadExisting
5
If Len(Data_received) > 0 Then
"If SerialPort1.IsOpen = True Then" ergänzen, da er sonst beim Debuggen
schreibt "Der Anschluss ist geschlossen"
Nun passiert überhaupt nichts mehr... beachtlicher weise, ohne jeglichen
Fehler.
Probeweise habe ich den Code von Schlaumaier erst in
TextBox1_Textchanged, und dann in Timer1 probiert...gleiches Ergebnis ->
Debugging bringt keinen Fehler, Form bleibt einfach zu. Habe mal den Log
vom Debugging angehängt.
Vielleicht sollte ich damit aber auch lieber einem VB Forum auf die
Nerven gehen? ;) Oder jemand findet meinen Fehler.
1
"RSTest.exe" (CLR v4.0.30319: DefaultDomain): "C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll" geladen. Das Laden von Symbolen wurde übersprungen. Das Modul ist optimiert, und die Debugoption "Nur eigenen Code" ist aktiviert.
2
(noch 10x die "Symbol übersprungen" Meldung)
3
Das Programm "[11584] RSTest.exe: Programmablaufverfolgung" wurde mit Code 0 (0x0) beendet.
4
Das Programm "[11584] RSTest.exe" wurde mit Code -1 (0xffffffff) beendet
Sk1 schrieb:> If SerialPort1.IsOpen = True Then> Data_received = SerialPort1.ReadExisting> Nun passiert überhaupt nichts mehr... beachtlicher weise, ohne jeglichen> Fehler.
Vermutlich weil nirgendwo vorher steht:
"Serialport1.Open"
Die if-Bedingung wird einfach nicht wahr.
Aber das sind Grundzüge der Programmierung, die sollte man eigentlich
selber rausfinden können.
Da der TO ja angeblich schon Daten empfangen hat bin ich davon
ausgegangen das er den Serial-Port korrekt initialisiert hat.
so z.b.
If S_Port.IsOpen Then
S_Port.Close() ' verhindert das ein Fehler auftritt wenn der Port
noch offen ist.
End If
S_Port.PortName = "COM10"
S_Port.BaudRate = 9600
S_Port.Open()
Das da ist übrigens aus den "Wie lese ich ein Arduino aus CODE von
mir".;)
Sk1 schrieb:> "If SerialPort1.IsOpen = True Then" ergänzen, da er sonst beim Debuggen> schreibt "Der Anschluss ist geschlossen">> Nun passiert überhaupt nichts mehr... beachtlicher weise, ohne jeglichen> Fehler.
Würde wetten, das wäre anders, wenn du den Port zu Beginn öffnen
würdest!?
Thomas F. schrieb:> Vermutlich weil nirgendwo vorher steht:> "Serialport1.Open">> Die if-Bedingung wird einfach nicht wahr.>> Aber das sind Grundzüge der Programmierung, die sollte man eigentlich> selber rausfinden können.Hauke Haien schrieb:> Würde wetten, das wäre anders, wenn du den Port zu Beginn öffnen> würdest!?
Der Port wird natürlich geöffnet. Mit Klick auf einen Button wird der
Port geöffnet, und Timer 1 startet.
Dazu gleich die nächste Beobachtung:
1
Data_received = SerialPort1.ReadExisting
funktioniert (nur werden die Daten eben nicht richtig dargestellt),
bei
1
Data_received = SerialPort1.ReadLine
friert die Form wieder ein, bzw öffnet beim Debugging nicht, auch
komplett ohne Fehlermeldung.
Komisch das ganze... es hat nicht zufällig jemand ein Projektbeispiel
mit einem solchen fertigen Puffer für SerialRead? Würde wahrscheinlich
schneller gehen, ein solches auseinander zu nehmen, und damit weiter zu
machen.
Sk1 schrieb:> Data_received = SerialPort1.ReadLine
Ist logisch.
Readline = LINE = Endzeichen erwartet
Mach ein Data_received = SerialPort1.Read(Anz_der_Zeichen)
Und das so:
dim lesen as boolean = true
Do while lesen = true
Data_received = SerialPort1.Read(Anz_der_Zeichen)
if len(Data_received)> 0 then
' mache was
end if
loop
Muss halt nur noch eine Abbruchbedingung haben, damit es sich nicht
tot_läuft.
Nachtrag :
Lies die mal alles durch was VB anzeigt wenn du
SerialPort1.R eingibst. Dann ist nämlich ein Auswahlmenü mit kurzen
Erklärungen auf. Da ich nicht genau weiß was du an Daten empfängst,
kann ich dir auch nicht sagen was du genau nehmen musst, und welche
Abbruchbedingung.
Siehe folgendes in der Hilfe.
SerialPort.ReadLine-Methode
Liest bis zum NewLine-Wert im Eingabepuffer.
SerialPort.NewLine-Eigenschaft
Ruft den Wert ab, mit dem das Ende eines Aufrufs der ReadLine-Methode
und der WriteLine-Methode interpretiert wird, oder legt diesen fest.
Ein Wert, der das Ende einer Zeile darstellt.
Der Standardwert ist ein Zeilenvorschub ( NewLine).
Einfach gesagt, erscheint da kein Zeilenvorschub, wartet der bis zum
sankt-nimmerleinstag auf Daten OHNE Timeout und Fehlermeldung.