Forum: PC-Programmierung [VBNET] TextBox Darstellung Serial Receive


von Sk1 (Gast)


Angehängte Dateien:

Lesenswert?

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

von cppbert (Gast)


Lesenswert?

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")

von Schlaumaier (Gast)


Lesenswert?

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.

von Sk1 (Gast)


Lesenswert?

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

von cppbert (Gast)


Lesenswert?

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

von Sk1 (Gast)


Lesenswert?

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.

von cppbert (Gast)


Lesenswert?

Such mal in google nach "vb.net variablen deklarieren"

von Schlaumaier (Gast)


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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". ;)

von Schlaumaier (Gast)


Lesenswert?

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. ;)

von Schlaumaier (Gast)


Lesenswert?

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.

von Sk1 (Gast)


Lesenswert?

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

Was mache ich bloß falsch?

von Thomas F. (igel)


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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".;)

von Schlaumaier (Gast)


Lesenswert?

Nachtrag :

Public Class form1  ' name der Form hier form1
  Dim S_Port As New IO.Ports.SerialPort



End class  'falls es nicht schon da steht

von Hauke Haien (Gast)


Lesenswert?

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!?

von Sk1 (Gast)


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.