Forum: PC-Programmierung VB Serial Port Datenempfang nicht komplett


von Alexander A. (alex0815)


Angehängte Dateien:

Lesenswert?

Hi,

ich habe mir eine Form in VB gebastelt in der ich die Serielle 
Schnittstelle auswerte.
Dort kommen Daten von einem Mikrocontroller rein.
Das komische ist, dass der Mikrocontroller circa 250 mal eine Zeile 
sendet die in ca. so aussieht "11|22|33|44\r\n", mein VB Projekt aber 
bei 158 empfangenen Zeilen immer Schluss macht!
Mit einem Terminal Programm welches wie Bild 1 eingestellt ist, klappt 
die komplette Übertragung!

Ich hatte den Fehler erst woanders gesucht, diesen Vorgang und andere 
Einstellwerte sieht man noch in diesem 
Thread:Beitrag "Ethernet - Serielle Verbindung"
Aber offensichtlich, da es ja im Terminal klappt, liegt der Fehler 
womöglich in VB Projekt...

Kann mir einer sagen was ich da Falsch machen?!?

Hier der Code des VB-Projekts:
1
Public Class Form1
2
    Dim SerialInput As String = ""
3
4
5
6
7
8
9
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
10
11
        '   SerialPort1.PortName = "COM4"
12
        '   SerialPort1.BaudRate = 9600
13
        '   SerialPort1.Parity = IO.Ports.Parity.None
14
        '   SerialPort1.DataBits = 8
15
        '   SerialPort1.StopBits = IO.Ports.StopBits.One
16
        '    SerialPort1.Handshake = IO.Ports.Handshake.None
17
        ' SerialPort1.RtsEnable = True
18
        SerialPort1.Open()
19
20
        If SerialPort1.IsOpen Then
21
            Label1.Text = "...verbunden"
22
            SerialPort1.Write("11|22|33|44" + Chr(13))
23
        Else
24
            Label1.Text = "...getrennt"
25
        End If
26
    End Sub
27
28
   
29
30
31
32
    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
33
34
35
        SerialInput = SerialPort1.ReadLine()
36
        Me.Invoke(New EventHandler(AddressOf DoUpdate))
37
38
39
    End Sub
40
41
    Public Sub DoUpdate()
42
43
        ListBox1.Items.Insert(0, "Recv: " & SerialInput)
44
        TextBox1.Text = TextBox1.Text + 1
45
46
    End Sub
47
48
49
50
    Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
51
        SerialPort1.Write(TextBox5.Text & Convert.ToChar(13) & Chr(13))
52
    End Sub
53
54
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
55
        ListBox1.Items.Clear()
56
        TextBox1.Text = 0
57
    End Sub
58
59
    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
60
        If SerialPort1.IsOpen = True Then
61
            SerialPort1.Close()
62
        End If
63
64
        Me.Close()
65
66
    End Sub
67
68
End Class

von Peter II (Gast)


Lesenswert?

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

das ist schon mal unsinn. Du kannst du nicht im demn Event mehr daten 
empfangen als vorhanden sind.

von Jonas B. (jibi)


Lesenswert?

Du musst die Abarbeitung asynchron machen->eigenen Thread starten 
dafür...

von Peter II (Gast)


Lesenswert?

Jonas Biensack schrieb:
> Du musst die Abarbeitung asynchron machen->eigenen Thread starten
> dafür...

nein muss er nicht, er musst die daten bei dem event nur sammeln.

von Alexander A. (alex0815)


Lesenswert?

Peter II schrieb:
> das ist schon mal unsinn. Du kannst du nicht im demn Event mehr daten
> empfangen als vorhanden sind.

Warum genau ist das Unsinn?
Wie kann ich es besser machen?

Ich kann es auch direkt ohne Zwischenvariable schreiben, jedoch macht 
das keine Unterschied!
1
    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
2
        Me.Invoke(New EventHandler(AddressOf DoUpdate))
3
    End Sub
4
5
    Public Sub DoUpdate()
6
7
        ListBox1.Items.Insert(0, "Recv: " & SerialPort1.ReadLine())
8
        TextBox1.Text = TextBox1.Text + 1
9
10
    End Sub

von bluppdidupp (Gast)


Lesenswert?

Alexander Alexander schrieb:
> Warum genau ist das Unsinn?

.ReadExisting statt .ReadLine wäre sinnvoller.
Im DataReceived-Event muss nicht zwingend bereits ein Zeilenende 
empfangen worden sein und dann würde ReadLine() den Event-Handler 
blockieren. (Ob das nun schlimm ist oder nicht sei dahin gestellt)

von Alexander A. (alex0815)


Lesenswert?

Aber gehen wir mal davon aus, dass ich immer ein Zeilenende habe. Merke 
ich alleine schon daran, dass wenn ich die ersten Sendestrings auf 
Mikrocontroller Seite entferne, macht er trotzdem 158. Also geht dann 
ein bischen weiter in der Liste...
Wie kriege ih denn ein Zeilenende mit ReadExisting mit?!?

Das ist doch mal wieder ein kack Fehler...

von Karl H. (kbuchegg)


Lesenswert?

Alexander Alexander schrieb:
> Aber gehen wir mal davon aus, dass ich immer ein Zeilenende habe. Merke
> ich alleine schon daran, dass wenn ich die ersten Sendestrings auf
> Mikrocontroller Seite entferne, macht er trotzdem 158. Also geht dann
> ein bischen weiter in der Liste...
> Wie kriege ih denn ein Zeilenende mit ReadExisting mit?!?

Indem du dir ansiehst, was von der Seriellen auf PC Seite alles 
herauspurzelt. Wenn da ein Carriage Return dabei ist, dann war alles 
davor eine Zeile. Wenn da nur ein einsames '1' herauspurzelt, dann wurde 
eben bis zu dem Zeitpunkt an dem du die Serielle befragst nur dieses 
eine Zeichen übertragen und der Rest kommt später.

von Alexander A. (alex0815)


Lesenswert?

Mit ReadExisting liest er alles ein, genau wie das Terminal Programm das 
ordentlich der Zeile nach einliest!

Ich verstehe nur nicht warum das ReadLine nicht richtig macht? Hinter 
jedem Sendebefehl im Mikrocontroller ist ein Return:

Ich habe gerade diese Zeile 400mal kopiert:

usart_writePC ("89|25|01|01\r\n");
usart_writePC ("89|25|01|01\r\n");
usart_writePC ("89|25|01|01\r\n");
usart_writePC ("89|25|01|01\r\n");
...
...

Trotzdem hört er jetzt nach 195-200 Zeilen auf

von Karl H. (kbuchegg)


Lesenswert?

Alexander Alexander schrieb:
> Mit ReadExisting liest er alles ein, genau wie das Terminal Programm das
> ordentlich der Zeile nach einliest!
>
> Ich verstehe nur nicht warum das ReadLine nicht richtig macht?

Ich schätze mal, dass das ReadLine ins Timeout laufen wird.

> Hinter
> jedem Sendebefehl im Mikrocontroller ist ein Return:

Alles schön und gut.
Aber der Event wird ausgelöst, sobald das erste Zeichen im PC 
eintrudelt. Da hat dein µC den Return noch gar nicht weggeschickt.

Du scheinst in der Annahme zu leben, dass irgendwie instantan im PC der 
komplette String "89|25|01|01\r\n" auftaucht, sobald du auf µC Seite 
einen

> usart_writePC ("89|25|01|01\r\n");

aufrufst.
Dem ist nicht so. Die Übertragung braucht ja auch Zeit und geht Zeichen 
für Zeichen.

von Alexander A. (alex0815)


Lesenswert?

Also würdest Du mir auch raten dort ein ReadExisting zu nehmen und dann 
abzufragen wenn ein CR kommt war das bis zum letzten CR eine Zeile!?!??

von Karl H. (kbuchegg)


Lesenswert?

> usart_writePC ("89|25|01|01\r\n");
> ...
> ...
>
> Trotzdem hört er jetzt nach 195-200 Zeilen auf

Tipp: schick nicht immer dieselbe Zeile. Sorge dafür, dass sich da etwas 
systematisch verändert und wenn es nur ein Zähler ist der hochzählt.
Dann kannst du am PC nämlich auch feststellen, ob dir nicht 
zwischendurch ein paar Zeilen flöten gegangen sind und dieses 'aufhören' 
völlig zu recht erfolgt ist, weil tatsächlich nichts mehr kommt.

von Alexander A. (alex0815)


Lesenswert?

Normalerweise sind das auch alles andere Werte, aber alle Querbet, nicht 
fortlaufend oder so.... Wie soll ich das denn auswerten?!

...
if (StatusByteSteck5&0b00000100)usart_writePC ("83|13|03|01\r"); else 
usart_writePC ("83|13|03|00\r");
if (StatusByteSteck5&0b00001000)usart_writePC ("83|13|04|01\r"); else 
usart_writePC ("83|13|04|00\r");
if (StatusByteSteck6&0b00000001)usart_writePC ("83|14|01|01\r"); else 
usart_writePC ("83|18|01|00\r");
if (StatusByteSteck6&0b00000010)usart_writePC ("83|14|02|01\r"); else 
usart_writePC ("83|18|02|00\r");
if (StatusByteSteck6&0b00001000)usart_writePC ("83|15|01|01\r"); else 
usart_writePC ("83|15|01|00\r");
if (StatusByteSteck6&0b00010000)usart_writePC ("83|15|02|01\r"); else 
usart_writePC ("83|15|02|00\r");
if (StatusByteSteck6&0b00100000)usart_writePC ("83|15|03|01\r"); else 
usart_writePC ("83|16|03|00\r");
if (StatusByteSteck6&0b01000000)usart_writePC ("83|15|04|01\r"); else 
usart_writePC ("83|16|04|00\r");
if (StatusByteSteck6&0b10000000)usart_writePC ("83|15|05|01\r"); else 
usart_writePC ("83|15|05|00\r");
....

von Karl H. (kbuchegg)


Lesenswert?

Alexander Alexander schrieb:
> Normalerweise sind das auch alles andere Werte, aber alle Querbet, nicht
> fortlaufend oder so.... Wie soll ich das denn auswerten?!

Ich denke im Moment geht es darum die PC Seite korrekt hinzukriegen, 
oder nicht?

Wer oder was hindert dich daran, in deinen µC ein Programm zu brennen

  for( i = 0; i < 99; i++ )
    for( j = 0; j < 99; j++ )
      for( k = 0; k < 99; k++ )
        for( l = 0; l < 99; l++ )
        {
          sprintf( str, "%02d|%02d|%02d|%02d\r", i, j, k, l );
          usart_writePC( str );
        }

damit debuggst du erst mal die PC-Seite Empfangsroutine und wenn da dann 
alles korrekt ist, dann kannst du deinen richtigen Code wieder auf den 
PC hetzen.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Wer oder was hindert dich daran, in deinen µC ein Programm zu brennen

Humpf.
4-mal ineinander geschachtelt bis 100 ist vielleicht ein bischen viel. 
Das könnte dauern.
einmal bis 3 und einmal bis 100 tuts auch.

von Alexander A. (alex0815)


Angehängte Dateien:

Lesenswert?

Also mein Terminal empfängt die Schleife richtig...dauert ewig;-)

Mein VB Projekt empfängt garnichts, wenn ich meine Form schliesse, kommt 
die Fehlermeldung (s. Bild 1)

Was macht das Terminal besser als ich?!?!? ;-)

VB Code:
1
Imports System.IO.Ports
2
3
4
5
Public Class Form1
6
    Dim SerialInput As String = ""
7
8
9
10
11
12
13
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
14
15
        SerialPort1.PortName = "COM4"
16
        SerialPort1.BaudRate = 9600
17
        SerialPort1.Parity = IO.Ports.Parity.None
18
        SerialPort1.DataBits = 8
19
        SerialPort1.StopBits = IO.Ports.StopBits.One
20
        SerialPort1.Handshake = IO.Ports.Handshake.None
21
        SerialPort1.RtsEnable = False
22
        SerialPort1.DtrEnable = False
23
        SerialPort1.Open()
24
25
        If SerialPort1.IsOpen Then
26
            Label1.Text = "...verbunden"
27
            SerialPort1.Write("11|22|33|44" + Chr(13))
28
        Else
29
            Label1.Text = "...getrennt"
30
        End If
31
    End Sub
32
33
34
35
36
37
    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
38
39
40
41
            SerialInput = SerialPort1.ReadLine()
42
43
44
45
46
            Me.Invoke(New EventHandler(AddressOf DoUpdate))
47
48
    End Sub
49
50
51
52
53
54
    Public Sub DoUpdate()
55
56
57
58
        ListBox1.Items.Insert(0, "Recv: " & SerialInput)
59
        TextBox1.Text = TextBox1.Text + 1
60
61
    End Sub
62
63
64
65
    Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
66
        SerialPort1.Write(TextBox5.Text & Convert.ToChar(13) & Chr(13))
67
    End Sub
68
69
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
70
        ListBox1.Items.Clear()
71
        TextBox1.Text = 0
72
    End Sub
73
74
    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
75
        If SerialPort1.IsOpen = True Then
76
            SerialPort1.Close()
77
        End If
78
79
        Me.Close()
80
81
    End Sub
82
83
End Class

von Peter II (Gast)


Lesenswert?

Alexander Alexander schrieb:
> Mein VB Projekt empfängt garnichts, wenn ich meine Form schliesse, kommt
> die Fehlermeldung (s. Bild 1)

steht doch alles da - es hängt in ReadLine während du versucht das 
Programm zu beenden.

entweder du verwendest einen Thread mit ReadLine oder du verwendest 
ReadExisting. Aber wie du es machst geht es nun mal nicht.

von Karl H. (kbuchegg)


Lesenswert?

Und ich würd mich auch mal mit mir selbst einigen, ob ich jetzt vom µC 
aus ein \r, ein \n oder ein \r\n wegschicke.

(Keine Ahnung wie Readline die Sache handhabt)

von Alex (Gast)


Lesenswert?

> entweder du verwendest einen Thread mit ReadLine oder du verwendest
> ReadExisting. Aber wie du es machst geht es nun mal nicht.

Wie geht das mit den Thread? Kenn ich noch nicht...

von Peter II (Gast)


Lesenswert?

Alex schrieb:
> Wie geht das mit den Thread? Kenn ich noch nicht...

dann macht es auch nicht damit, ein thread ereugt erstmal noch mehr 
probleme als Lösungen.

mach einfach

String Data;

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

Data += SerialPort1.ReadExisting()

int pos = Data.IndexOf('\n');
if ( pos >= 0 ) {
   String meineDaten = Data.Substring(0, pos );
   //verarbeite meineDaten
   Data = Data.Substring( pos, Data.length-pos );
}

von Alex (Gast)


Lesenswert?

Probier ich morgen mal aus! Danke.

von Steffen H. (avrsteffen)


Lesenswert?

Hallo

Ich würde auch gerne mal wieder ein wenig in Delphi programmieren. Vor 
allem Kommunikation via Serial-Ports!

Ich habe noch eine Delphi6 CD + Buch da Heim. Die ist von 2004 oder so. 
Bei welcher Version ist man denn jetzt? Und ist Delphi Software frei 
verfügbar im Internet erhältlich?


Gruß Steffen

von bluppdidupp (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> (Keine Ahnung wie Readline die Sache handhabt)
Was ReadLine als Zeilenende nimmt, kann man einstellen via 
SerialPort.NewLine-Eigenschaft

von Alex (Gast)


Lesenswert?

bluppdidupp schrieb:
> Karl Heinz Buchegger schrieb:
>> (Keine Ahnung wie Readline die Sache handhabt)
> Was ReadLine als Zeilenende nimmt, kann man einstellen via
> SerialPort.NewLine-Eigenscha

Guter Tip, danke!

von Alexander A. (alex0815)


Lesenswert?

Peter II schrieb:
> String Data;
>
> Private Sub SerialPort1_DataReceived(ByVal sender As System.Object,
> ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles
> SerialPort1.DataReceived
>
> Data += SerialPort1.ReadExisting()
>
> int pos = Data.IndexOf('\n');
> if ( pos >= 0 ) {
>    String meineDaten = Data.Substring(0, pos );
>    //verarbeite meineDaten
>    Data = Data.Substring( pos, Data.length-pos );
> }

Hi,

ich programmiere mit Visual Basic 2010 mit "String Data" kann ich leider 
nichts anfangen. Wie sieht das in VB aus?!?!?

von Peter II (Gast)


Lesenswert?

Alexander Alexander schrieb:
> Hi,
> ich programmiere mit Visual Basic 2010 mit "String Data" kann ich leider
> nichts anfangen. Wie sieht das in VB aus?!?!?

etwas mitdenken musst du schon. Das soll einfach eine Variabel vom Typ 
String sein.

Warum tut man sich überhaupt freiwillig VB an, wenn es doch C# gibt?

von Karl H. (kbuchegg)


Lesenswert?

Alexander Alexander schrieb:
> Peter II schrieb:
>> String Data;
>>
>> Private Sub SerialPort1_DataReceived(ByVal sender As System.Object,
>> ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles
>> SerialPort1.DataReceived
>>
>> Data += SerialPort1.ReadExisting()
>>
>> int pos = Data.IndexOf('\n');
>> if ( pos >= 0 ) {
>>    String meineDaten = Data.Substring(0, pos );
>>    //verarbeite meineDaten
>>    Data = Data.Substring( pos, Data.length-pos );
>> }
>
> Hi,
>
> ich programmiere mit Visual Basic 2010 mit "String Data" kann ich leider
> nichts anfangen. Wie sieht das in VB aus?!?!?

String    ist der Datentyp
Data      ist der Name der Variablen

Bei dir dann wohl

   Dim Data As String = ""


Bitte in bischen mitdenken, wie wohl
1
  Data += SerialPort1.ReadExisting()
2
3
  int pos = Data.IndexOf('\n');
4
  if ( pos >= 0 ) {
5
     String meineDaten = Data.Substring(0, pos );
6
     //verarbeite meineDaten
7
     Data = Data.Substring( pos, Data.length-pos );
8
  }
arbeitet. Das ist nach all dem Vorgeplänkel wirklich nicht schwer zu 
verstehen.

von Alexander A. (alex0815)


Lesenswert?

Hallo,

ich habe des jetzt mal ausprovbiert und komme nicht darauf wofür das
 meineDaten = s.Substring(0, pos)

ist?!?!

Was soll das bringen?


Leider kommt so garnichts auf die Anzeige
1
    Dim SerialInput As String = ""
2
3
4
    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
5
        Dim pos As Integer
6
        Dim meineDaten As String
7
8
        SerialInput += SerialPort1.ReadExisting()
9
10
        pos = SerialInput.IndexOf(vbCr)
11
12
        If (pos >= 0) Then
13
            meineDaten = s.Substring(0, pos)
14
            'verarbeite meineDaten
15
            SerialInput = SerialInput.Substring(pos, SerialInput.Length - pos)
16
        End If
17
18
    End Sub

von Alexander A. (alex0815)


Angehängte Dateien:

Lesenswert?

Da passt irgendetwas nicht, wenn ich selbst nach | filter, gibt er mir 
als Länge 16 raus und bei Position 2.

Mit  pos = SerialInput.IndexOf(vbCr) gibt er als erste Länge 56 raus...
Alles murks...

von Karl H. (kbuchegg)


Lesenswert?

Alexander Alexander schrieb:
> Hallo,
>
> ich habe des jetzt mal ausprovbiert und komme nicht darauf wofür das
>  meineDaten = s.Substring(0, pos)
>
> ist?!?!
>
> Was soll das bringen?


OK. Du bist der Computer und ich die Gegenstelle. Ich schicke dir

 "86|2"

bzw. das ist das, was im UART Empfangsbuffer vorliegt, wenn dein Message 
Handler mittels ReadExisting die Finger an die empfangenen Daten kriegt.

Was machst du damit?
Noch gar nichts. Da ist noch kein \n enthalten, daher kannst du noch 
nichts damit anfangen. Die Daten werden einfach mal in der Variablen 
zwischengespeichert, wo sie vor sich rumlungern, bis das nächste mal 
Windows meldet: Ich hab was an der Seriellen für dich.

Gut. Die Zeit vergeht und als nächstes trudelt ein

  "5|01|"

das hängst du an das bisher empfangene hinten drann. D.h. bisher hast du 
empfangen

  "86|25|01|"

kannst du damit was anfangen?
Nein. Immer noch kein \n weit und breit. D.h. der zusammengestückelte 
String lungert weiter vor sich hin in der Variablen 'Data' und wartet 
drauf, dass von der Seriellen noch was kommt.

Dauert auch nicht lange und Windows meldet wieder, dass es Daten an der 
UART zur gefälligen Entgegennahme für dich hätte.
Aus ReadExisting kriegst du raus

   "01\r\n89|"

Das wird wieder an das bisher empfangene hinten drann gehängt, sodass in 
Data jetzt steht

  "86|25|01|01\r\n89|"

Kannst du damit was anfangen?
Ja! Jetzt kannst du damit was anfangen. Hier

  "86|25|01|01\r\n89|"
                 ^
                 |
                 |

ist der \n, der das Ende der Zeile markiert. Um also an die Zeile zu 
kommen, brauchst du diesen

  "86|25|01|01\r\n89|"
   |             |
   |             |
   +-------------+

Teil des Strings. Das ist deine Zeile.
Und das was dann noch in Data übrig bleibt, das ist schon wieder der 
Anfang der nächsten Zeile. D.h. du schneidest dir genau diesen Teil aus 
Data raus

  "86|25|01|01\r\n"

und anschliessend stutzt du Data so zurecht, dass der rausgeschnittene 
Teil da drinnen nicht mehr vorkommt

  "89|"

und wenn dann die nächsten Daten eintrudeln

     "25|01|05"

dann werden die, alles wie gehabt, wieder hinten an Data drann gehängt

  "89|25|01|05"

und alles geht weiter seinen gewohnten Gang.


So. Und jetzt geh nochmal den Code durch, den du gekriegt hast und 
studier den nochmal, ob du diese Operationen da drinnen wiederfindest.

von Karl H. (kbuchegg)


Lesenswert?

>         pos = SerialInput.IndexOf(vbCr)
>
>        If (pos >= 0) Then
>            meineDaten = s.Substring(0, pos)


mal scharf überlegen: kann s hier die richtige Variable sein?

von Alex (Gast)


Lesenswert?

Dim SerialInput As String = ""


    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, 
ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles 
SerialPort1.DataReceived
        Dim pos As Integer
        Dim meineDaten As String


        SerialInput += SerialPort1.ReadExisting()
> Hier wird das SerialInput jedesmal mit ReadExisting Erweitert und nicht 
>überschrieben.
        pos = SerialInput.IndexOf(vbCr)
> Hier wird geguckt auf welcher Postiion sich ein CarriageReturn ("\r" >oder doch 
beides? "\r\n") befindet
        If (pos >= 0) Then
> Wenn ein CR gefunden
            meineDaten = SerialInput .Substring(0, pos)
> Zeigt den Ersten String bis zum CR an, aber nur den ersten...86|25|01|01
>            'verarbeite meineDaten
            SerialInput = SerialInput.Substring(pos, SerialInput.Length 
- pos)
> hier würde jetzt auch immer der String stehen der vom letzten bis zum aktuellen 
gefundenen CR steht.
        End If

Ist doch so richtig, oder? Wofür ist dann meineDaten = SerialInput 
.Substring(0, pos) ???

    End Sub

von Peter II (Gast)


Lesenswert?

Alex schrieb:
> Ist doch so richtig, oder? Wofür ist dann meineDaten = SerialInput
> .Substring(0, pos) ???

das kann doch nicht so schwer sein, versteht du überhaupt was du machst? 
Das ist Deine Daten auf die du gewartest hast und die jetzt verarbeitet 
werden können.

von Karl H. (kbuchegg)


Lesenswert?

Alex schrieb:

> Ist doch so richtig, oder? Wofür ist dann meineDaten = SerialInput
> .Substring(0, pos) ???


Weil du nach dem finden des CR in SerialInput DIESEN Fall vorliegen 
haben kannst

  "86|25|01|01\r\n89|"

Da ist deine Zeile drinnen, schon richtig. Aber da ist auch mehr als 
diese eine Zeile drinnen! (wenn du mal genau schauen würdest)

Du musst dich endlich von der Vorstellung lösen, dass du von der 
Seriellen wieder deine Zeilenstruktur kriegst, so wie du das gewohnt 
warst bzw. so wie du das am µC wegschickst.

DEM IST NICHT SO!

Von der Seriellen kommen Bytes rein. Und zwar aus Sicht des Handlers 
eines oder MEHRERE auf einmal. Je nachdem wie Windows gerade Zeit hatte 
den UART Puffer auszuleeren, bzw. je nachdem ob dein Programm Zeit hatte 
sofort auf die Benachrichtigung von Windows zu reagieren.
Und es ist deine Aufgabe dir aus dem Bytestrom wieder die Zeilen, die du 
brauchst, rauszuholen. Nur dann musst du aber auch wirklich irgendwann 
mal aus dem empfangenen Bytestrom die dich interessierende Zeile 
rausholen! Und zwar ohne dass du irgendwelche Annahmen triffst, was 
alles in der Zwischenzeit sich in deinem Buffer angesammelt hat. Du 
kannst nicht davon ausgehen, dass nur und ausschliesslich die Bytes 
einer einzigen Zeile in deinem Buffer stehen, wenn du dir mit 
ReadExisting die nächsten Daten holst. Das mag manchmal so sein, aber du 
hast keine Garantie dafür. Also triff auch nicht diese Annahme.

von Karl H. (kbuchegg)


Lesenswert?

>             meineDaten = SerialInput .Substring(0, pos)
>    Zeigt den Ersten String bis zum CR an,

Was heißt hier 'zeigt an'. Da wird überhaupt nichts angezeigt. Aus dem 
empfangenen Bytestrom wird der Teil rauskopiert, der einer Zeile 
entspricht (weil pos ja anzeigt, wo der \n ist).

was dann damit weiter passiert, ob das auf eine Anzeige geht oder ob das 
in einem File gespeichert wird oder ... das interessiert hier nicht. 
meineDaten ist eine Variable und was immer mit deren Inhalt weiter 
passiert, das passiert. Aber das interessiert ja den Empfangscode nicht.

von Alex (Gast)


Lesenswert?

Danke für deine Antworten und Entschuldigung wenn  ich nicht so schlau 
bin wie Du auf dem Gebiete der Programmierung!

Wofür brauche ich genau:

meineDaten = SerialInput .Substring(0, pos)

Wenn ich vom Mikrocontroller ein solchen String senden:

11|22|33|44\r\n55|66|77|88\r\n99|00|12|23\r\n34|45|56|78\r\n


steht in  meineDaten dann:

11|22|33|44
wenn die nächste pos gefunden:
11|22|33|4455|66|77|88
wenn die nächste pos gefunden
11|22|33|4455|66|77|8899|00|12|23
wenn die nächste pos gefunden
11|22|33|4455|66|77|8899|00|12|2334|45|56|78

Das brauche ich doch nicht...?

Ich verstehe das nicht?!

von Karl H. (kbuchegg)


Lesenswert?

Alex schrieb:
> Danke für deine Antworten und Entschuldigung wenn  ich nicht so schlau

> Wenn ich vom Mikrocontroller ein solchen String senden:
>
> 11|22|33|44\r\n55|66|77|88\r\n99|00|12|23\r\n34|45|56|78\r\n
>
>
> steht in  meineDaten dann:
>
> 11|22|33|44
> wenn die nächste pos gefunden:
> 11|22|33|4455|66|77|88

nö.

meine Daten wird ja überschrieben
Beim nächsten mal steht
55|66|77|88

drinnen.

> wenn die nächste pos gefunden
> 11|22|33|4455|66|77|8899|00|12|23

nö
99|00|12|23

> wenn die nächste pos gefunden
> 11|22|33|4455|66|77|8899|00|12|2334|45|56|78

nö
34|45|56|78

> Das brauche ich doch nicht...?

Du wolltest doch die Zeilen einzeln haben!

Hier
  SerialInput = SerialInput.Substring(pos,
                                      SerialInput.Length - pos)

wird aus dem empfangenen der Teil, der mittels meineDaten 
zurückgeliefert wurde, vorne rausgeschnitten.
Nachdem
  11|22|33|44
nach meineDaten kopiert wurde, wird aus 11|22|33|4455|66|77|88 der 
Anfang entfernt, so dass danach nur noch 55|66|77|88 für den nächsten 
Aufruf übrig bleibt. Beim nächsten mal kann daher gar nicht mehr
11|22|33|4455|66|77|88
in meineDaten geliefert werden, weil der Teil 11|22|33|44 in SerialInput 
schon längst nicht mehr drinnen steht!

von Karl H. (kbuchegg)


Lesenswert?

Alex schrieb:
> Danke für deine Antworten und Entschuldigung wenn  ich nicht so schlau
> bin wie Du auf dem Gebiete der Programmierung!


Das hat mit schlau nichts zu tun.

Schnapp dir Papier und Bleistift und spiele Computer.
Denk dir eine Abfolge von Zeichen aus, wie sie bei mehreren Aufrufen der 
Funktion aus ReadExisting herauskommen können und arbeite jedesmal den 
Code durch.

Dein Computer macht letzten Endes auch nichts anderes.

Das

  11|22|33|44\r\n55|66|77|88\r\n99|00|12|23\r\n34|45|56|78\r\n

ist das, was dein µC sendet.
Jetzt nimm an, dass aus dem PC folgendes passiert

die SerialPort1_DataReceived wird aufgerufen
   ReadExisting liefert     11|22|3

die SerialPort1_DataReceived wird aufgerufen
   ReadExisting liefert     3|44\r\n55

die SerialPort1_DataReceived wird aufgerufen
   ReadExisting liefert     |66|77|88\r\n

die SerialPort1_DataReceived wird aufgerufen
   ReadExisting liefert     99|00|1

die SerialPort1_DataReceived wird aufgerufen
   ReadExisting liefert     2|23\r

die SerialPort1_DataReceived wird aufgerufen
   ReadExisting liefert     \n34|45|45|78\r\n


gehs nicht im Kopf durch sondern schnapp dir Papier und Bleistift und 
schreib dir auf welche Variablen welche Werte haben. Und ansonsten 
machst du genau das (und nur das), was im Programmtext steht.

Wenn dus dann immer noch nicht hast, dann kann ich dir nur noch raten, 
dir ein anderes Hobby zu suchen.

von Karl H. (kbuchegg)


Lesenswert?

Und PS

Du solltest dir vielleicht mal ansehen, was eigentlich die Funktion 
Substring macht!
So wie das für mich aussieht, hast du eine falsche Vorstellung davon, 
was die tut.

von Alex (Gast)


Lesenswert?

Mich hat die 0 bei der Startposition des Substringes verwirt. Deswegen 
bin ich durcheienander gekommen!

meineDaten = SerialInput .Substring(0, pos)

Jetzt habe ich es aber verstanden.

Danke

von Alexander A. (alex0815)


Angehängte Dateien:

Lesenswert?

Ich habe es nocheinmal mit diesem Code ausprobiert und da kommt, so wie 
ich schon vermutete habe, nicht das richtig raus:
1
Public Class Form1
2
3
    Dim meineDaten As String
4
5
    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
6
        Dim pos As Integer
7
        Dim SerialInput As String
8
9
        SerialInput = SerialPort1.ReadExisting()
10
11
        pos = SerialInput.IndexOf(vbCr)
12
13
        If (pos >= 0) Then
14
            meineDaten = SerialInput.Substring(0, pos)
15
            'verarbeite meineDaten
16
            SerialInput = SerialInput.Substring(pos, SerialInput.Length - pos)
17
            Me.Invoke(New EventHandler(AddressOf DoUpdate))
18
        End If
19
20
    End Sub
21
22
    Public Sub DoUpdate()
23
        ListBox1.Items.Insert(0, "Recv: " & meineDaten)
24
        TextBox1.Text = TextBox1.Text + 1
25
26
    End Sub
27
End Class

auf dem Mikro:
1
 for( uint16_t i = 0; i < 4; i++ )
2
3
    for( uint16_t j = 0; j < 4; j++ )
4
5
    for( uint16_t k = 0; k < 4; k++ )
6
    
7
      for( uint16_t l = 0; l < 4; l++ )
8
      {
9
      sprintf( str, "%02d|%02d|%02d|%02d\r", i, j, k, l );
10
      usart_write_str0(str);
11
      }
12
      
13
  usart_write_str0(test);

Ausgabe in der Listbox siehe Anhang.

von Alexander A. (alex0815)


Lesenswert?

Schreibfehler

war:
SerialInput = SerialPort1.ReadExisting()

muss sein:
SerialInput += SerialPort1.ReadExisting()

von bluppdidupp (Gast)


Lesenswert?

Du wirfst Daten weg, wenn kein CR im DataReceived-Aufruf dabei ist ;D

Ungetesteter (keine VB.net-Kenntnisse) Änderungsvorschlag:
1
Dim SerialInput As String
2
Dim eineZeile As String
3
4
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
5
  Dim pos As Integer
6
7
  // Daten an SerialInput dranhängen, statt SerialInput zu überschreiben
8
  SerialInput = SerialInput + SerialPort1.ReadExisting()
9
10
  pos = SerialInput.IndexOf(vbCr)
11
  If (pos >= 0) Then
12
    eineZeile = SerialInput.Substring(0, pos)
13
    'verarbeite meineDaten
14
    SerialInput = SerialInput.Substring(pos, SerialInput.Length - pos)
15
    Me.Invoke(New EventHandler(AddressOf DoUpdate))
16
  End If
17
18
End Sub
19
20
Public Sub DoUpdate()
21
  ListBox1.Items.Insert(0, "Recv: " & eineZeile)
22
  TextBox1.Text = TextBox1.Text + 1
23
24
End Sub

von Alexander A. (alex0815)


Angehängte Dateien:

Lesenswert?

Da hatten wir ne Doppelpost...sorry. Damit bekomme ich dann 
komischerweise folgende Anzeige!
1
    Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
2
        Dim pos As Integer
3
4
5
6
        '' Daten an SerialInput dranhängen, statt SerialInput zu überschreiben
7
        SerialInput = SerialInput + SerialPort1.ReadExisting()
8
9
        pos = SerialInput.IndexOf(vbCr)
10
        If (pos >= 0) Then
11
            eineZeile = SerialInput.Substring(0, pos)
12
            'verarbeite meineDaten
13
            SerialInput = SerialInput.Substring(pos, SerialInput.Length - pos)
14
            Me.Invoke(New EventHandler(AddressOf DoUpdate))
15
        End If
16
17
18
    End Sub
19
20
    Public Sub DoUpdate()
21
        ListBox1.Items.Insert(0, "Recv: " & eineZeile)
22
        TextBox1.Text = TextBox1.Text + 1
23
24
    End Sub

von Alexander A. (alex0815)


Angehängte Dateien:

Lesenswert?

Nochmal zum Vergleich, mit einem Terminal sieht es so aus (s.Anhang)

von bluppdidupp (Gast)


Lesenswert?

vllt. muss bei:
SerialInput = SerialInput + SerialPort1.ReadExisting()
...wie unten auch ein "&" statt "+" hin?
Kann es sein, dass "+" in vb.net womöglich irgendwelche Besonderheiten 
macht und "&" da für normale Konkatenation gedacht ist?

von Alexander A. (alex0815)


Lesenswert?

Hi und danke, aber das bringt auch nichts, glaube,d ass hier das += auch 
schon richtig ist. Aber ich weiss nicht warum das nicht klappt. Komische 
ist, dass es im Terminal einwandfrei funktioniert....

von Karl H. (kbuchegg)


Lesenswert?

Eine Möglichkeit ist noch, dass VB bei Strings bei den Zeichen mit 1 zu 
zählen anfängt und nicht mit 0.

Ansonsten musst du dir halt mal die Zwischenergebnisse ausgeben lassen. 
Die generelle Strategie ist ja in Ordnung.

von Karl H. (kbuchegg)


Lesenswert?

Alexander Alexander schrieb:
> .... glaube, .....

Mit "glauben" gewinnt man in der Programmierung keinen Blumentopf. 
Entweder etwas ist so oder es ist nicht so. Und wenn man es nicht weiß, 
dann muss man eben Doku studieren, oder den Debugger anschmeissen, oder 
sich sonst überlegen, wie man durch entsprechende Ausgaben irgendwohin 
sich Klarheit verschaffen kann.

von Chriss (Gast)


Angehängte Dateien:

Lesenswert?

ich kenn die probs zu genüge...

ich kann nur sagen verwende nicht die ocx... hatte damit nur ärger
und du musst immer schön warten zwischen abfrage absenden und antwort 
abholen
(waitms-function)

hier ein modul im anhang damit konnte ich arbeiten atmega32...

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.