Forum: PC-Programmierung [Visual Basic] Komischer Fehler beim empfangen eines Strings über COM


von Benji Bone (Gast)


Lesenswert?

Hallo.
Ich habe ein ein problem mit folgenden Programmteil:

Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As 
System.IO.Ports.SerialDataReceivedEventArgs) Handles 
SerialPort1.DataReceived

        Control.CheckForIllegalCrossThreadCalls = False
        Dim data, zwischen As String
        data = SerialPort1.ReadExisting()
        SerialPort1.DiscardInBuffer()

        'Empfangene Daten auswerten:
        If data.Contains("L1Value") Then
            data = data.Remove(0, 7)
            data = CInt(data)
            zwischen = data   'nur zum debuggen
            TrackBarL1.Value = data
            Label1.Text = data * 10 & " %"
        End If
     End Sub

Ich werte einen String aus der über die serielle SChnittstelle empfangen 
wird. Und zwar erstmal nur für ein Objekt, d.h. die If-Anweisung könnte 
man auch erstmal weglassen.

Das Problem ist nun folgendes:
Der String der empfangen wird lautet "L1Value" direkt gefolgt von einer 
Zahl 0 bis 10. Also z.B. L1Value9 oder L1Value10
Ich scheide dann L1Value vom String ab und weise die Zahl einem Label 
und Trackbar zu. Das klappt eigentlich ganz gut nur funktioniert es 
nicht richtig mit dem String "L1Value10"! data hat nach dem Scneiden den 
Wert 1!
Es funktioniert nur einmal wenn der erste String der nach dem 
programmstart gesendet wird "L1Value10" ist. Nur dann übernimmt das 
Programm die 10.

???

Ich verstehe das nicht. Bin auch noch Anfänger mit Visual Basic (2005)

von juppi (Gast)


Lesenswert?

Was passiert bei z.B. 11-21

"L1Value11"-"L1Value21"

von Philipp B. (philipp_burch)


Lesenswert?

Schalte mal in den Projektoptionen "Option Strict" auf "On", korrigiere 
alle Fehler und poste den Code noch mal. Möglicherweise funktioniert es 
dann bereits.
Zeilen à la "data = CInt(data)" sind jedenfalls relativ sinnfrei. Damit 
wandelst du den Inhalt des Strings "data" erstmals explizit in einen 
Integer um und gleich anschliessend implizit wieder in einen String.

von Mario R. (mario001) Benutzerseite


Lesenswert?

Du machst da einen "threadübergreifenden Zugriff", das bedeutet, diese 
Verarbeitungsroutine für die serielle Schnittstelle ist in einem anderen 
Thread beheimatet als das Steuerelement, auf das du die Werte zuweist.

Das klingt erstmal komisch, aber ich hatte ein ähnliches Problem auch 
schon mal und das generierte die verrücktesten Fehler. Setze mal 
"Control.CheckForIllegalCrossThreadCalls" auf True (oder kommentier die 
Zeile aus), und du wirst sehen dass VB bei der Ausführung da eine 
Exception wirft !!

Eine Lösung fand ich im MSDN, die sollte dir auch weiterhelfen:
-> http://msdn.microsoft.com/de-de/library/ms171728.aspx

Hth, Mario

von Benji Bone (Gast)


Lesenswert?

@juppi
>Was passiert bei z.B. 11-21

>"L1Value11"-"L1Value21"

Weiss nicht, kommt doch gar nicht vor dass ich was subtrahiere. ???

@Philipp
>Zeilen à la "data = CInt(data)" sind jedenfalls relativ sinnfrei. Damit
>wandelst du den Inhalt des Strings "data" erstmals explizit in einen
>Integer um und gleich anschliessend implizit wieder in einen String.

Aber wieso kann ich dem TrackBarL1.Value einen String zuweisen, wenn der 
doch als Integer definiert ist?

>"Option Strict" auf "On"
Was bedeutet das? Wo stelle ich das ein?

@Mario

Was soll es mir bringen den Wert wieder auf True zu setzen, außer dass 
es dann überhaupt nicht mehr geht?

von Mario R. (mario001) Benutzerseite


Lesenswert?

Wenn du die Option "CheckForIllegalCrossThreadCalls" auf False stellst, 
dann UNTERDRÜCKST du eine Fehlermeldung über einen unzulässigen Vorgang. 
Und offensichtlich hat dein Programm genau an der Stelle ein Problem !

Ich mach dir nen Vorschlag: Du schreibst dein Programm um, so wie ich's 
dir gleich zeige. Wenn es dann geht, gibste mir - virtuell - einen aus, 
wenn nicht, dann nehm ich alles zurück und behaupte das Gegenteil, ok ?

Also, mach das ganze mal so:
1
Private Sub DeineDatenEmpfangsRoutine(...)
2
3
  ' Folgende Zeile auskommentieren (Überprüfung an)      
4
  ' Control.CheckForIllegalCrossThreadCalls = False
5
6
  Dim data, zwischen As String
7
  data = SerialPort1.ReadExisting()
8
  SerialPort1.DiscardInBuffer()
9
10
  'Empfangene Daten auswerten:
11
  If data.Contains("L1Value") Then
12
13
    data = data.Remove(0, 7)
14
    data = CInt(data)
15
    zwischen = data   'nur zum debuggen
16
17
    'TrackBarL1.Value = data
18
    'Label1.Text = data * 10 & " %"
19
    ' das wird ersetzt durch:
20
    SetTrackBarAndLabel(data)
21
22
  End If
23
End Sub
24
25
' Delegate für SetTrackBarAndLabel (nötig für asynchrone Calls)
26
Delegate Sub SetTrackBarAndLabelCallback(data As String)
27
28
' Und hier die Sub, die threadsicher TrackBar und Label updatet
29
Private Sub SetTrackBarAndLabel(ByVal data As String)
30
31
  If TrackBarL1.InvokeRequired Then
32
    Dim d As New SetTrackBarAndLabelCallback(AddressOf SetTrackBarAndLabel)
33
    Me.Invoke(d, New Object() {data})
34
  Else
35
    TrackBarL1Value = data
36
    Label1.Text = data * 10 & " %"
37
  End If
38
39
End Sub

Eigentlich solltest du noch checken, ob "data" wirklich eine Zahl ist, 
bevor du es auf TrackBar und Label loslässt ...

Viel Erfolg, Mario

von Philipp B. (philipp_burch)


Lesenswert?

Benji Bone wrote:
> @Philipp
>>Zeilen à la "data = CInt(data)" sind jedenfalls relativ sinnfrei. Damit
>>wandelst du den Inhalt des Strings "data" erstmals explizit in einen
>>Integer um und gleich anschliessend implizit wieder in einen String.
>
> Aber wieso kann ich dem TrackBarL1.Value einen String zuweisen, wenn der
> doch als Integer definiert ist?

Es ist durch die implizite Konvertierung möglich. "data" wird in einen 
Integer umgewandelt und dann zugewiesen, aber du hast keine Kontrolle 
darüber. Ausserdem ist es einfach nicht schön.

>>"Option Strict" auf "On"
> Was bedeutet das? Wo stelle ich das ein?

"Option Strict On" bedeutet, dass sich der Code genau an die Regeln 
halten muss, implizite Konvertierungen und solche "Unschönheiten" werfen 
dann einen Fehler. Gibt zwar mehr Schreibarbeit, ist aber weniger 
fehleranfällig. Die Einstellung findest du unter 
Project->Options->Compiler oder sowas...

von Benji Bone (Gast)


Lesenswert?

@Mario

Ich habe deinen Code mal eingefügt, aber es funktioniert immer noch 
nicht richtig. :-( Schade, ich hätte dir sehr gerne einen ausgegeben...
Was mir auffällt ist, dass das Programm anscheinend nur die erste Ziffer 
nach "L1Value" beachtet. Ich kann nämlich anhängen was ich will, ohne 
dass es Auswirkungen hat. Ich schicke z.B. "L1Value89384" dann geht die 
TrackBar auf 8 bzw. Label: 80%, bei "L1Value10000" oder "L1Value18373" 
auf 1 bzw. Label: 10%.

???

von Mario R. (mario001) Benutzerseite


Lesenswert?

Schade, hätte wetten können dass es das ist ! Zumal du sagst, dass es 
beim ersten Mal immer klappt ...

Versuch doch mal das Problem weiter einzukreisen und finde raus, welcher 
Befehl nicht das tut was er soll.

von Benji Bone (Gast)


Lesenswert?

Ich habe das Problem mit

data = SerialPort1.ReadLine()

gelöst. Am Ende des Strings muss man noch ein LF dran hängen und schon 
klappts. :-)

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.