Die Community zu .NET und Classic VB.
Menü

VB.NET-Tipp 0071: Serielle Schnittstelle ansteuern

 von 

Beschreibung

In diesem Tipp wird beschrieben, wie man auf einfache Weise eine Verbindung über die serielle Schnittstelle herstellt. Hier zu wird die Klasse IO.Ports.SerialPort des .NET-Frameworks genutzt. Es ist zu beachten, dass die Einstellungen des Ports die gleichen seien müssen, wie die des Geräts mit dem kommuniziert werden soll. Außerdem benötigt man ein passendes Verbindungskabel mit der richtigen Pinbelegung. Näheres dazu entnehmen Sie bitte der Dokumentation ihres Geräts.

Schwierigkeitsgrad:

Schwierigkeitsgrad 1

Framework-Version(en):

.NET Framework 2.0, .NET Framework 3.0, .NET Framework 3.5

.NET-Version(en):

Visual Basic 2005, Visual Basic 2008

Download:

Download des Beispielprojektes [11,55 KB]

' Dieser Quellcode stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!

' Projektversion:   Visual Studio 2005
' Option Strict:    An
'
' Referenzen: 
'  - System
'  - System.Data
'  - System.Deployment
'  - System.Drawing
'  - System.Windows.Forms
'  - System.Xml
'
' Imports: 
'  - Microsoft.VisualBasic
'  - System
'  - System.Collections
'  - System.Collections.Generic
'  - System.Data
'  - System.Drawing
'  - System.Diagnostics
'  - System.Windows.Forms
'

' ##############################################################################
' ################################# Form1.vb ###################################
' ##############################################################################
Public Class Form1
    ' Das Delegat muss die selbe Signature haben
    Delegate Sub TextBoxCallback(ByVal text As String)

    Private WithEvents myComPort As IO.Ports.SerialPort

    ' Bei den meisten Geräten ist ein Abschlußzeichen erforderlich, meistens 
    '  wird ChrW(13) oder ChrW(10) oder beide benötigt 
    '  - Wählt was eure Gegenstelle benötigt:
    ' Private EndOfCommand As String = Constants.vbCr.ToString
    ' Private EndOfCommand As String = Constants.vbLf.ToString
    Private EndOfCommand As String = Constants.vbCrLf.ToString

    Private Sub Form1_Load(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load

        ' Mal nachschauen, ob es hier SerialPorts gibt
        Dim str() As String = IO.Ports.SerialPort.GetPortNames()

        ' Wenn nein, dann beenden:
        If str.Length = 0 Then
            MsgBox("No Serialport available!", MsgBoxStyle.Critical)
            Me.Close()
        End If

        ' Eine Instance von SerialPort erstellen
        ' Im Normalfall ist das COM1:
        Me.myComPort = New IO.Ports.SerialPort(str(0))

        ' Die folgenden vier Einstellungen müssen denen der 
        ' Gegenstelle entsprechen
        Me.myComPort.BaudRate = 9600
        Me.myComPort.DataBits = 8
        Me.myComPort.StopBits = IO.Ports.StopBits.One
        Me.myComPort.Parity = IO.Ports.Parity.None

        ' Wichtig! Hier wird eingestellt nach wieviel Bytes im Eingangspuffer 
        ' das DataReceived Event gefeuert wird
        Me.myComPort.ReceivedBytesThreshold = 1

        ' Und nun öffnen wir den Port
        Me.myComPort.Open()
    End Sub

    ''' <summary>
    ''' Wird ausgelöst wenn die Comm die in ReceivedBytesThreshold eingestellte 
    ''' Anzahl Bytes empfangen hat
    ''' </summary>
    Private Sub myComPort_DataReceived( _
        ByVal sender As Object, _
        ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
        Handles myComPort.DataReceived

        Select Case e.EventType
            Case IO.Ports.SerialData.Chars
                ' Ein Zeichen wurde empfangen und im Eingabepuffer platziert.

            Case IO.Ports.SerialData.Eof
                ' Das Dateiendezeichen wurde empfangen und im 
                '  Eingabepuffer platziert. 

        End Select
        Dim msg As String = Me.myComPort.ReadExisting
        Me.ShowText(msg)
    End Sub

    ''' <summary>
    ''' Wird ausgelöst wenn sich die Steuerleitungen geändert haben
    ''' </summary>
    Private Sub myComPort_PinChanged(ByVal sender As Object, ByVal e As  _
        System.IO.Ports.SerialPinChangedEventArgs) Handles myComPort.PinChanged
        Select Case e.EventType
            Case IO.Ports.SerialPinChange.Break
                ' Bei der Eingabe wurde ein "break" erkannt.

            Case IO.Ports.SerialPinChange.CDChanged
                ' Der Zustand des CD-Signals (Carrier Detect) hat sich geändert.
                ' Mit diesem Signal wird angezeigt, ob ein Modem mit einer 
                '  Telefonleitung verbunden ist und ein Datenträgersignal 
                '  erkannt wurde.

            Case IO.Ports.SerialPinChange.CtsChanged
                ' Der Zustand des CTS-Signals (Clear to Send) hat sich geändert.
                '  Mit diesem Signal wird angegeben, ob Daten über den seriellen
                '  Anschluss gesendet werden können. 

            Case IO.Ports.SerialPinChange.DsrChanged
                ' Zustand des DSR-Signals (Data Set Ready) hat sich geändert.
                '  Mit diesem Signal wird angezeigt, ob das Gerät am seriellen
                '  Anschluss betriebsbereit ist.

            Case IO.Ports.SerialPinChange.Ring
                'Ein Ringindikator wurde erkannt. 

        End Select
    End Sub

    ''' <summary>
    ''' Wird ausgelöst wenn ein Fehler in der Übertragung endeckt wurde
    ''' </summary>
    Private Sub myComPort_ErrorReceived( _
        ByVal sender As Object, _
        ByVal e As System.IO.Ports.SerialErrorReceivedEventArgs) _
        Handles myComPort.ErrorReceived

        Select Case e.EventType
            Case IO.Ports.SerialError.Frame
                ' Die Hardware hat einen Rahmenfehler erkannt.

            Case IO.Ports.SerialError.Overrun
                ' Ein Zeichenpufferüberlauf ist aufgetreten. Das nächste 
                '  Zeichen geht verloren. 

            Case IO.Ports.SerialError.RXOver
                ' Ein Eingabepufferüberlauf ist aufgetreten.
                ' Die Kapazität des Eingabepuffers ist erschöpft,
                '  oder es wurde ein Zeichen nach dem Dateiendezeichen 
                '  (EOF, end-of-file) empfangen. 

            Case IO.Ports.SerialError.RXParity
                ' Die Hardware hat einen Paritätsfehler erkannt.

            Case IO.Ports.SerialError.TXFull
                ' Die Anwendung hat versucht, ein Zeichen zu übertragen, aber 
                ' die Kapazität des Ausgabepuffers war erschöpft. 

        End Select
        Me.ShowText("ERROR" & vbCrLf)
    End Sub

    ''' <summary>
    '''  Da die Daten aus einem anderem Thread kommen müssen wir die Ausgabe 
    '''  über Invoke machen
    ''' </summary>
    Private Sub ShowText(ByVal text As String)
        If Me.TextBox1.InvokeRequired Then
            Dim d As New TextBoxCallback(AddressOf ShowText)
            Me.Invoke(d, New Object() {text})
        Else
            Me.TextBox1.Text = Me.TextBox1.Text & text
        End If
    End Sub

    ''' <summary>
    ''' Hier wird der Command zusammengesetzt und versendet
    ''' </summary>
    ''' <param name="command"></param>
    ''' <remarks></remarks>
    Private Sub Send(ByVal command As String)
        Me.myComPort.Write(command & Me.EndOfCommand)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles Button1.Click

        Me.Send("Ein Befehl, den die Gegenstelle kennt!")
    End Sub
End Class

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Perfekt - Gast 07.03.12 07:38 2 Antworten
In ein anderes Modul verlagern - tommes 30.04.13 14:06 2 Antworten

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 11 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von RogerBerglen am 28.09.2010 um 19:05

Ich habe mit großem Interesse das Beispielprogramm ausprobiert. Es funktioniert super. Nur weis ich nicht wie ich jetzt per Invoke die Daten nicht direkt an ein Steuerelement, sondern als Byte-Array in eine Variable schreibe die dann von meinem weiteren Programm verarbeitet werden kann.
Ich möchte eine separate Function schreiben die in etwa so funktionieren soll: Function SerSend(ByVal ByteOut() As Byte, ByVal Fehler As String) As Byte und Function SerEmpf(ByVal ByteIn() As Byte, ByVal Fehler As String). Ich habe jetzt schon Tage damit verbracht das so hinzubekommen, aber es gelingt mir aus Verständlichkeitsgründen nicht.
Hier mal mein bisheriger Code zum Testen:

Public Class Form1

Delegate Sub Callback(ByVal Bef() As Byte)

Private Shared ByteIn() As Byte
Private Shared ByteArray() As Byte

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Me.SerialPort1.PortName = "COM1" 'Name der RS-232 festlegen.
Me.SerialPort1.Handshake = IO.Ports.Handshake.None 'Kein Handshaking
Me.SerialPort1.BaudRate = 9600 'Übertragungsrate
Me.SerialPort1.Parity = IO.Ports.Parity.None 'Keine Paritätsprüfung
Me.SerialPort1.DataBits = 8 '8 Datenbits
Me.SerialPort1.StopBits = IO.Ports.StopBits.One '1 Stoppbit
Me.SerialPort1.RtsEnable = True 'RTS-Signal aktivieren
Me.SerialPort1.DtrEnable = True 'DTR-Signal aktivieren

Me.SerialPort1.Open 'Seriellen Port mit den Einstellungen
'öffnen.
'Me.SerialPort1.Write(Chr(&H1A) & Chr(&H55)) 'Zum Test LED-Muster auf dem MLT aus-
'geben. Danach Befehlstabelle aus dem
Me.SerialPort1.Write(Chr(&H14)) 'MLT-System ausgeben lassen.

'Versuch hier "MsgBox(Str(ByteArray.Length) einzufügen erzeugt eine Ausnahme!!

End Sub

Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
'!!ACHTUNG!! Weiterer Tread <<<<<
Dim ByteIn(Me.SerialPort1.BytesToRead - 1) As Byte 'Byte-Array einrichten anhand der An-
'zahl der empfangenen Bytes. Die em-
Me.SerialPort1.Read(ByteIn, 0, Me.SerialPort1.BytesToRead) 'pfangenen Bytes in das Byte-Array
'schreiben. Byte-Array in anderen Tread
Me.Liste(ByteIn) 'übergeben.

End Sub

Private Sub Liste(ByVal Bef() As Byte)

If Me.lstBef.InvokeRequired Then 'Sollte ein CallBack notwendig sein,
Dim d As New Callback(AddressOf Liste) 'diesen dann aufrufen. Per Invoke dann
Me.Invoke(d, New Object() {Bef}) 'das Byte-Array an den Haupttread über-
Else 'geben.
Dim ByteArray(Bef.Length - 1)
For A As Integer = 0 To Bef.Length - 1 'Sonst das Byte-Array in ein List-Feld
Me.lstBef.Items.Add(Hex(Bef(A))) 'schreiben und in Hex-Werte wandeln.
ByteArray(A) = Bef(A)
Next
End If
lstBef.Sorted = True 'List-Feld sortiert anzeigen.

'Versuch "MsgBox(Str(ByteArray.Length)) einzufügen erzeugt eine Ausnahme.

End Sub

End Class

Kommentar von Andre Krohn am 08.03.2010 um 15:41

Hallo,

ich wuerde die empfangen Zeichen nicht ungefiltert weiterreichen. Das sind Steuercodes. Meist CR+LF (CarriageReturn + LineFeed = chr(13)+chr(10) :)

Eine Schnelle Loesung waere z.B.:

Dim MyNewString as String="" ' <- Gefilteter String
Dim tmp as String="" ' 1 tmp Zeichen
For i as integer = 1 to Len(MyString)-1 ' <- Empfangener String
tmp=Mid(MyString, i, 1)
if asc(tmp)<127 and asc(tmp)>31 then
MyNewString=MyNewString + tmp
end if
next

Hier werden nur reine Buchstaben, Zahlen und Sonderzeichen, keine Steuercodes in einen neuen String geschrieben, den man dann weiterverwursten kann. Das geht sicher noch besser/einfacher/eleganter, aber ich hoffe, dass es so sehr leserlich ist.

Schoenen Gruss...
Andre

Kommentar von Dietmar am 07.03.2010 um 20:23

hallo,

dein code ist super, die funktion zum senden ist auch super,
aber kannst du mir mal sagen wie ich die zeichen weg bekomme, die hinter dem eingang kommen, zum bsp: sende ich hallo von einem geraet zu computer, der sieht das hallo im eingang der RS232 und schickt es dann in die textbox, aber da kommt jetzt der punkt, da steht nicht nur hallo sondern hallo. und ein zeichen ich weiss nicht was es ist, ist transparent, aber es stoert mich ungemein, weil so kann ich zum bsp keine sachen steuern oder visualisieren. ich danke im vorraus.

Kommentar von Dietmar am 07.03.2010 um 20:19

hallo,

dein code ist super, die funktion zum senden ist auch super,
aber kannst du mir mal sagen wie ich die zeichen weg bekomme, die hinter dem eingang kommen, zum bsp: sende ich hallo von einem geraet zu computer, der sieht das hallo im eingang der RS232 und schickt es dann in die textbox, aber da kommt jetzt der punkt, da steht nicht nur hallo sondern hallo. und ein zeichen ich weiss nicht was es ist, ist transparent, aber es stoert mich ungemein, weil so kann ich zum bsp keine sachen steuern oder visualisieren. ich danke im vorraus.

Kommentar von Andre Krohn am 03.12.2009 um 19:42

Hallo JG,
Klar! Me.myComPort.open() oeffnet bereits den Port.
mach mal:
If Me.myComPort.IsOpen = false then
stop
Else
Msgbox("ComPort ist offen!")
End If

Du wirst sehen, dass der Port offen ist, also true!
Wenn das angeschlossene Geraet z.B die Steuerleitungen benutzt, kannst Du darauf reagieren. (Siehe Source)

Generell ist es so, dass der Comport "dumm" ist und geoeffnet werden kann ohne das kommuniziert werden muss.

Kommentar von JG am 03.12.2009 um 10:33

Frage zu Port open.
Port ist vorhanden, aber kein Kabel angeschlossen.
Wie kann ich abfragen, das der Port geöffnet ist?
' Und nun öffnen wir den Port
Me.myComPort.Open()
Auf die Abfrage "If Me.myComPort.IsOpen = False Then Stop"
erfolgt kein Reaktion. Programm läuft weiter.

Kommentar von Andre Krohn am 09.11.2009 um 21:50

Hallo Sebastian,

ich wuerde den Handler mal naeher unter die Lupe nehmen. Z.B. koennte der ReceivedBytesThreshold nicht stimmen. So wird der Handler gar nicht erst ausloesen.
Zum test:
- ReceivedBytesThreshold auf 1 byte setzen
- EndOfCommand ueberpruefen.

Ist bekannt, was das serielle Geraet antworten soll? Hyperterminal und Nullmodem hilft auch manchmal...
Viel Erfolg und Gruesse....

Kommentar von Sebastian am 09.11.2009 um 13:08

Hallo, erstmal danke für ihren Code.
Ich hoffe sie können mir helfen, ich habe ein Problem das ich zwar code verschicken kann der auch verarbeitet wird, aber es wird nichts empfangen bzw. angezeigt.
Haben sie eine Idee woran es liegen könnte?

Mit freundlichen Güßen
Sebastian

Kommentar von Andre Krohn am 29.09.2009 um 16:12

Supersache! Hat mir sehr geholfen!
NUR:
Was, wenn viele COM-ports gleichzeitig genutzt werden muessen?
Ich habe eine Loesung, bei der ich aber nie weiss, von welchem Comport die Daten eigentlich stammen, und muss dieses umstaendlich (Fehlertraechtig) herausfinden. Ich benutze ein list(of T) dem ich ueber eine Ueberladung die Handler zuweise...

Gruss, Andre

Kommentar von Hadzic Damir am 23.09.2009 um 08:20

Hallo auch von mir,

genau das gleich Problem habe ich auch , hab mir bis jetzt 3 Bücher gekauft und in keinem der Bücher ist etwas ausführlicher die Kommunikation mit Seriellen Anschlüssen bzw. auch die Kommunikation im Netzwerk beschrieben.

Wen sie mir ein Buch empfehlen könnten über die Schnittstellen und Netzwerk Programmierung währe ich ihnen dankbar, vielleicht haben sie noch irgendwo ein eBook zur hand.

Mit freundlichen Grüßen HD

Kommentar von Fritz Lampert am 12.03.2009 um 14:44

Ich möchte Text, z. B. in einer TextBox TextBox2 von mir eingegebenen Text, zur Schnittstelle senden, der in der TextBox TextBox1 wieder ausgegeben wird.
Das o. a. Programm läuft ohne Fehler, aber ich komme mit der Aufforderung "Ein Behehl, den die Schnittstelle kennt!" im Aufruf Me.Send() überhaupt nicht klar.
Ich programmiere in Visual C++ (Builer 2006) und möchte gleichermaßen in Visual Basic (Visual Studio 2005) programmieren , weil mir VB an sich liegt.
In Visual C++ geht es (Richard Kaiser), warum sollte es dann in Visual Basic soviel schwerer für mich sein?
Können Sie mir bei meiner Frage helfen und/oder weiteres Material über Schnittstellen-Pragrammierung in VB (SSS und USB-SS) senden. Oder nennen Sie mir ein Buch , in dem die Schnittstellenprogrammierung nicht zu kurz kommt und gut nachvollziehbar beschrieben ist. Die 4 Bücher, die ich habe, behandeln dieses Thema überhaupt nicht.

Mit freundlichen Güßen
Fritz Lampert