Diese Frage ist eher allgemeiner Natur. Konkret geht es um das Digital-Multimeter VA18B unter Visual Basic 6.0, aber allgemeine Antworten sind auch willkommen.
Folgendes Problem besteht:
Das Gerät, also in meinem Fall das Multimeter, schickt alle paar Millisekunden Daten (Bytes). 14 Bytes ergeben ein vollständiges Paket. Aus diesen 14 Bytes lese ich u. a. die aktuell gemessene Spannung aus.
Ich verwende in VB6 das MSComm-Steuerelement. Im OnComm()-Event frage ich die Daten ab:
"RThreshold" steht auf "1", d. h. sobald ein Byte angekommen ist, wird das Event ausgelöst. GetUBound liefert lediglich den UBound eines Arrays (aber ohne Fehler, wenn der Array keinen Inhalt hat), comMMInp ist eine globale Variable (Byte-Array), RecValueMultimeter verarbeitet die 14 Bytes und zeigt den Wert an (die Routine ist hier irrelevant).
Nun hat das bisher auch immer gut geklappt. Neuerdings passiert in meinem Programm aber etwas mehr und dadurch entstehen leichte Delays, die dazu führen, dass plötzlich nicht 1 Byte ankommt, sondern mehrere. Zufällig ergibt das auch meistens irgendwann 14 Bytes (UBound=13). Nur manchmal, wenn eine etwas größere Pause im Programm entsteht, sind im Puffer evtl. 100 Bytes.
Zwischenzeitlich hatte ich den Puffer auf 14 Bytes gesetzt, aber das ergibt das selbe Problem.
Anschließend hatte ich einfach immer die ersten 14 Bytes genommen und den Rest verworfen. Aber hier liegt das Problem. Unter Umständen habe ich den Anfang eines Pakets damit verworfen.
Als Lösung hatte ich folgendes getestet:
Brachte leider auch nichts. Im Moment ist es wie folgt:
Aber auch das führt zu zerstückelten Paketen.
Die große Frage ist: Mache ich das generell richtig? Wie sorgt man dafür, dass kein Paket zerstückelt wird? Man kann (soweit ich weiß) im Falle des Multimeters nicht erkennen, wo ein Paket anfängt oder aufhört. Somit müsste ich quasi jedes ankommende Byte verarbeiten. Ich könnte also niemals was verwerfen. Zwar verwerfe ich meiner Ansicht nach derzeit nichts (es sei denn, mein Code ist falsch), aber es geht ja trotzdem nicht.
Die Frage nochmal in Kurzform:
Wie sorgt ihr dafür, dass Daten, die über die serielle Schnittstelle kommen, niemals zerstückelt werden, sofern immer mehrere Zeichen/Bytes einen Gesamtwert ergeben?
Folgendes Problem besteht:
Das Gerät, also in meinem Fall das Multimeter, schickt alle paar Millisekunden Daten (Bytes). 14 Bytes ergeben ein vollständiges Paket. Aus diesen 14 Bytes lese ich u. a. die aktuell gemessene Spannung aus.
Ich verwende in VB6 das MSComm-Steuerelement. Im OnComm()-Event frage ich die Daten ab:
Visual Basic-Quellcode
- ' Ereignisse
- Case comEvReceive ' Anzahl empfangener Zeichen gleich RThreshold
- inp = comMultimeter.Input
- u = GetUBound(comMMInp)
- For I = 0 To GetUBound(inp)
- ReDim Preserve comMMInp(u + I + 1)
- comMMInp(u + I + 1) = inp(I)
- Next I
- If GetUBound(comMMInp) = 13 Then
- RecValueMultimeter comMMInp
- Erase comMMInp
- End If
"RThreshold" steht auf "1", d. h. sobald ein Byte angekommen ist, wird das Event ausgelöst. GetUBound liefert lediglich den UBound eines Arrays (aber ohne Fehler, wenn der Array keinen Inhalt hat), comMMInp ist eine globale Variable (Byte-Array), RecValueMultimeter verarbeitet die 14 Bytes und zeigt den Wert an (die Routine ist hier irrelevant).
Nun hat das bisher auch immer gut geklappt. Neuerdings passiert in meinem Programm aber etwas mehr und dadurch entstehen leichte Delays, die dazu führen, dass plötzlich nicht 1 Byte ankommt, sondern mehrere. Zufällig ergibt das auch meistens irgendwann 14 Bytes (UBound=13). Nur manchmal, wenn eine etwas größere Pause im Programm entsteht, sind im Puffer evtl. 100 Bytes.
Zwischenzeitlich hatte ich den Puffer auf 14 Bytes gesetzt, aber das ergibt das selbe Problem.
Anschließend hatte ich einfach immer die ersten 14 Bytes genommen und den Rest verworfen. Aber hier liegt das Problem. Unter Umständen habe ich den Anfang eines Pakets damit verworfen.
Als Lösung hatte ich folgendes getestet:
Visual Basic-Quellcode
- If GetUBound(comMMInp) >= 13 Then
- Dim value() As Byte
- value = comMMInp
- Erase comMMInp
- If GetUBound(value) > 13 Then
- For I = 14 To GetUBound(value)
- ReDim Preserve comMMInp(GetUBound(comMMInp) + 1)
- comMMInp(GetUBound(comMMInp)) = value(I)
- Next I
- End If
- ReDim Preserve value(13)
- RecValueMultimeter value
- End If
Brachte leider auch nichts. Im Moment ist es wie folgt:
Visual Basic-Quellcode
- ' Ereignisse
- Case comEvReceive ' Anzahl empfangener Zeichen gleich RThreshold
- inp = comMultimeter.Input
- u = GetUBound(comMMInp)
- For I = 0 To GetUBound(inp)
- ReDim Preserve comMMInp(u + I + 1)
- comMMInp(u + I + 1) = inp(I)
- If GetUBound(comMMInp) = 13 Then
- RecValueMultimeter comMMInp
- Erase comMMInp
- u = -1
- End If
- Next I
Aber auch das führt zu zerstückelten Paketen.
Die große Frage ist: Mache ich das generell richtig? Wie sorgt man dafür, dass kein Paket zerstückelt wird? Man kann (soweit ich weiß) im Falle des Multimeters nicht erkennen, wo ein Paket anfängt oder aufhört. Somit müsste ich quasi jedes ankommende Byte verarbeiten. Ich könnte also niemals was verwerfen. Zwar verwerfe ich meiner Ansicht nach derzeit nichts (es sei denn, mein Code ist falsch), aber es geht ja trotzdem nicht.
Die Frage nochmal in Kurzform:
Wie sorgt ihr dafür, dass Daten, die über die serielle Schnittstelle kommen, niemals zerstückelt werden, sofern immer mehrere Zeichen/Bytes einen Gesamtwert ergeben?