Zurück zur Homepage

Datenübertragung mit der Seriellen Schnittstelle

Wie schon bei Beispiel 29 wird ein Com-Port nur mit API-Funktionen des Betriebssystems geöffnet. Spezielle Steuerelemente und dll's sind unnötig. Die Übertragung läuft im Prinzip so wie ein Dateizugriff ab. Mit CreateFile wird ein Comport geöffnet und mit WriteFile/ReadFile werden Daten gesendet und empfangen. Da ein Empfang von Daten nicht über ein Ereignis signalisiert wird, muss man halt häufiger mal nachschauen, ob im Puffer was angekommen ist.

Das Ganze habe ich als Klasse ausgeführt, um den Umgang damit zu erleichtern. Da bei der Datenübertragung häufig Ascii und nicht Ansi (Win) verwendet wird, sind auch ein paar Umwandlungsfunktionen dabei. Wenn man an der Seriellen Schnittstelle Pin 2 und 3 brückt, kann man Senden/Empfangen auch bequem austesten.
Ich habe mit Hyperterminal am Laptop als Gegenstelle getestet. Das mit der Baudrate funktioniert, auch die Ascii - Ansi Umwandlung. Das Setzen der Ausgänge DTR und RTS, sowie das korrekte Auslesen der Eingänge habe ich mit einem Schnittstellentester ausprobiert. Ein paar Sachen, wie XON, XOFF, Flussüberwachung etc. sind zwar umgesetzt, aber ungetestet.
  

Beispielmappe uebertragung.zip 87 KB)

'**************************************************
'Das Folgende zeigt die Verwendung der Klasse.
'Danach kommt die eigentliche Klasse
************************************************** 

Option Explicit
Private Komm As clsSeriell


Private Sub cbStatus_Click()

    If ObjPtr(Komm) <> 0 Then
        'Status Steuerleitungen abfragen
        chbCTS = Komm.CTS_Status
        chbDSR = Komm.DSR_Status
        chbRing = Komm.RING_Status
        chbRLS = Komm.DCD_Status
    End If
End Sub

Private Sub chbCTSOutFlow_Click()
    Range("C1").Select
    Einstellungen
End Sub
Private Sub chbDSROutFlow_Click()

    Range("C1").Select
    Einstellungen
End Sub
Private Sub chbDSRSensitiv_Click()

    Range("C1").Select
    Einstellungen
End Sub
Private Sub chbEmpfangAscii_Click()

    Range("C1").Select
    Einstellungen
End Sub
Private Sub chbNoEOFCheck_Click()

    Range("C1").Select
    Einstellungen
End Sub
Private Sub chbParityCheck_Click()

    Range("C1").Select
    Einstellungen
End Sub
Private Sub chbSendenAscii_Click()

    Range("C1").Select
    Einstellungen
End Sub
Private Sub chbXOffContinuesTx_Click()

    Range("C1").Select
    Einstellungen
End Sub
Private Sub chbXONIn_Click()

    Range("C1").Select
    Einstellungen
End Sub
Private Sub chbXONOut_Click()

    Range("C1").Select
    Einstellungen
End Sub


Private Sub chbCTS_Click()
    Range("C1").Select
End Sub
Private Sub chbDSR_Click()

    Range("C1").Select
End Sub
Private Sub chbRing_Click()

    Range("C1").Select
End Sub
Private Sub chbRLS_Click()

    Range("C1").Select
End Sub

Private Sub chbRTS_Click()
    If ObjPtr(Komm) <> 0 Then
        'RTS setzen
        Komm.RTS_Fest = chbRTS
    End If
    Range("C1").Select
End Sub
Private Sub chbDTR_Click()

    If ObjPtr(Komm) <> 0 Then
        'DTR setzen
        Komm.DTR_Fest = chbDTR
    End If
    Range("C1").Select
End Sub

Private Sub cmbcrlf_Click()
Range("A17") = Range("A17") & vbCrLf
End Sub
Private Sub cmbLf_Click()

    Range("A17") = Range("A17") & vbLf
End Sub
Private Sub cmbCr_Click()

    Range("A17") = Range("A17") & vbCr
End Sub

Private Sub cmbEmpfangen_Click()
Dim Wartezeit As Long, Puffer As String
Wartezeit = Range("B1")
If ObjPtr(Komm) <> 0 Then
    cbStatus_Click 'Steuerleitungen abfragen
    If chbEmpfangAscii.Value = True Then
        'Empfangener Text wird von Ascii nach
        'Ansi umgewandelt

        Komm.Eingang_ASCII = True
    Else
        'Empfangener Text bleibt unverändert
        Komm.Eingang_ASCII = False
    End If
    'Timeout für Warten auf Empfang (1-60 s)
    Komm.Timeout_Empfang = Wartezeit
    'Empfangenen Text auslesen
    Puffer = Komm.EingegangenerText
    If Puffer <> "" Then
        'Zur Zelle A21 in eine neue Zeile hinzufügen
        Range("A21") = Range("A21") & Puffer & Chr(10)
    End If
End If
End Sub


Private Sub cmbLoeschen_Click()

'Zelle, in der der Empfangene Text steht
    Range("A21") = ""
End Sub
Private Sub cmbSendefeldLoeschen_Click()
'Zelle, in der der Sendetext steht
    Range("A17") = ""
End Sub


Private Sub cmbSenden_Click()

If ObjPtr(Komm) <> 0 Then
    cbStatus_Click 'Steuerleitungen abfragen
    If chbSendenAscii.Value = True Then
        'Zu sendender Ansi-Text wird nach Ascii umgewandelt
        Komm.Ausgabe_ASCII = True
    Else
        'Zu sendender Ansi-Text wird nicht umgewandelt
        Komm.Ausgabe_ASCII = False
    End If
    Komm.Ausgabetext = Range("A17")
End If
End Sub


Private Sub Einstellungen()

If ObjPtr(Komm) <> 0 Then
    With Komm
        'Einstellung Kommunikationsschnittstelle
        .Baudrate = 1200
        .Datenbits = 8
        'Parity : 4=Leerzeichen / 3=Markierung
        '2=gerade / 1=ungerade / 0=keine

        .Parity = 0
        'Stopbits : 2=2 / 1=1,5 / 0=1
        .Stopbits = 0
        'Einstellungen Zeichensatzumwandlung der
        'Klasse übergeben

        .Eingang_ASCII = chbEmpfangAscii
        .Ausgabe_ASCII = chbSendenAscii
        'Einstellungen Komm
        .CTSOutFlowControl = chbCTSOutFlow
        .DSROutFlowControl = chbDSROutFlow
        .DSRSensitiv = chbDSRSensitiv
        .NoEOFCheck = chbNoEOFCheck
        .ParityCheck = chbParityCheck
        .XOFFCHAR = Range("B10")
        .XONCHAR = Range("B11")
        .XOffContinuesTx = chbXOffContinuesTx
        .XONInFlowControl = chbXONIn
        .XONOutFlowControl = chbXONOut
        .Baudrate = Range("B9")
        .Datenbits = Range("B7")
        .Parity = Range("B6")
        .Stopbits = Range("B8")
        .LängeEingabepuffer = Range("B5")
        .LängeAusgabepuffer = Range("B5")
    End With
End If
End Sub


Private Sub cmbOeffnen_Click()

Dim hwndCom As Long
'Neue Klasse clsSeriell
Set Komm = New clsSeriell
With Komm
    Einstellungen
    'Com-Port öffnen
    hwndCom = .KommunikationÖffnen(Range("B2"))
    If hwndCom <> 0 Then
        .RTS_Fest = chbRTS
        .DTR_Fest = chbDTR
        cbStatus_Click 'Steuerleitungen abfragen
        Me.Unprotect
            'Zustand farbig darstellen
            Range("B3").Interior.Color = vbRed
            Range("B4").Interior.ColorIndex = xlNone
            Range("B12") = hwndCom
        Me.Protect
    End If
End With
End Sub


Private Sub cmbSchliessen_Click()

On Error Resume Next
If ObjPtr(Komm) <> 0 Then
    'Com-Port schließen
    Komm.KommunikationSchließen
End If
Me.Unprotect
    'Zustand farbig darstellen
    Range("B4").Interior.Color = vbRed
    Range("B3").Interior.ColorIndex = xlNone
    Range("B12") = ""
Me.Protect
Set Komm = Nothing
End Sub

Private Sub Worksheet_Change(ByVal Target As Excel.Range)
 If Target.Column <> 2 Then Exit Sub
 If (Target.Row < 5) Or (Target.Row > 11) Then Exit Sub
 Einstellungen
End Sub

 

 

'**************************************************
'Ab hier beginnt die Klasse clsSeriell
************************************************** 

Option Explicit


' fBitFields
' FieldName             Bit #     Description
' -----------------     -----     ------------------------------
' fBinary                 1       binary mode, no EOF check
' fParity                 2       enable parity checking
' fOutxCtsFlow            3       CTS output flow control
' fOutxDsrFlow            4       DSR output flow control
' fDtrControl             5       DTR flow control type (2 bits)
' fDsrSensitivity         7       DSR sensitivity
' fTXContinueOnXoff       8       XOFF continues Tx
' fOutX                   9       XON/XOFF out flow control
' fInX                   10       XON/XOFF in flow control
' fErrorChar             11       enable error replacement
' fNull                  12       enable null stripping
' fRtsControl            13       RTS flow control (2 bits)
' fAbortOnError          15       abort reads/writes on error
' fDummy2                16       reserved

Private Type DCB
        DCBlength As Long
        Baudrate As Long
        fBitFields As Long
        wReserved As Integer
        XonLim As Integer
        XoffLim As Integer
        ByteSize As Byte
        Parity As Byte
        Stopbits As Byte
        XonChar As Byte
        XoffChar As Byte
        ErrorChar As Byte
        EofChar As Byte
        EvtChar As Byte
        wReserved1 As Integer
End Type
Private Type COMSTAT

    Bits As Long
    cbInQue As Long
    cbOutQue As Long
End Type
Private Type SECURITY_ATTRIBUTES

        nLength As Long
        lpSecurityDescriptor As Long
        bInheritHandle As Long
End Type
Private Declare Function CharToOem Lib "user32" Alias _
    "CharToOemA" ( _
    ByVal lpszSrc As String, _
    ByVal lpszDst As String _
    ) As Long
Private Declare Function OemToChar Lib "user32" Alias _
    "OemToCharA" ( _
    ByVal lpszSrc As String, _
    ByVal lpszDst As String _
    ) As Long
Private Declare Function CreateFile Lib "kernel32" Alias _
    "CreateFileA" ( _
    ByVal lpFileName As String, _
    ByVal dwDesiredAccess As Long, _
    ByVal dwShareMode As Long, _
    lpSecurityAttributes As SECURITY_ATTRIBUTES, _
    ByVal dwCreationDisposition As Long, _
    ByVal dwFlagsAndAttributes As Long, _
    ByVal hTemplateFile As Long _
    ) As Long
Private Declare Function CloseHandle Lib "kernel32" ( _
    ByVal hObject As Long _
    ) As Long
Private Declare Function SetCommBreak Lib "kernel32" ( _
    ByVal nCid As Long _
    ) As Long
Private Declare Function ClearCommBreak Lib "kernel32" ( _
    ByVal nCid As Long _
    ) As Long
Private Declare Function EscapeCommFunction& Lib "kernel32" _
    (ByVal nCid As Long, ByVal nFunc As Long)
Private Declare Function GetLastError Lib "kernel32" () As Long
Private Declare Function GetCommModemStatus& Lib "kernel32" ( _
    ByVal hFile As Long, _
    lpModemStat As Long)
Private Declare Function ReadFile Lib "kernel32" ( _
    ByVal hFile As Long, _
    ByVal lpBuffer As String, _
    ByVal nNumberOfBytesToRead As Long, _
    lpNumberOfBytesRead As Long, _
    ByVal NOlpOverlapped As Long _
    ) As Long
Private Declare Function WriteFile Lib "kernel32" ( _
    ByVal hFile As Long, _
    ByVal lpBuffer As String, _
    ByVal nNumberOfBytesToWrite As Long, _
    lpNumberOfBytesWritten As Long, _
    ByVal lpOverlapped As Long _
    ) As Long
Private Declare Function SetupComm Lib "kernel32" ( _
    ByVal hFile As Long, _
    ByVal dwInQueue As Long, _
    ByVal dwOutQueue As Long _
    ) As Long
Private Declare Function ClearCommError Lib "kernel32" ( _
    ByVal hFile As Long, _
    lpErrors As Long, _
    lpStat As COMSTAT _
    ) As Long
Private Declare Function SetCommState Lib "kernel32" ( _
    ByVal hCommDev As Long, _
    lpDCB As DCB _
    ) As Long
Private Declare Function GetCommState Lib "kernel32" ( _
    ByVal nCid As Long, _
    lpDCB As DCB _
    ) As Long
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const OPEN_EXISTING = 3
Private Const SETDTR = 5
Private Const SETRTS = 3
Private Const CLRDTR = 6
Private Const CLRRTS = 4
Private Const MS_DSR_ON = &H20&
Private Const MS_CTS_ON = &H10&
Private Const MS_RING_ON = &H40&
Private Const MS_RLSD_ON = &H80&
Private iEingabepuffer As Long, iAusgabepuffer As Long
Private iAusgabe_ASCII As Boolean, iEingang_ASCII As Boolean
Private ComHandle As Long, iWartezeit As Long
Private iBaudrate As Long, iDatenbits As Long
Private iStopbits As Long, iParity As Long
Private iXONCHAR As String, iXOFFCHAR As String
Private iCTSOutFlowControl As Boolean, iDSROutFlowControl As Boolean 'Bit 3, Bit 4
Private iXONOutFlowControl As Boolean, iXONInFlowControl As Boolean 'Bit 9, Bit 10
Private iParityCheck As Boolean, iNoEOFCheck As Boolean 'Bit 2, Bit 1
Private iDSRSensitiv As Boolean, iXOffContinuesTx As Boolean 'Bit 7, Bit 8

 
Private Function DTR(DTRAN As Boolean) As Boolean
'Steuerleitung DTR setzen
'DTR (Data Terminal Ready), Pin 4

Dim Fehler&
If DTRAN Then
    Fehler = EscapeCommFunction(ComHandle, SETDTR)
Else
    Fehler = EscapeCommFunction(ComHandle, CLRDTR)
End If
If Fehler <> 0 Then DTR = True
End Function
Private Function RTS(RTSAN As Boolean) As Boolean

'Steuerleitung RTS setzen
'RTS (Request To Send), Pin 7

Dim Fehler&
If RTSAN Then
    Fehler = EscapeCommFunction(ComHandle, SETRTS)
Else
    Fehler = EscapeCommFunction(ComHandle, CLRRTS)
End If
If Fehler <> 0 Then RTS = True
End Function
Private Function TXD(TXDAN As Boolean) As Boolean

'Sendeleitung Dauer High
'TXD (Transmit Data). Sendeleitung, Pin 3

Dim Fehler&
If TXDAN Then
    Fehler = SetCommBreak(ComHandle)
Else
    Fehler = ClearCommBreak(ComHandle)
End If
If Fehler <> 0 Then TXD = True
End Function
Private Function DCDstatus() As Boolean

'Status DCD
'DCD (Data Carrier Detect), Pin 1

Dim Status&
GetCommModemStatus ComHandle, Status
If Status And MS_RLSD_ON Then
    DCDstatus = True
Else
    DCDstatus = False
End If
End Function
Private Function RINGstatus() As Boolean

Dim Status&
GetCommModemStatus ComHandle, Status
If Status And MS_RING_ON Then
    RINGstatus = True
Else
    RINGstatus = False
End If
End Function
Private Function CTSstatus() As Boolean

Dim Status&
GetCommModemStatus ComHandle, Status
If Status And MS_CTS_ON Then
    CTSstatus = True
Else
    CTSstatus = False
End If
End Function
Private Function DSRstatus() As Boolean

'Status DSR
'DSR (Data Set Ready), Pin 6

Dim Status&
GetCommModemStatus ComHandle, Status
If Status And MS_DSR_ON Then
    DSRstatus = True
Else
    DSRstatus = False
End If
End Function


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'DTR Fest auf Ein

Public Property Let DTR_Fest(ByVal vNewValue As Boolean)
    DTR vNewValue
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'RTS Fest auf Ein

Public Property Let RTS_Fest(ByVal vNewValue As Boolean)
    RTS vNewValue
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'TXD Fest auf Ein

Public Property Let TXD_Fest(ByVal vNewValue As Boolean)
    TXD vNewValue
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Status Eingänge

Public Property Get DCD_Status() As Boolean
    DCD_Status = DCDstatus()
End Property
Public Property Get RING_Status() As Boolean

    RING_Status = RINGstatus()
End Property
Public Property Get CTS_Status() As Boolean

    CTS_Status = CTSstatus()
End Property
Public Property Get DSR_Status() As Boolean

    DSR_Status = DSRstatus()
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Puffergröße für Ein- und Ausgabe

Public Property Let LängeEingabepuffer(ByVal vNewValue As Long)
    iEingabepuffer = vNewValue
    KommunikationEinstellen
End Property
Public Property Get LängeEingabepuffer() As Long

    LängeEingabepuffer = iEingabepuffer
End Property
Public Property Let LängeAusgabepuffer(ByVal vNewValue As Long)

    iAusgabepuffer = vNewValue
    KommunikationEinstellen
End Property
Public Property Get LängeAusgabepuffer() As Long

    LängeAusgabepuffer = iAusgabepuffer
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Baudrate, Datenbits, Stopbits, Parity

Public Property Let Baudrate(ByVal vNewValue As Long)
    iBaudrate = vNewValue
    KommunikationEinstellen
End Property
Public Property Get Baudrate() As Long

    Baudrate = iBaudrate
End Property
Public Property Let Datenbits(ByVal vNewValue As Long)

    iDatenbits = vNewValue
    KommunikationEinstellen
End Property
Public Property Get Datenbits() As Long

    Datenbits = iDatenbits
End Property
Public Property Let Stopbits(ByVal vNewValue As Long)

    iStopbits = vNewValue
    KommunikationEinstellen
End Property
Public Property Get Stopbits() As Long

    Stopbits = iStopbits
End Property
Public Property Let Parity(ByVal vNewValue As Long)

    iParity = vNewValue
    KommunikationEinstellen
End Property
Public Property Get Parity() As Long

    Parity = iParity
End Property
Public Property Let XONCHAR(ByVal vNewValue As String)

    iXONCHAR = Left(vNewValue, 1)
    KommunikationEinstellen
End Property
Public Property Get XONCHAR() As String

    XONCHAR = iXONCHAR
End Property
Public Property Let XOFFCHAR(ByVal vNewValue As String)

    iXOFFCHAR = Left(vNewValue, 1)
    KommunikationEinstellen
End Property
Public Property Get XOFFCHAR() As String

    XOFFCHAR = iXOFFCHAR
End Property
Public Property Let CTSOutFlowControl(ByVal vNewValue As Boolean)

    iCTSOutFlowControl = vNewValue
    KommunikationEinstellen
End Property
Public Property Get CTSOutFlowControl() As Boolean

    CTSOutFlowControl = iCTSOutFlowControl
End Property
Public Property Let DSROutFlowControl(ByVal vNewValue As Boolean)

    iDSROutFlowControl = vNewValue
    KommunikationEinstellen
End Property
Public Property Get DSROutFlowControl() As Boolean

    DSROutFlowControl = iDSROutFlowControl
End Property
Public Property Let XONOutFlowControl(ByVal vNewValue As Boolean)

    iXONOutFlowControl = vNewValue
    KommunikationEinstellen
End Property
Public Property Get XONOutFlowControl() As Boolean

    XONOutFlowControl = iXONOutFlowControl
End Property
Public Property Let XONInFlowControl(ByVal vNewValue As Boolean)

    iXONInFlowControl = vNewValue
    KommunikationEinstellen
End Property
Public Property Get XONInFlowControl() As Boolean

    XONInFlowControl = iXONInFlowControl
End Property
Public Property Let ParityCheck(ByVal vNewValue As Boolean)

    iParityCheck = vNewValue
    KommunikationEinstellen
End Property
Public Property Get ParityCheck() As Boolean

    ParityCheck = iParityCheck
End Property
Public Property Let NoEOFCheck(ByVal vNewValue As Boolean)

    iNoEOFCheck = vNewValue
    KommunikationEinstellen
End Property
Public Property Get NoEOFCheck() As Boolean

    NoEOFCheck = iNoEOFCheck
End Property
Public Property Let DSRSensitiv(ByVal vNewValue As Boolean)

    iDSRSensitiv = vNewValue
    KommunikationEinstellen
End Property
Public Property Get DSRSensitiv() As Boolean

    DSRSensitiv = iDSRSensitiv
End Property
Public Property Let XOffContinuesTx(ByVal vNewValue As Boolean)

    iXOffContinuesTx = vNewValue
    KommunikationEinstellen
End Property
Public Property Get XOffContinuesTx() As Boolean

    XOffContinuesTx = iXOffContinuesTx
End Property

'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Wenn Ausgabe_ASCII Wahr, wird der Gesendete Text von Ansi
'nach Ascii umgewandelt, ansonsten wird unverändert gesendet

Public Property Let Ausgabe_ASCII(ByVal vNewValue As Boolean)
    iAusgabe_ASCII = vNewValue
End Property
Public Property Get Ausgabe_ASCII() As Boolean

    Ausgabe_ASCII = iAusgabe_ASCII
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Timeout Empfang

Public Property Let Timeout_Empfang(ByVal vNewValue As Long)
    If iWartezeit <= 0 Then iWartezeit = 1
    If iWartezeit >= 60 Then iWartezeit = 60
    iWartezeit = vNewValue
End Property
Public Property Get Timeout_Empfang() As Long

    Timeout_Empfang = iWartezeit
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Wenn Eingang_ASCII Wahr, wird der Eingegangene Text von Ascii
' nach Ansi umgewandelt, ansonsten wird unverändert gesendet

Public Property Let Eingang_ASCII(ByVal vNewValue As Boolean)
    iEingang_ASCII = vNewValue
End Property
Public Property Get Eingang_ASCII() As Boolean

    Eingang_ASCII = iEingang_ASCII
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Text für Ausgabe
'Wenn iAusgabe_ASCII Wahr, wird der Text von Ansi nach
'Ascii umgewandelt, ansonsten wird unverändert gesendet

Public Property Let Ausgabetext(ByVal vNewValue As String)
If iAusgabe_ASCII Then
    Senden NachAscii(vNewValue)
Else
    Senden vNewValue
End If
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Eingegangener Text
'Wenn iEingang_ASCII Wahr, wird der Text von Ascii nach
'Ansi umgewandelt, ansonsten wird unverändert empfangen

Public Property Get EingegangenerText() As String
If iEingang_ASCII Then
    EingegangenerText = NachAnsi(Empfangen())
Else
    EingegangenerText = Empfangen()
End If
End Property


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Daten auslesen und Senden

Private Function Empfangen()
Dim ret As Long, Puffer As String, geschrieben As Long
Dim gebraucht As Long, comerror As Long
Dim Status As COMSTAT, TimeoutWaitForInput As Date
'Beenden, wenn schon ein Port offen ist
If ComHandle = 0 Then Exit Function
'Timeoutüberprüfung Empfang
If iWartezeit <= 0 Then iWartezeit = 1
If iWartezeit >= 60 Then iWartezeit = 60
'Zu diesem Zeitpunkt wird spätestens abgebrochen
TimeoutWaitForInput = Now + TimeSerial(0, 0, iWartezeit)
Do
    'Nachschauen, ob was eingegangen ist
    ClearCommError ComHandle, comerror, Status
    'Anzahl der Zeichen im Einganspuffer ermitteln
    gebraucht = Status.cbInQue
    If gebraucht > 0 Then
        'Puffer auslesen
        Puffer = String(gebraucht, 0)
        ReadFile ComHandle, Puffer, gebraucht, geschrieben, 0
        Exit Do
    End If
    'Beenden, wenn Zeit abgelaufen ist
    If Now > TimeoutWaitForInput Then Exit Do
Loop While gebraucht = 0
Empfangen = Puffer
End Function


Private Function Senden(Text As String)

Dim geschrieben As Long
'Beenden, wenn kein Port offen
If ComHandle = 0 Then Exit Function
'Text in den Ausgabepuffer schieben
WriteFile ComHandle, Text, Len(Text), geschrieben, 0
End Function


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Kommunikation Öffnen und schließen
'Comport als Text übergeben z.B. com1, com2 etc. ..

Public Function KommunikationSchließen() As Boolean
    KommunikationSchließen = CloseHandle(ComHandle) <> 0
    ComHandle = 0
End Function


Public Function KommunikationÖffnen(Optional Port As String) As Long

Dim Sicherheit As SECURITY_ATTRIBUTES
Dim Zugriff As Long, Fehler As Long
Dim Einstellungen As DCB
Dim Flags As Long, Korr As Integer
On Error GoTo fehlerbehandlung
Zugriff = GENERIC_READ Or GENERIC_WRITE
If Port = "" Then Port = "COM1"
Sicherheit.nLength = 12
Sicherheit.bInheritHandle = 0
Sicherheit.lpSecurityDescriptor = 0
Fehler = GetLastError
If ComHandle <> 0 Then GoTo fehlerbehandlung
'Com öffnen
ComHandle = CreateFile(Port, Zugriff, 0&, Sicherheit, _
    OPEN_EXISTING, 0&, 0&)
'Einstellung setzen
KommunikationEinstellen
fehlerbehandlung:
KommunikationÖffnen = ComHandle
End Function


Private Sub KommunikationEinstellen()

Dim Einstellungen As DCB
Dim Flags As Long, Korr As Integer
If ComHandle = 0 Then Exit Sub
'Datenbits
If (iDatenbits < 5) Or (iDatenbits > 8) Then iDatenbits = 8
'Baudrate
Select Case iBaudrate
    Case 110, 300, 1200, 2400, 4800, 9600
    Case 19200, 38400, 57600, 115200
    Case Else
        iBaudrate = 9600
End Select
'Stopbits
Select Case iStopbits
    Case 2
        iStopbits = 2
    Case 1.5
        iStopbits = 1
    Case Else
        iStopbits = 0
End Select
'Parity : 4=Leerzeichen / 3=Markierung
'2=gerade / 1=ungerade / 0=keine

If (iParity > 4) Or (iParity < 0) Then iParity = 0
'GetCommState ComHandle, Einstellungen
With Einstellungen
    .ByteSize = iDatenbits
    .Parity = iParity
    .Baudrate = iBaudrate
    .Stopbits = iStopbits
    .XONCHAR = Asc(iXONCHAR)
    .XOFFCHAR = Asc(iXOFFCHAR)
    'Anscheinend fängt beim Kommentar in der Win32Api.txt die
    'Zählung der Bits bei 1 an. Ich bin mir aber nicht sicher,
    'deshalb Kurrektur vorgesehen.
    'Bei 1. Bit Zählung = 1,  korr=1
    'Bei 1. Bit Zählung = 0,  korr=0

    Korr = 1
    '-----------
    Flags = 2 ^ (3 - Korr)
    If iCTSOutFlowControl Then
        .fBitFields = .fBitFields Or Flags
    Else
        .fBitFields = .fBitFields And (Not Flags)
    End If
    '-----------
    Flags = 2 ^ (4 - Korr)
    If iDSROutFlowControl Then
        .fBitFields = .fBitFields Or Flags
    Else
        .fBitFields = .fBitFields And (Not Flags)
    End If
    '-----------
    Flags = 2 ^ (9 - Korr)
    If iXONOutFlowControl Then
        .fBitFields = .fBitFields Or Flags
    Else
        .fBitFields = .fBitFields And (Not Flags)
    End If
    '-----------
    Flags = 2 ^ (10 - Korr)
    If iXONInFlowControl Then
        .fBitFields = .fBitFields Or Flags
    Else
        .fBitFields = .fBitFields And (Not Flags)
    End If
    '-----------
    Flags = 2 ^ (2 - Korr)
    If iParityCheck Then
        .fBitFields = .fBitFields Or Flags
    Else
        .fBitFields = .fBitFields And (Not Flags)
    End If
    '-----------
    Flags = 2 ^ (1 - Korr)
    If iNoEOFCheck Then
        .fBitFields = .fBitFields Or Flags
    Else
        .fBitFields = .fBitFields And (Not Flags)
    End If
    '-----------
    Flags = 2 ^ (7 - Korr)
    If iDSRSensitiv Then
        .fBitFields = .fBitFields Or Flags
    Else
        .fBitFields = .fBitFields And (Not Flags)
    End If
    '-----------
    Flags = 2 ^ (8 - Korr)
    If iXOffContinuesTx Then
        .fBitFields = .fBitFields Or Flags
    Else
        .fBitFields = .fBitFields And (Not Flags)
    End If
End With
'Com-Einstellungen setzen
SetCommState ComHandle, Einstellungen
'Puffer setzen
If iEingabepuffer = 0 Then iEingabepuffer = 4096
If iAusgabepuffer = 0 Then iAusgabepuffer = 4096
SetupComm ComHandle, iEingabepuffer, iAusgabepuffer
End Sub


'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'Umwandlungsfunktionen

Public Function NachAnsi(ByVal Quelle As String) As String
Dim Zielzeichenkette$, dummy&
Zielzeichenkette = String(Len(Quelle), 0)
dummy = OemToChar(Quelle, Zielzeichenkette)
NachAnsi = Zielzeichenkette
End Function
Public Function NachAscii(ByVal Quelle As String) As String

Dim Zielzeichenkette$, dummy&
Zielzeichenkette = String(Len(Quelle), 0)
dummy = CharToOem(Quelle, Zielzeichenkette)
NachAscii = Zielzeichenkette
End Function


Private Sub Class_Terminate()

    KommunikationSchließen
End Sub
Public Sub AllePortsSchließen()

Dim i As Long
Do
    i = i + 1
    If i > 1000000 Then Exit Do
Loop While CloseHandle(i) = 0
ComHandle = 0
End Sub