Forum: PC-Programmierung Daten von serieller Schnittstelle formatieren


von Stefan (Gast)


Lesenswert?

Hallo,

ich habe ein Programm gemacht, das mit einer Waage kommuniziert - also 
auf
Knopfdruck das Wiegeergebnis ausliest und anzeigt. Das funktioniert 
alles
soweit gut.

Mein Problem ist, wie bekomme ich die Daten formatiert? - Bzw. an 
welcher
Stelle muss ich da ansetzen?
Die Waage liefert z. B. "S S                127.3 g <Return>" ich möchte
aber in meiner Textbox nur "127,3 g" stehen haben.
Wenn ich nach meinem Invoke-Befehl nur schon eine MSGBOX machen will, 
die
mir das ganze etwas formatiert, erhalte ich schon folgende nette 
Meldung:

Der Index und die Länge müssen sich auf eine Position in der 
Zeichenfolge
beziehen - Parameter: length

Es scheint mir, als ob noch nicht alle Daten da sind und das Programm 
schon
weiter läuft.
Kann man irgendwie abprüfen ob alles da ist?
Wo muss ich mit dem formatieren ansetzen?

Ich hoffe, dass einer mir weiterhelfen kann.


Gruß
Stefan


Private Sub cmd_wiegen_uebernehmen_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles cmd_wiegen_uebernehmen.Click

' Anzeigefeld leeren

TextBox_Waagendisplay.Text = Nothing

ToolStripStatusLabel_Gewicht.Text = Nothing

' Befehl an Schnittstelle / Gerät senden

If ComboBox_Waagen_Modell.SelectedItem = "MODEM" Then

Serielle_Schnittstelle.WriteLine("ATI3" & (Chr(13)))

End If



If ComboBox_Waagen_Modell.SelectedItem = "Mettler-Toledo" Then

Serielle_Schnittstelle.WriteLine("S" & (Chr(13)))

End If

End Sub

======================================================================== 
==============================================

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

Try

TextBox_Waagendisplay.Invoke(New myDelegate(AddressOf updateTextBox), 
New
Object() {})

MsgBox(TextBox_Waagendisplay.Text.Substring(4, 10), 
MsgBoxStyle.Information,
"Waagendisplay formatiert...")

Catch ex As Exception

MsgBox(ex.Message, MsgBoxStyle.Exclamation, "Fehler aufgetreten... 
...Gerät
/ Port richtig eingestellt?")

Exit Sub

End Try

End Sub

======================================================================== 
================================================

Public Delegate Sub myDelegate()

Public Sub updateTextBox()

With TextBox_Waagendisplay

.Font = New Font("Microsoft Sans Serif", 16.0!, FontStyle.Bold)

.AppendText(Serielle_Schnittstelle.ReadExisting)

.ScrollToCaret()

End With

End Sub


von Ralf (Gast)


Lesenswert?

Das ist VB, richtig?

> "S S                127.3 g <Return>"

Kann die Waage nur in Gramm oder auch in Kilogramm anzeigen, und wieviel 
jeweils? Wenn die Waage nur Gramm anzeigen kann, und das beispielsweise 
nur bis 10 kg, dann muss deine Textbox mit den letzten 9 Zeichen (ohne 
Return) von rechts aus deinen empfangenen Daten gefüllt werden, und 
dafür bietet VB viele nette Textfunktionen...

Oder ist das nicht das, was du dir vorstellst?
Ralf

von Stefan (Gast)


Lesenswert?

Hallo Ralf,

die Einheit ist variabel - Waage kann z. B. auch Stückzählen.
L. T. Datenbeschreibung ist die Anzeige 10 Stellen wobei aber die 
Stellen davor mit Leerzeichen erscheinen.

Ja, es ist VB .NEt 2005.
Wo kann ich versuchen da anzusetzen? - Hast du ein Beispiel?

Wenn ich mit Substring was "rausschneiden" will, klappt das irgendwie 
immer nur mit der Fehlermeldung, da wohl noch Daten ankommen bzw. noch 
nicht alle Daten da sind.
Ich habe schon versucht mit einem TextChanged Ereignis der Textbox zu 
arbeiten, aber da läuft es auch auf den Fehler.

Dadurch, dass wohl noch Daten ankommen, wird wohl mehrfach das 
DataReceived Ereignis durchlaufen.

Hast du noch eine Idee???

Mein Programm ist vergleichbar mit dem Beispiel unter
http://www.devx.com/dotnet/Article/31001/0/page/2
Jedoch ist da auch nichts gezeigt, wie man was formatiert bzw. an 
welcher Stelle.


Gruß
Stefan

von Ralf (Gast)


Lesenswert?

Ach so du arbeitest in der seriellen Schnittstelle mit Polling? Dann 
könntest du eine Bool-Variable verwenden, die erst dann auf True geht, 
wenn das Return empfangen wurde, das zeigt dir dann an, dass die Daten 
komplett sind...
Deine Anzeige-Routine pollt diese Bool-Variable, und gibt erst aus, 
nachdem die Variable True ist. Nach der Ausgabe setzt die 
Ausgabe-Routine die Variable auf False...

Zum Thema String bearbeiten, in VB6 gabs da die left- bzw. 
right-Funktionen (und noch viele andere ähnliche)...

Sag Bescheid, obs geklappt hat...

Ralf

von Wolfram (Gast)


Lesenswert?

>Dadurch, dass wohl noch Daten ankommen, wird wohl mehrfach das
>DataReceived Ereignis durchlaufen

Das vermutest du richtig
ändere deine Programmstruktur. Der Zugriff auf Textboxen hat nichts in 
der Empfangsroutine für einzelne Zeichen zu suchen. Das Einzige was du 
da machst, ist die Zeichen in einen String zu übernehmen und 
möglicherweise zu signalisieren wann der String die entsprechende Länge 
hat, damit er weiterverarbeitet werden kann.

von Stefan (Gast)


Lesenswert?

Hallo,

habt Ihr zufällig ein kleines Beispiel wie Ihr das genau meint bzw. man 
sowas aufbaut?


Gruß
Stefan

von Wolfram (Gast)


Lesenswert?

Wow, der Programmcode den du hast hast du ja vollständig kopiert von dem 
Link den du angibst.
Jetzt kapiere ich auch warum du so eine ungünstige Programmstruktur 
nimmst.
Nun das geht hervorragend für ein Terminalprogramm aber nicht für deinen 
Anwendungsfall. Du willst eine Waage abfragen und ich schätze das 
funktioniert folgendermaßen: Du sendest einen Befehl und bekommst eine 
Antwort.
Dazu brauchst du kein Event wenn daten ankommen, die kommen nämlich nur 
wenn du sie anforderst und damit wird es sehr einfach.
Du schreibst nämlich nur auf die Schnittstelle und wenn die 
entsprechende Anzahl Zeichen der Antwort da ist liest du das ganze aus.
Dazu braucht man kein Bsp, man muss nur die Serialportklasse kennen, 
hierzu gibt es die MSDN
http://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.aspx
nebenbei ist da auch ein Bsp, aber das solltest du auch so hinbekommen.

von Stefan (Gast)


Lesenswert?

Hallo Wolfram,

ja, ich sende nur einen Befehl und greife auf die Antwort zurück.
Das würde bedeuten, dass ich gleich bei dem Klick auf den Wiege-Button 
den Befehl sende und den Empfang auslese und ggf. noch formatiere.

Zum formatieren hatte mir jemand mal folgendes vorgeschlagen:
Dim a As String

Dim wert As Double

If Double.TryParse(string_von_waage, out wert) = true Then

  a.Format(“{0:#####.0} g”, wert)

  textbox.Text = a

Else

  textbox.Text = “Fehler”

End If

findest du das GUT???



Wenn man mit dem DataReceived Event arbeitet, muss man wohl immer ein 
Invoke machen und ein Delegate, damit die Daten in die Textbox 
geschrieben werden. - Ansonsten bekommt man so schöne Meldungen wie 
diese:

Der Zugriff auf das Steuerelement TextBox_Waagendisplay erfolgte von 
einem anderen Thread als dem Thread, für den es erstellt wurde."

  Source="System.Windows.Forms"


Zusammengefasst würde ich jetzt sowas machen (Modem ist zum testen, wenn 
ich die Waage nicht dran habe):

' Befehl an Schnittstelle / Gerät senden

        If ComboBox_Waagen_Modell.SelectedItem = "MODEM" Then
            Serielle_Schnittstelle.WriteLine("ATI3" & (Chr(13)))
        End If


        If ComboBox_Waagen_Modell.SelectedItem = "Mettler-Toledo" Then
            Serielle_Schnittstelle.WriteLine("S" & (Chr(13)))
        End If

        TextBox_Waagendisplay.Text = 
Serielle_Schnittstelle.ReadExisting()
(Formatieren)

von Stefan (Gast)


Lesenswert?

Hallo,

habe festgestellt, dass man besser noch ein Sleep ins Programm einbauen 
sollte - sonst kann es sein, dass noch nicht alle Daten im Puffer der 
Schnittstelle zur Verfügung stehen bzw. noch etwas vom vorherigen 
Versuch wohl da ist.

System.Threading.Thread.Sleep(100)  ' 1000 = 1 Sekunde warten

sollte helfen!


Gruß
Stefan

von Wolfram (Gast)


Lesenswert?

>ja, ich sende nur einen Befehl und greife auf die Antwort zurück.
>Das würde bedeuten, dass ich gleich bei dem Klick auf den Wiege-Button
>den Befehl sende und den Empfang auslese und ggf. noch formatiere.

dachte ich es mir doch, du brauchst keinen receive Event sondern es geht 
ganz einfach: schreiben->auslesen

>Zum formatieren hatte mir jemand mal folgendes vorgeschlagen:...
du kennst doch das geanue Format der Antwort, schneide alles 
überflüssige weg und mache dann die Umwandlung

>Wenn man mit dem DataReceived Event arbeitet, muss ...

genau deswegen ist es nötig, deshalb vermeidet man solche Abfragen wenn 
nicht unbedingt nötig, da hieraus gewöhnlich ein sehr unübersichtlicher 
Code entsteht.

Das Sleep ist keine schlechte Idee da das Senden über die Serielle 
dauert.
Aber bist damit immer noch sehr unsauber. Entweder du arbeitest mit 
Timeout für die Antwort oder du wartest bis die entsprechende Anzahl von 
Zeichen gekommen ist, dann erst liest du. Natürlich solltest du dann 
immer noch einen Timeout haben.


von J. S. (engineer) Benutzerseite


Lesenswert?

Warum machst du das denn nicht einfach ereignisgesteuert über das 
TextBoxFeld, das die Daten einliest?  Geht das in *.NET nicht?

Ich habe das in meinen Accessdatenbanken immer so gehandhabt, daß ein 
Textfeld (Variablenfeld) beim Eintreffen einer neuen validen Nachricht 
einmalig aktualisiert wurde. Formatierungen kann man dann über ein 
versteckt eingelesenens Feld (Visibility = 0) und einem anderen 
sichtbaren Feld realisieren, wobei man auf das nichtsichtbare die in VBA 
vorhandenen Textoperatoren und Konversionfunktionen loslässt. Damit wird 
dann nur "bei Änderung" und auch nur einmalig gerechnet. (also nix 
"polling" oder wait state oder so ...)

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.