• [VB.NET] Rs232 通讯 COM口


    来源:http://www.fenbi360.net/Content.aspx?id=1011&t=jc

    RS232数据处理.vb

    Imports System.Text
    Imports System.IO
    Imports System.Threading

    Public Class RS232数据处理
    Dim crs232 As New cRS232
    Dim WithEvents Hrs232 As New cRS232
    Dim fportopen As Boolean
    Dim mydb As dataload = New dataload()
    Dim curid As String
    ''' <summary>
    ''' 打开端口
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btnOPEN_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOPEN.Click
    Try
    btnOPEN.Enabled
    = False
    If fportopen Then
    crs232.PortOpen
    = False
    btnOPEN.Text
    = " 打开通信端口"
    fportopen
    = False
    If crs232.CommPort = 1 Then
    RBCom1.ForeColor
    = RBCOM2.ForeColor
    Else
    RBCOM2.ForeColor
    = RBCom1.ForeColor
    End If
    Timer1.Enabled
    = True
    Exit Sub
    End If
    If RBCom1.Checked Then
    crs232.CommPort
    = 1 '打开COM1
    Else
    crs232.CommPort
    = 2 'COM2
    End If
    '参数据设置
    crs232.BaudRate = crs232.eBaudrates.BR_9600
    crs232.DataBit
    = crs232.eDataBit.Bit_8
    crs232.Parity
    = crs232.eDataParity.Parity_None
    crs232.StopBit
    = crs232.eDataStopBit.StopBit_1
    crs232.PortOpen
    = True '使用默认值打开通信端口
    fportopen = True
    btnOPEN.Text
    = "关闭通信端口"
    If RBCom1.Checked Then
    RBCom1.ForeColor
    = Color.Blue
    Else
    RBCOM2.ForeColor
    = Color.Blue
    End If
    Timer1.Enabled
    = True
    Catch ex As Exception
    MsgBox(ex.Message)
    Finally
    btnOPEN.Enabled
    = True
    End Try
    End Sub
    '发送信息
    Private Sub btnsend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnsend.Click

    If Not fportopen Then
    MsgBox(" 必须先打开通信端口")
    Exit Sub
    End If
    Try
    btnsend.Enabled
    = False
    crs232.Write(txtsend.Text)

    Catch ex As Exception
    MsgBox(ex.Message)
    Finally
    btnsend.Enabled
    = True
    End Try

    End Sub
    '接收信息事件
    Private Sub rs232_ondatareceived() ' Handles Hrs232.OnDataReceived
    Dim strinput As String, readno As Integer
    Try

    crs232.Read(readno, strinput)
    txtreceive.Text
    &= ControlChars.CrLf + strinput
    Catch ex As Exception
    MsgBox(ex.Message)
    End Try
    Try
    Dim strsql As String
    strsql
    = "insert into tbreceive(C_Code,C_Receive,C_Date) values('" + Me.txtsend.Text + "','" + strinput + "','" + Date.Now.ToString() + "')"
    mydb.sqldelorupdata(strsql)
    Catch ex As Exception

    End Try
    End Sub

    Private Sub RS232数据处理_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Me.tbreceive.AutoGenerateColumns = False
    End Sub

    'Private Sub RBCom1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RBCom1.Click
    ' If (fportopen) And crs232.CommPort = 2 Then
    ' RBCOM2.Checked = True
    ' MsgBox(" 请先关闭COM2端口")
    ' Return
    ' End If
    'End Sub

    'Private Sub RBCOM2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RBCOM2.Click
    ' If (fportopen) And crs232.CommPort = 1 Then
    ' RBCom1.Checked = True
    ' MsgBox(" 请先关闭COM1端口")
    ' Return
    ' End If
    'End Sub

    Private Sub RS232数据处理_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
    crs232.PortOpen
    = False
    If crs232.Timer1.Enabled Then
    crs232.Timer1.Stop()
    End If
    Application.Exit()
    End Sub
    ''' <summary>
    ''' 设置DTR状态 高低电位
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btndtr_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btndtr.Click
    If Not crs232.PortOpen Then Exit Sub
    crs232.DTR
    = Not crs232.DTR
    End Sub
    ''' <summary>
    ''' 设置RTS状态 高低电位
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btnrts_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnrts.Click
    If Not crs232.PortOpen Then Exit Sub
    crs232.RTS
    = Not crs232.RTS
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    If crs232.RTS Then
    lbrts.BackColor
    = Color.Red
    Else
    lbrts.BackColor
    = Color.White
    End If
    If crs232.DTR Then
    lbdtr.BackColor
    = Color.Red
    Else
    lbdtr.BackColor
    = Color.White
    End If
    If crs232.CTSHolding Then
    lbcts.BackColor
    = Color.Red
    Else
    lbcts.BackColor
    = Color.White
    End If
    If crs232.DSRHolding Then
    lbdsr.BackColor
    = Color.Red
    Else
    lbdsr.BackColor
    = Color.White
    End If
    If crs232.CDHolding Then
    lbcd.BackColor
    = Color.Red
    Else
    lbcd.BackColor
    = Color.White
    End If
    If crs232.RIHolding Then
    lbri.BackColor
    = Color.Red
    Else
    lbri.BackColor
    = Color.White
    End If
    If (crs232.miReceived > 0) Then
    crs232.miReceived
    = 0
    rs232_ondatareceived()
    End If

    End Sub

    Private Sub btnlook_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnlook.Click
    If btnlook.Text.Trim() = "查看历史记录" Then
    btnlook.Enabled
    = False
    Me.Width = Me.Width + 290
    Me.tbreceive.Visible = True
    btnlook.Text
    = "隐藏记录"
    btnlook.Enabled
    = True
    loaddata()
    Else
    btnlook.Enabled
    = False
    Me.Width = Me.Width - 290
    Me.tbreceive.Visible = False
    btnlook.Text
    = "查看历史记录"
    btnlook.Enabled
    = True
    End If


    End Sub

    Private Sub loaddata()
    Dim mytb As DataTable
    Try
    mytb
    = mydb.openoledbdata("select * from tbreceive order by C_Date desc")
    Me.tbreceive.DataSource = mytb

    tbreceive.Refresh()
    Catch ex As Exception

    End Try
    End Sub

    Private Sub 发送SToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles 发送SToolStripMenuItem.Click
    btnsend_Click(sender, e)
    End Sub

    Private Sub 查看历史记录LToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles 查看历史记录LToolStripMenuItem.Click
    btnlook_Click(
    Me.btnlook, e)
    End Sub

    Private Sub 打开端口OToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles 打开端口OToolStripMenuItem.Click
    Me.btnOPEN_Click(btnOPEN, e)
    End Sub

    Private Sub 退出EToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles 退出EToolStripMenuItem.Click
    Me.Close()
    Application.Exit()
    End Sub

    Private Sub btndel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btndel.Click
    Try
    Dim strsql As String
    If (Date.Parse(txtsdate.Text) > Date.Parse(txtedate.Text)) Then
    MessageBox.Show(
    "起始时间不可大于结束时间!")
    Return
    End If

    If (MessageBox.Show("您确认要删除从" + txtsdate.Text + "" + txtedate.Text + "的记录吗?", "确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1) = Windows.Forms.DialogResult.Cancel) Then
    Return
    End If

    strsql
    = "delete from tbreceive where C_Date between cdate('" + Me.txtsdate.Text + "') and cdate('" + Me.txtedate.Text + "')"
    mydb.sqldelorupdata(strsql)
    loaddata()
    MessageBox.Show(
    "删除成功!")
    Catch ex As Exception
    MessageBox.Show(
    "删除失败!")
    End Try
    End Sub
    End Class

    cRS232.vb

    Imports System.Runtime.InteropServices
    Imports System.ComponentModel
    Imports System.Text
    Imports System.Threading
    Imports System.Windows.Forms

    Public Class cRS232
    Public WithEvents Timer1 As System.Windows.Forms.Timer '声明一个定时器
    #Region "类头部"
    #Region "各种参数枚举"
    '极性位设置
    Public Enum eDataParity
    Parity_None
    = 0
    Parity_Odd
    Parity_Even
    Parity_Mark
    End Enum
    '停止位设置
    Public Enum eDataStopBit
    StopBit_1
    = 0
    StopBit_2
    = 2
    End Enum
    '数据位设置
    Public Enum eDataBit
    Bit_5
    = 5
    Bit_6
    = 6
    Bit_7
    = 7
    Bit_8
    = 8
    End Enum
    '硬件握手设置
    Public Enum eHwHandShake
    hhNone
    = 0
    hhRtsOn
    = 1
    hhRtsCts
    = 2
    hhDtrOn
    = 3
    hhDtrDsr
    = 4
    End Enum
    ''软件握手设置
    Public Enum eSwHandShake
    shNone
    = 0
    shXonXoff
    = 1
    End Enum
    '缓冲区清除设置
    Public Enum ePurgeBuffers
    PXAbort
    = &H2
    PXClear
    = &H8
    TxAbort
    = &H1
    txClear
    = &H4
    End Enum
    '串行通信硬件线路设置 (EscapeFunction)
    Public Enum eLines
    SetXoff
    = 1 '当接收到xoff 字符时启动传输操作
    SetXon = 2 '当接收到XON字符时启动传输操作
    SetRts = 3 '将RTS线路升成高电位
    ClearRts = 4 '将RTS线路降成低电位
    SetDtr = 5 '将DTR线路升成高电位
    ClearDtr = 6 '将DTR线路降为低电位
    ResetDev = 7 '重置设备
    SetBreak = 8 '设置通信状态为中断(送出BREAK信号)
    ClearBreak = 9 '清除 BREAK信号,使传输操作继续
    End Enum
    '调制解调器专用状态位设置
    <Flags()> Public Enum eModemStatusBits
    ClearToSendOn
    = &H10
    DataSetReadOn
    = &H20
    RingIndicatorOn
    = &H40
    CarrierDetect
    = &H80
    End Enum
    '事件屏蔽设置
    <Flags()> Public Enum eEventMasks
    RxChar
    = &H1 '输入缓冲区已收到一个字符
    RXFlag = &H2 '使用 setcommstate函数设置的DCB结构中的等待字符已被传入输入缓冲区
    TxBufferEmpty = &H4 '在输出缓冲区中的数据已被完全送出
    ClearToSend = &H8 'CTS(Clear to send)线路发生变化
    DataSetReady = &H10 'DSR线路发生变化
    ReceiveLine = &H20 'CD线路信号发生变化
    Break = &H40 '收到BREAK信号
    StatusError = &H80 '线路状态错误,包括了CE——FRAME和CE——OVERRUN,CE——RXPARITY三种错误
    Ring = &H100 '检测到响铃信号
    End Enum
    'DCB设置常数
    <Flags()> Public Enum eBitDef
    dcb_Binary
    = &H1
    dcb_parityCheck
    = &H2
    dcb_OutxCtsFlow
    = &H4
    dcb_OutxDsrFlow
    = &H8
    dcb_DtrControlMask
    = &H30
    dcb_DtrControlDisable
    = &H0
    dcb_DtrControlEnable
    = &H10
    dcb_DtrControlHandshake
    = &H20
    dcb_DsrSendsivity
    = &H40
    dcb_TXContinueOnXoff
    = &H80
    dcb_Outx
    = &H100
    dcb_InX
    = &H200
    dcb_ErrorChar
    = &H400
    dcb_NullStrip
    = &H800
    dcb_RtsControlMask
    = &H3000
    dcb_RtsControlToggle
    = &H3000
    dcb_RtsControldisable
    = &H0
    dcb_RtsControlEnable
    = &H1000
    dcb_RtscontrolHandShake
    = &H2000
    dcb_AbortOnError
    = &H4000
    dcb_Reserveds
    = &HFFFF8000
    End Enum
    '通信端口错误常数
    <Flags()> Public Enum eCommError
    CE_DREAK
    = &H10
    CE_DNS
    = &H800
    CE_FRAME
    = &H8
    CE_IOE
    = &H400
    CE_MODE
    = &H8000
    CE_OOP
    = &H1000
    CE_PTO
    = &H200
    CE_OVERRUN
    = &H2
    CE_RXOVER
    = &H1
    End Enum
    '通信端口线路状态检测常数
    <Flags()> Public Enum eCommErrorLine
    fCtsHold
    = &H1 '等待CTS信号准备传送
    fDsrHold = &H2 '等待DRS信号准备传送
    fRlsdHold = &H4 '等待RLAS信号准备传送
    fXoffHold = &H8 ' 收到XOFF字符停止传送
    fXoffSent = &H10 '已送出XOFF字符,停止传送
    fEof = &H20 'EOF字符已送出
    fTxim = &H40 '字符等待传送
    End Enum
    '通信速度的设置枚举
    Public Enum eBaudrates
    BR_110
    = 100
    BR_300
    = 300
    BR_600
    = 600
    BR_1200
    = 1200
    BR_2400
    = 2400
    BR_4800
    = 4800
    BR_9600
    = 9600
    BR_14400
    = 14400
    BR_19200
    = 19200
    BR_38400
    = 38400
    BR_56000
    = 56000
    BR_57600
    = 57600
    BR_115200
    = 115200
    End Enum
    #End Region
    #Region "结构"
    'Device Control block 结构声明
    <StructLayout(LayoutKind.Sequential, Pack:=1)> Public Structure DCB
    Public DCBlength As Int32
    Public BaudRate As Int32
    Public Bits1 As Int32
    Public wReserved As Int16
    Public XonLim As Int16
    Public XoffLim As Int16
    Public ByteSize As Byte
    Public Parity As Byte
    Public StopBits As Byte
    Public XonChar As Char
    Public XoffChar As Char
    Public ErrorChar As Char
    Public EofChar As Char
    Public EvtChar As Char
    Public wReserved2 As Int16
    End Structure
    '通信端口状态结构
    <StructLayout(LayoutKind.Sequential, Pack:=1)> Public Structure COMSTAT
    Dim fBitFields As Int32
    Dim cbInQue As Int32
    Dim cbOutQue As Int32
    End Structure
    '超时设置结构
    <StructLayout(LayoutKind.Sequential, Pack:=1)> Public Structure COMMTIMEOUTS
    Public ReadIntervalTimeout As Int32
    Public ReadTotalTimeoutMultiplier As Int32
    Public ReadTotalTimeoutConstant As Int32
    Public WriteTotalTimeoutMultiplier As Int32
    Public WriteTotalTimeoutConstant As Int32
    End Structure
    '通信端口配置结构
    <StructLayout(LayoutKind.Sequential, Pack:=8)> Public Structure COMMCONFIG
    Public dwSize As Int32
    Public wVersion As Int16
    Public wReserved As Int16
    Public dcbx As DCB
    Public dwProviderSubType As Int32
    Public dwProviderOffset As Int32
    Public dwProviderSize As Int32
    Public wcProviderData As Int16
    End Structure
    '异步传输的设置结构
    <StructLayout(LayoutKind.Sequential, Pack:=1)> Public Structure OVERLAPPED
    Public Internal As Int32
    Public InternalHigh As Int32
    Public Offset As Int32
    Public OffsetHigh As Int32
    Public hEvent As IntPtr
    End Structure
    #End Region
    #Region "常数"
    Private Const PURGE_RXABORT As Integer = &H2
    Private Const PURGE_RXCLEAR As Integer = &H8
    Private Const PURGE_TXABORT As Integer = &H1
    Private Const PURGE_TXCLEAR As Integer = &H4
    Private Const GENERIC_READ As Integer = &H80000000 '打开通信端口时的参数
    Private Const GENERIC_WRITE As Integer = &H40000000 '打开通信端口时的参数
    Private Const OPEN_EXISTING As Integer = 3 '打开通信端口时的参数
    Private Const INVALID_HANDLE As Integer = -1 '通信端口关闭时的Handle值
    Private Const IO_BUFFER_SIZE As Integer = 1024
    Private Const FILE_FLAG_OVERLAPPED As Int32 = &H40000000
    Private Const ERROR_IO_PENDING As Int32 = 997
    Private Const WAIT_OBJECT_0 As Int32 = 0
    Private Const ERROR_IO_INCOMPLETE As Int32 = 996
    Private Const WAIT_TIMEOUT As Int32 = &H102&
    Private Const INFINITE As Int32 = &HFFFFFFFF
    Private Const TIMER_INTERVAL As Int16 = 10 ' 定时器所使用的时间隔
    #End Region
    #Region "局部变量"
    Private mabtRxBuf As Byte()
    'Private meMode As eMode
    Private moThreadTx As Thread
    Private moThreadRx As Thread
    Private moEvents As Thread
    Private miTmpBytes2Read As Int32
    Private meMask As eEventMasks
    Private mbDisposed As Boolean
    Private mbUseXonXoff As Boolean
    Private mbEnableEvents As Boolean
    Private miBufThreshold As Int32 = 1
    Private muOvlE As OVERLAPPED
    Private muOvlW As OVERLAPPED
    Private muOvlR As OVERLAPPED
    Private mhRS As IntPtr = INVALID_HANDLE '// 串口的handle
    Private miPort As Integer = 1 '// 默认通信端口为COM1
    Private mfPortOpen As Boolean '通信端口打开状态
    Private meBaudrate As eBaudrates = eBaudrates.BR_9600 '9600bps
    Private miTimeout As Int32 = 70 '//
    Private miBaudRate As Int32 = 9600
    Private meParity As eDataParity = eDataParity.Parity_None '无同位校验
    Private mstopBit As eDataStopBit = eDataStopBit.StopBit_1 '停止校验位为1
    Private meDataBit As eDataBit = eDataBit.Bit_8 '数据长度为8
    Private meHwHandshake As eHwHandShake = eHwHandShake.hhNone '默认为无硬件握手
    Private meSwHandshake As eSwHandShake = eSwHandShake.shNone '默认为无软件握手
    Private meCommEvent As eEventMasks '通信事件号码
    Private meCommError As eCommError ' 错误号码
    Private mDCBBit As eBitDef '控制区块变量
    Private mReadLen As Integer '每次READ命令的读取字节数
    Private mRThreshold As Integer = 1 '触发ondatareceived事件阈值
    Private mCDHolding As Boolean 'CD的针脚状态
    Private mDSRHolding As Boolean 'DSR的针脚状态
    Private mCTSHolding As Boolean 'CTS的针脚状态
    Private mRIHolding As Boolean 'RI的针脚状态
    Private meStopBit As eDataStopBit = 0
    Private miDataBit As Int32 = 8
    Private mHE As GCHandle
    Private mHR As GCHandle
    Private mHW As GCHandle
    Private mDTR As Boolean 'DTR状态
    Private mRTS As Boolean 'RTS状态
    Private mfTimer As Boolean '记录定时器的状态
    Private miBufferSize As Integer = 512 '默认缓冲区512bytes
    Public miReceived As Integer = 0 '已收到数据
    #End Region
    #Region "属性"
    '通信端口号码属性设置
    Public Property CommPort() As Integer
    Get
    Return miPort
    End Get
    Set(ByVal value As Integer)
    miPort
    = value
    End Set
    End Property
    '''设置端口开关
    ''' 设置会调用OpenCom及CloseCom
    Public Property PortOpen() As Boolean
    Get
    Return mfPortOpen
    End Get
    Set(ByVal value As Boolean)
    If value Then '打开
    If mfPortOpen Then '已经打开
    Throw New Exception(" 通信端口已打开")
    Exit Property
    End If
    If Not OpenCOM() Then
    Throw New Exception(" 通信端口打开错误(端口被其它程序占用或不存在此端口)!")
    Exit Property
    End If
    mfPortOpen
    = True
    mfTimer
    = True
    If Not Timer1.Enabled Then
    Timer1.Start()
    End If

    Else '关闭通信端口
    If Not CloseCOM() Then '调用关闭端口
    Throw New Exception("通信端口关闭错误")
    Exit Property
    End If
    mfPortOpen
    = False
    End If
    End Set
    End Property
    '设置通信速度,利用枚举比较方便
    Public Property BaudRate() As eBaudrates
    Get
    Return meBaudrate
    End Get
    Set(ByVal value As eBaudrates)
    meBaudrate
    = value
    End Set
    End Property
    '************************************************************
    '硬件握手设置
    '************************************************************
    Public Property hwhandShaking() As eHwHandShake
    Get
    Return meHwHandshake
    End Get
    Set(ByVal value As eHwHandShake)
    meHwHandshake
    = value
    End Set
    End Property
    '************************************************************
    '软件握手设置
    '************************************************************
    Public Property swhandShaking() As eSwHandShake
    Get
    Return meSwHandshake
    End Get
    Set(ByVal value As eSwHandShake)
    meSwHandshake
    = value
    End Set
    End Property
    '数据位设置
    Public Property DataBit() As eDataBit
    Get
    Return meDataBit
    End Get
    Set(ByVal Value As eDataBit)
    meDataBit
    = Value
    End Set
    End Property
    '停止位设置
    Public Property StopBit() As eDataStopBit
    Get
    Return meStopBit
    End Get
    Set(ByVal Value As eDataStopBit)
    meStopBit
    = Value
    End Set
    End Property
    '同位校验设置
    Public Property Parity() As eDataParity
    Get
    Return meParity
    End Get
    Set(ByVal Value As eDataParity)
    meParity
    = Value
    End Set
    End Property
    '通信事件(只读)
    Public ReadOnly Property CommEvent() As eEventMasks
    Get
    Return meCommEvent
    End Get
    End Property
    '通信错误(只读)
    Public ReadOnly Property CommError() As eCommError
    Get
    Return meCommError
    End Get
    End Property
    '每次读取操作的字节数,使用read命令时可以指定
    Public Property ReadLen() As Integer
    Get
    Return mReadLen
    End Get
    Set(ByVal value As Integer)
    mReadLen
    = value
    End Set
    End Property
    ';触发 ondatareceived事件的阈值,可以设置启动事件的阈值
    Public Property RThreshold() As Integer
    Get
    Return mRThreshold
    End Get
    Set(ByVal value As Integer)
    mRThreshold
    = value
    End Set
    End Property
    'DSR线路状态,TRUE、FALSE 高电位置、位电位
    Public ReadOnly Property DSRHolding() As Boolean
    Get
    Return mDSRHolding
    End Get
    End Property
    'CTS线路状态 true,false 高电位,低电位
    Public ReadOnly Property CTSHolding() As Boolean
    Get
    Return mCTSHolding
    End Get
    End Property
    'RI线路状态 true,false 高电位,低电位
    Public ReadOnly Property RIHolding() As Boolean
    Get
    Return mRIHolding
    End Get
    End Property
    'CD线路状态 true,false 高电位,低电位
    Public ReadOnly Property CDHolding() As Boolean
    Get
    Return mCDHolding
    End Get
    End Property
    'DTR线路状态控制 true,false 高电位,低电位
    Public Property DTR() As Boolean
    Get
    Return mDTR
    End Get
    Set(ByVal value As Boolean)
    If SetDTR(value) Then
    mDTR
    = value
    End If
    End Set
    End Property
    'RTS线路状态控制 true,false 高电位,低电位
    Public Property RTS() As Boolean
    Get
    Return mRTS
    End Get
    Set(ByVal value As Boolean)
    If SetRTS(value) Then
    mRTS
    = value
    End If
    End Set
    End Property
    #End Region
    #End Region

    '事件声明
    Public Event OnDataReceived() '收到RThreshold规定的数据
    Public Event OnCommError(ByVal ErrNo As eCommError) '错误发生
    Public Event OnEvent(ByVal EventMo As eEventMasks) '事件

    #Region "方法"
    ''' <summary>
    ''' 打开COM口
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function OpenCOM() As Boolean
    Dim udcb As DCB, irc As Integer
    Dim sdcbstate As String
    If miPort > 0 Then
    '打开通信端口
    mhRS = rs232api.CreateFile("COM" & miPort.ToString(), GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0)
    If mhRS <> -1 Then
    ' 清除通信错误
    Dim lperrcode As Integer
    irc
    = rs232api.ClearCommError(mhRS, lperrcode, Nothing)
    '清除缓冲区
    irc = rs232api.PurgeComm(mhRS, ePurgeBuffers.PXClear Or ePurgeBuffers.txClear)
    '取得通信端口设置值,并填入DCB结构
    irc = rs232api.SetupComm(mhRS, miBufferSize, miBufferSize)
    irc
    = rs232api.GetCommState(mhRS, udcb)
    ' 以下将通信端口设置值填入
    udcb.BaudRate = meBaudrate
    udcb.ByteSize
    = meDataBit
    udcb.Parity
    = meParity
    udcb.StopBits
    = meStopBit
    'BITL参数的设置指定
    mDCBBit = 0
    Select Case meHwHandshake '硬件握手状况
    Case eHwHandShake.hhNone
    mDCBBit
    = mDCBBit Or eBitDef.dcb_RtsControldisable
    Case eHwHandShake.hhRtsOn
    mDCBBit
    = mDCBBit Or eBitDef.dcb_RtsControlEnable
    Case eHwHandShake.hhRtsCts
    mDCBBit
    = mDCBBit Or eBitDef.dcb_DtrControlHandshake
    mDCBBit
    = mDCBBit Or eBitDef.dcb_OutxCtsFlow
    Case eHwHandShake.hhDtrOn
    mDCBBit
    = mDCBBit Or eBitDef.dcb_DtrControlEnable
    Case eHwHandShake.hhDtrDsr
    mDCBBit
    = mDCBBit Or eBitDef.dcb_DtrControlHandshake
    End Select
    ' 软件握手状况
    Select Case meSwHandshake
    Case eSwHandShake.shNone
    Case eSwHandShake.shXonXoff
    mDCBBit
    = mDCBBit Or eBitDef.dcb_InX Or eBitDef.dcb_Outx
    End Select
    udcb.Bits1
    = mDCBBit
    irc
    = rs232api.SetCommState(mhRS, udcb) '将DCB设置进去
    If irc = 0 Then
    Return False '设置错误返回
    End If
    '打开通信端口时,将 DTR,RTS均拉至低电位
    SetDTR(False)
    SetRTS(
    False)
    mDTR
    = False
    mRTS
    = False
    Return True
    Else
    ' 打开错误
    Return False '打开错误。返回
    End If
    Else
    Return False '串口未定义,返回
    End If
    End Function
    ''' <summary>
    ''' 关闭COM口
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function CloseCOM() As Boolean
    If mhRS <> INVALID_HANDLE Then
    mfTimer
    = False
    Do
    If Timer1.Enabled = False Then Exit Do
    Application.DoEvents()
    Loop
    rs232api.CloseHandle(mhRS)
    mhRS
    = INVALID_HANDLE
    End If
    Return True
    End Function
    #End Region

    Public Sub New()
    Timer1
    = New System.Windows.Forms.Timer
    'Timer1 = New System.Windows.Forms.Timer()
    Timer1.Interval = TIMER_INTERVAL
    Timer1.Enabled
    = False
    End Sub
    '===================================================
    '将字节传出去,
    '===================================================
    Public Overloads Sub Write(ByVal Buffer As Byte())
    Dim iRc, iBytesWritten As Integer, hOvl As GCHandle
    '-----------------------------------------------------------------
    muOvlW = New OVERLAPPED
    If mhRS.ToInt32 <= 0 Then
    Throw New ApplicationException("请先打开端口")
    Else
    Try
    iRc
    = RS232API.WriteFile(mhRS, Buffer, Buffer.Length, 0, muOvlW)
    If iRc = 0 Then
    If Marshal.GetLastWin32Error <> ERROR_IO_PENDING Then
    Throw New ApplicationException("指定失败")
    Else
    If RS232API.GetOverlappedResult(mhRS, muOvlW, iBytesWritten, 1) = 0 Then
    Throw New ApplicationException("写入失败")
    Else
    If iBytesWritten <> Buffer.Length Then Throw New ApplicationException("写入字节失败" & iBytesWritten.ToString & " of " & Buffer.Length.ToString)
    End If
    End If
    End If
    Finally
    '//Closes handle
    RS232API.CloseHandle(muOvlW.hEvent)
    If (hOvl.IsAllocated = True) Then hOvl.Free()
    End Try
    End If
    End Sub
    Public Overloads Sub Write(ByVal Buffer As String)

    Dim aByte() As Byte = System.Text.Encoding.Default.GetBytes(Buffer)
    Me.Write(aByte)
    End Sub
    '接收字节
    Public Overloads Function Read(ByRef Bytes2Read As Integer, ByRef inputbyte() As Byte) As Boolean
    Dim ireadchars, itoread, irc, lperrors As Integer
    Dim mabtrxbuf As Byte() '接收缓冲区
    '设置读取数据的长度
    If mhRS = -1 Then
    Return False
    Else
    '读取字节
    Try
    Dim cs As COMSTAT
    rs232api.ClearCommError(mhRS, lperrors, cs)
    '取得缓冲区的字节数
    If mReadLen > 0 Then '是否高置了每次 READ命令所读取的字节数
    If mReadLen > cs.cbInQue Then
    ireadchars
    = cs.cbInQue
    Else
    ireadchars
    = mReadLen
    End If
    Else
    ireadchars
    = cs.cbInQue
    End If
    ReDim mabtrxbuf(ireadchars - 1)
    irc
    = rs232api.ReadFile(mhRS, mabtrxbuf, ireadchars, itoread, Nothing)
    If irc = 0 Then
    '读取错误
    Return False
    Else
    Bytes2Read
    = ireadchars
    inputbyte
    = mabtrxbuf
    Return True
    End If
    Catch ex As Exception
    Return False
    Finally
    miReceived
    = 0
    End Try
    End If

    End Function
    '将字符串数据读进来
    Public Overloads Function Read(ByRef char2read As Integer, ByRef inputstring As String) As Boolean
    Dim bytes As Byte()
    If Read(char2read, bytes) Then
    inputstring = System.Text.Encoding.Default.GetString(bytes)
    Return True
    Else
    Return False
    End If
    End Function
    '设置DTS状态
    Private Function SetDTR(ByVal fstate As Boolean) As Boolean
    If fstate Then '设置高电位
    If Not rs232api.EscapeCommFunction(mhRS, eLines.SetDtr) Then
    Return False
    End If
    Else
    '设置低电位
    If Not rs232api.EscapeCommFunction(mhRS, eLines.ClearDtr) Then
    Return False
    Else
    Return True
    End If
    End If
    Return True
    End Function
    '设置RTS状态
    Private Function SetRTS(ByVal fstate As Boolean) As Boolean
    If fstate Then '设置高电位
    If Not rs232api.EscapeCommFunction(mhRS, eLines.SetRts) Then
    Return False
    End If
    Else
    '设置低电位
    If Not rs232api.EscapeCommFunction(mhRS, eLines.ClearRts) Then
    Return False
    Else
    Return True
    End If
    End If
    Return True
    End Function
    '取得数字输入线路的状态
    Private Function GetModemStatus() As Integer
    Dim lineresult As Integer
    If Not rs232api.GetCommModemStatus(mhRS, lineresult) Then
    MsgBox(" 取得信号错误!", MsgBoxStyle.Critical Or MsgBoxStyle.OkOnly, "系统信息")
    Return (-1)
    End If
    Return lineresult
    End Function
    '''定时器TICK事件
    ''' 检查接收的状况。线路状况,错误状况
    ''' 依状况触发预定事件
    Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
    Dim linestatus, lperrors As Integer
    Dim cs As COMSTAT
    '检查通信端口是否打开
    If Not mfPortOpen Then
    Timer1.Enabled
    = False
    Exit Sub
    End If
    '检查数据是否达到
    RS232API.ClearCommError(mhRS, lperrors, cs) '取得缓冲区内的字节数
    If mRThreshold > 0 Then
    If cs.cbInQue >= mReadLen Then Me.miReceived = cs.cbInQue 'RaiseEvent OnDataReceived()
    End If
    RaiseEvent OnDataReceived()
    '检查是否产生错误
    meCommError = lperrors
    If lperrors > 0 Then RaiseEvent OnCommError(lperrors)
    '检查线路状态,决定是否触发事件
    linestatus = GetModemStatus() '取得线路状态
    If linestatus And eModemStatusBits.CarrierDetect Then '比对CD状态
    If Not mCDHolding Then
    meCommEvent
    = eEventMasks.ReceiveLine
    RaiseEvent OnEvent(eEventMasks.ReceiveLine)

    End If
    mCDHolding
    = True
    Else
    If mCDHolding Then
    meCommEvent
    = eEventMasks.ReceiveLine
    RaiseEvent OnEvent(meCommEvent)
    End If
    mCDHolding
    = False
    End If
    If linestatus And eModemStatusBits.ClearToSendOn Then
    '对比 CTS状态
    If Not mCTSHolding Then
    meCommEvent
    = eEventMasks.ClearToSend
    RaiseEvent OnEvent(eEventMasks.ClearToSend)

    End If
    mCTSHolding
    = True
    Else
    If mCTSHolding Then
    meCommEvent
    = eEventMasks.ClearToSend
    RaiseEvent OnEvent(eEventMasks.ClearToSend)
    End If
    mCTSHolding
    = False
    End If
    If linestatus And eModemStatusBits.DataSetReadOn Then
    '对比DRS状态
    If Not mDSRHolding Then
    meCommEvent
    = eEventMasks.DataSetReady
    RaiseEvent OnEvent(eEventMasks.DataSetReady)

    End If
    mDSRHolding
    = True
    Else
    If mDSRHolding Then
    meCommEvent
    = eEventMasks.DataSetReady
    End If
    mDSRHolding
    = False
    End If
    If linestatus And eModemStatusBits.RingIndicatorOn Then '比对Ri状态
    If Not mRIHolding Then
    meCommEvent
    = eEventMasks.Ring
    RaiseEvent OnEvent(eEventMasks.Ring)
    End If
    mRIHolding
    = True
    Else
    If mRIHolding Then
    meCommEvent
    = eEventMasks.Ring
    RaiseEvent OnEvent(eEventMasks.Ring)
    End If
    mRIHolding
    = False
    End If
    '判断定时器状态
    If Not mfTimer Then
    Timer1.Stop()
    '检查标志,终止定时器的操作
    End If
    Application.DoEvents()

    End Sub
    End Class

    RS232API.vb

    Imports System.Runtime.InteropServices
    Public Class RS232API
    Dim rs232 As cRS232
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function SetCommState(ByVal hCommDev As IntPtr, ByRef lpDCB As RS232.cRS232.DCB) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function GetCommState(ByVal hCommDev As IntPtr, ByRef lpDCB As RS232.cRS232.DCB) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True, CharSet:=CharSet.Auto)> Public Shared Function BuildCommDCB(ByVal lpDef As String, ByRef lpDCB As RS232.cRS232.DCB) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function SetupComm(ByVal hFile As IntPtr, ByVal dwInQueue As Int32, ByVal dwOutQueue As Int32) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function SetCommTimeouts(ByVal hFile As IntPtr, ByRef lpCommTimeouts As RS232.cRS232.COMMTIMEOUTS) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function GetCommTimeouts(ByVal hFile As IntPtr, ByRef lpCommTimeouts As RS232.cRS232.COMMTIMEOUTS) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function ClearCommError(ByVal hFile As IntPtr, ByRef lpErrors As Int32, ByRef lpComStat As RS232.cRS232.COMSTAT) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function PurgeComm(ByVal hFile As IntPtr, ByVal dwFlags As Int32) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function EscapeCommFunction(ByVal hFile As IntPtr, ByVal ifunc As Int32) As Boolean
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function WaitCommEvent(ByVal hFile As IntPtr, ByRef Mask As RS232.cRS232.eEventMasks, ByRef lpOverlap As RS232.cRS232.OVERLAPPED) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function WriteFile(ByVal hFile As IntPtr, ByVal Buffer As Byte(), ByVal nNumberOfBytesToWrite As Integer, ByRef lpNumberOfBytesWritten As Integer, ByRef lpOverlapped As RS232.cRS232.OVERLAPPED) As Integer
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function ReadFile(ByVal hFile As IntPtr, <Out()> ByVal Buffer As Byte(), ByVal nNumberOfBytesToRead As Integer, ByRef lpNumberOfBytesRead As Integer, ByRef lpOverlapped As RS232.cRS232.OVERLAPPED) As Integer
    End Function
    <DllImport("kernel32.dll", SetlastError:=True, CharSet:=CharSet.Auto)> Public Shared Function CreateFile(ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer, ByVal lpSecurityAttributes As Integer, ByVal dwCreationDisposition As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As Integer) As IntPtr
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function CloseHandle(ByVal hObject As IntPtr) As Boolean
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function GetCommModemStatus(ByVal hFile As IntPtr, ByRef lpModemStatus As Int32) As Boolean
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function SetEvent(ByVal hEvent As IntPtr) As Boolean
    End Function
    <DllImport("kernel32.dll", SetlastError:=True, CharSet:=CharSet.Auto)> Public Shared Function CreateEvent(ByVal lpEventAttributes As IntPtr, ByVal bManualReset As Int32, ByVal bInitialState As Int32, ByVal lpName As String) As IntPtr
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function WaitForSingleObject(ByVal hHandle As IntPtr, ByVal dwMilliseconds As Int32) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function GetOverlappedResult(ByVal hFile As IntPtr, ByRef lpOverlapped As RS232.cRS232.OVERLAPPED, ByRef lpNumberOfBytesTransferred As Int32, ByVal bWait As Int32) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function SetCommMask(ByVal hFile As IntPtr, ByVal lpEvtMask As Int32) As Int32
    End Function
    <DllImport("kernel32.dll", SetlastError:=True, CharSet:=CharSet.Auto)> Public Shared Function GetDefaultCommConfig(ByVal lpszName As String, ByRef lpCC As RS232.cRS232.COMMCONFIG, ByRef lpdwSize As Integer) As Boolean
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function SetCommBreak(ByVal hFile As IntPtr) As Boolean
    End Function
    <DllImport("kernel32.dll", SetlastError:=True)> Public Shared Function ClearCommBreak(ByVal hFile As IntPtr) As Boolean
    End Function
    End Class
  • 相关阅读:
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-print
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-bookmark
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-book
    ListView与RadioButton组合——自定义单选列表
    谷歌邮箱上不了的情况下怎么登录谷歌邮箱
    Valid page threshold based garbage collection for solid state drive
    Win10 owerShell Get命令大全
    程序员每天应该思考的5个问题,你有思考过吗?
    程序员每天应该思考的5个问题,你有思考过吗?
    程序员每天应该思考的5个问题,你有思考过吗?
  • 原文地址:https://www.cnblogs.com/hcbin/p/1709045.html
Copyright © 2020-2023  润新知