mikrocontroller.net

Forum: PC-Programmierung SerialPort abfragen (VB2008)


Autor: Micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich verwende VB2008.net und möchte Daten vom SerialPort abfragen.
Leider hängt es und VB zeigt mir keinen Fehler an.
Die Komponente SerialPort habe ich auf der Oberfläche.

Kurzbeschreibung:
Wenn im SerialCom der Wert 1 vorhanden ist, soll Bild 1 auf der 
Oberfläche angezeigt werden, bei Wert 2 wieder ausgeblendet und Bild 2 
sichtbar werden. Der Wechsel findet alle ~5 - 10 Sekunden statt - im 
WindowsTerminal kann ich die Werte empfangen (Com4).

Würde mich freuen, wenn sich jemand mein Code ansehen könnte

schon mal Danke
Micha
Imports System.IO.Ports
Public Class Form1
    Dim Daten As Integer

    'Daten empfangen
    Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click
        SerialPort1.PortName = "com4"
        SerialPort1.BaudRate = 9600
        SerialPort1.WriteTimeout = 1000
        SerialPort1.ReadTimeout = 1000
        SerialPort1.Open()
    End Sub

    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        While (Daten > 4)
            Daten = SerialPort1.ReadExisting
        End While
    End Sub

    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        Do
            Select Case Daten
                Case "1"
                    PictureBox1.Visible = True
                    PictureBox2.Visible = False
                    PictureBox3.Visible = False

                Case "2"
                    PictureBox1.Visible = False
                    PictureBox2.Visible = True
                    PictureBox3.Visible = False
                Case "3"
                    PictureBox1.Visible = False
                    PictureBox2.Visible = False
                    PictureBox3.Visible = True
            End Select
        Loop Until Daten > 4
    End Sub
End Class

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lass dir doch mal die empfangenen Daten anzeigen.

Autor: Lasse S. (cowz) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        While (Daten > 4)
            Daten = SerialPort1.ReadExisting
        End While
    End Sub

Vielleicht hängt's auch hier? Er sollte in dem EventHandler nur soviele 
Daten lesen, wie auch wirklich da sind. Und nicht einfach immer weiter, 
bis da zufällig mal was kleinergleich 4 rüber kommt.

Allgemein hast du da recht viele Schleifen drin, die schnell mal 
unendlich lang werkeln. Wenn das unbedingt sein muss (nein, muss es 
nie), dann bau da mal ein Application.DoEvents rein. Aber vermeide die 
Schleifen lieber gleich.

Autor: Albrecht H. (alieninside)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie Lasse S. bereits schrieb, das mit dem

While (Daten > 4)

ist schlecht, "Sub SerialPort1_DataReceived" ist ja zumindest vom 
Verständnis her eine Art Interruptroutine, die gibts zwar unter VB wie 
Sand am Meer, aber in diesem Fall ist sie ja noch an eine echte externe 
Hardware, nämlich den seriellen Port gebunden und solche Routinen sollte 
man möglichst schnell abarbeiten und wieder verlassen, bevor sie erneut 
aufgerufen werden.
Aber genau das macht "While (Daten > 4)" nicht, (was passiert z.B. wenn 
gerade nur ein einziges Byte den "DataReceived"-Event ausgelöst hat?).

Du solltest die "SerialPort.BytesToRead"-Eigenschaft checken um 
festzustellen wieviele Bytes sich gerade im Empfangspuffer des seriellen 
Ports befinden wenn "DataReceived" ausgelöst wird.

Nachtrag: In der Regel wird "DataReceived" bereits nach einem 
empfangenen Byte ausgelöst, muss aber nicht so sein, je nachdem was das 
Betriebsystem gerade macht können es auch mal zwei, drei oder noch mehr 
Bytes sein.

Autor: Micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert


Hab den Code nun etwas verändert und siehe da es funktioniert.

Ich hatte noch einen weiteren Fehler und zwar wurde der SerialPort nicht 
abgefragt.

Hier die abgeänderte Version:
Imports System.IO.Ports
Imports System.Windows.Forms
Imports System

Public Class Sim

    Dim Verbindung As Double
    Dim Daten As String

    Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click

        SerialPort1.PortName = "com4"
        SerialPort1.BaudRate = 9600
        SerialPort1.WriteTimeout = 1000                        ' 1000 ms = 1 Sek.
        SerialPort1.ReadTimeout = 1000                         ' 1000 ms = 1 Sek.
        SerialPort1.Open()
        If SerialPort1.IsOpen Then
            Verbindung = 1
        End If
    End Sub

    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        txtAusgabe.Text = Daten
        Do
            'If SerialPort1.BytesToRead = 0 Then
            Daten = SerialPort1.ReadExisting
            Application.DoEvents()
            'Else
            'End If
            Select Case Daten
                Case "1"
                    PictureBox1.Visible = True
                    PictureBox2.Visible = False
                    PictureBox3.Visible = False

                Case "2"
                    PictureBox1.Visible = False
                    PictureBox2.Visible = True
                    PictureBox3.Visible = False
                Case "3"
                    PictureBox1.Visible = False
                    PictureBox2.Visible = False
                    PictureBox3.Visible = True
            End Select
        Loop Until Verbindung = 0
    End Sub


    Private Sub Ampelsimulation_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        Verbindung = 0
        SerialPort1.Close()
    End Sub
End Class


Autor: Albrecht H. (alieninside)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schön, dass es funktioniert. Übung macht den Meister. Nett gemeint! Aber 
das ist leider noch lange nicht!

Zumindest vom reinen Ansatz her sogar noch schlechter als dein erster 
Entwurf, weil du jetzt nur noch eine Schleife und keine Events mehr zum 
Auslesen des seriellen Ports verwendest. Dein Programm hängt praktisch 
in der "Loop Until Verbindung = 0"-Schleife fest und ohne 
"Application.DoEvents()" würde vermutlich gar nichts mehr gehen, ganz 
schlechter Stil!

Zudem ist gar nicht festgelegt was passieren soll, wenn 
"SerialPort1.ReadExisting" zufällig mal mehr als 1 Byte liefert.

Dann bau lieber wieder alles in das "SerialPort1_DataReceived"-Event 
ein. Im Prinzip ist es doch ganz einfach: "SerialPort1_DataReceived" 
wird automatisch aufgerufen wenn der serielle Port etwas empfangen hat, 
dann schaut man mit ....

Ok, ich gebs ja zu, es ist dann doch nicht ganz so einfach, wie es auf 
den ersten Blick in die VS2008 Dokumentation ausschaut. Ich hab das 
gestern einfach mal selber ausprobiert, das hat dann zwar auch gleich 
irgendwie so funktioniert, wie ich mir das vorgestellt habe, aber halt 
nur irgendwie. Unschöne Warnungen wegen "Threadübergreifender Zugriffe 
auf eine Form" und eine ganz üble Exception beim Beenden des Programms 
haut einem der VS2008 Compiler um die Ohren wenn man die Sache im 
VB6-Stil angeht. Microsoft hat da für den Gelegenheits-VB-Programmierer 
inzwischen doch ein paar Fußangeln ausgelegt.

Trotzdem, eines der wenigen schönen Beispiele für die Verwendung des 
seriellen Ports unter VB2005/2008, ist hier zu finden:
http://www.activevb.de/tipps/vbnettipps/tipp0071.html

Schön deshalb, weil es in sehr kompakter Form:

- zeigt wie man das serielle Port-Control dynamisch erzeugt

- zeigt wie man die verfügbaren COM-Ports auflistet

- zeigt wie man nicht nur das "DataReceived"-Event behandelt sondern 
auch alle anderen die mit dem COM-Port zu tun haben.

- auch die, inzwischen zum Leidwesen und Unverständnis vieler 
VB-Gelegenheitsprogrammierer, notwendige "Thread-sichere"-Programmierung 
am Beispiel einer Textausgabe, nicht unterschlägt

- scheinbar alles soweit richtig macht, dass es den Anwender auch nicht 
mit der, recht häufig diskutierten "Der E/A-Vorgang wurde wegen eines 
Threadendes oder einer Anwendungsanforderung abgebrochen."-Fehlermeldung 
bzw. einer "System.IO.IOException" nerven muss.

Nach Durchsicht dieses Beispiels kann man dann vermutlich auch den Kauf 
dieses Buches verzichten:
http://home.comcast.net/~hardandsoftware/books2.htm

Obwohl der Mann ja durchaus einiges von der Sache zu verstehen scheint, 
seine "DesktopSerialIO.dll" hat jedenfalls in einem ersten Test schon 
mal funktioniert:
http://home.comcast.net/~hardandsoftware/DesktopSerialIO.htm

Autor: Micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Albrecht H. schrieb:
> Zudem ist gar nicht festgelegt was passieren soll, wenn
> "SerialPort1.ReadExisting" zufällig mal mehr als 1 Byte liefert.

Naja, zufällig wird ja nichts versendet, denn mehr versende ich mit dem 
Mikrocontroller nicht.

Mit dem anderen hast du schon Recht, jedoch kamen nur noch die Besagten 
Thread Fehler und ich musste es so lösen.
Deinen Tipp werde ich mir noch ansehen, leider hab ich nicht mehr viel 
Zeit am Code zu basteln

Autor: Albrecht H. (alieninside)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Micha schrieb:
> Albrecht H. schrieb:
>> Zudem ist gar nicht festgelegt was passieren soll, wenn
>> "SerialPort1.ReadExisting" zufällig mal mehr als 1 Byte liefert.
>
> Naja, zufällig wird ja nichts versendet, denn mehr versende ich mit dem
> Mikrocontroller nicht.
>
> Mit dem anderen hast du schon Recht, jedoch kamen nur noch die Besagten
> Thread Fehler und ich musste es so lösen.

Verständlich. Aber wenns nur mal so zum testen oder schnell vorführen 
ist, lässt sich die Sache mit den "IllegalCrossThreadCalls" auch einfach 
abschalten, dazu einfach folgende Zeile unterhalb von "Private Sub 
Form1_Load ..." einfügen, dann verhält sich das Programm so als wäre es 
unter VB2003 kompiliert worden, da gabs das noch nicht:

Control.CheckForIllegalCrossThreadCalls = False

und im verlinkten Beispiel wird ja dann gezeigt wie es richtig geht.

> Deinen Tipp werde ich mir noch ansehen, leider hab ich nicht mehr viel
> Zeit am Code zu basteln

Autor: Eugler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Albrecht H. schrieb:
> lässt sich die Sache mit den "IllegalCrossThreadCalls" auch einfach
> abschalten

Naja, auch irgendwie dirty. Dann lieber einen delegaten anlegen, der den 
GUI Thread handelt.

Autor: juppi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch einfacher

Schicke vom Controller nur 1 Byte als ByteBefehl.

Diesen auswerten und deine Ampeln schalten.

P.S.  das DataReceived Ereignis kann eingestellt werden, nach wieviel 
Byte es Auslöst.

Autor: Micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, Danke euch

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.