Imports System.Runtime.InteropServices

Public Class modbusForm
    Dim modbusInt, ComPort, Readtrue As Integer
    '串口控制函数
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtuComOpen", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtuComOpen(ByVal nport As Integer, _
                               ByVal BaudRate As Integer, _
                               ByVal DataBits As Integer, _
                               ByVal Parity As String, _
                               ByVal StopBits As Integer, _
                               ByVal User As String) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtuComClose", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtuComClose(ByVal nport As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtuComTrue", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtuComTrue(ByVal nport As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtuComWork", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtuComWork(ByVal nport As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtuSetDelay", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtuSetDelay(ByVal value As Integer) As Integer
    End Function
    '标准modbus函数
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn01", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn01(ByVal nport As Integer, _
                               ByVal node As Integer, _
                               ByVal address As Integer, _
                               ByVal Count As Integer, _
                               ByRef RxdBuffer As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn02", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn02(ByVal nport As Integer, _
                              ByVal node As Integer, _
                              ByVal address As Integer, _
                              ByVal Count As Integer, _
                              ByRef RxdBuffer As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn03", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn03(ByVal nport As Integer, _
                              ByVal node As Integer, _
                              ByVal address As Integer, _
                              ByVal Count As Integer, _
                              ByRef RxdBuffer As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn04", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn04(ByVal nport As Integer, _
                              ByVal node As Integer, _
                              ByVal address As Integer, _
                              ByVal Count As Integer, _
                              ByRef RxdBuffer As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn05", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn05(ByVal nport As Integer, _
                             ByVal node As Integer, _
                             ByVal address As Integer, _
                             ByVal value As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn06", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn06(ByVal nport As Integer, _
                             ByVal node As Integer, _
                             ByVal address As Integer, _
                             ByVal value As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn15", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn15(ByVal nport As Integer, _
                              ByVal node As Integer, _
                              ByVal address As Integer, _
                              ByVal Count As Integer, _
                              ByRef TxdBuffer As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn16", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn16(ByVal nport As Integer, _
                             ByVal node As Integer, _
                             ByVal address As Integer, _
                             ByVal Count As Integer, _
                             ByRef TxdBuffer As Integer) As Integer
    End Function
    '延伸modbus函数
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn03DInt", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn03DInt(ByVal nport As Integer, _
                             ByVal node As Integer, _
                             ByVal regular As Integer, _
                             ByVal address As Integer, _
                             ByVal Count As Integer, _
                             ByRef RxdBuffer As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn03Float", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn03Float(ByVal nport As Integer, _
                            ByVal node As Integer, _
                            ByVal regular As Integer, _
                            ByVal address As Integer, _
                            ByVal Count As Integer, _
                            ByRef RxdBuffer As Single) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn04DInt", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn04DInt(ByVal nport As Integer, _
                             ByVal node As Integer, _
                             ByVal regular As Integer, _
                             ByVal address As Integer, _
                             ByVal Count As Integer, _
                             ByRef RxdBuffer As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn04Float", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn04Float(ByVal nport As Integer, _
                            ByVal node As Integer, _
                            ByVal regular As Integer, _
                            ByVal address As Integer, _
                            ByVal Count As Integer, _
                            ByRef RxdBuffer As Single) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn16DInt", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn16DInt(ByVal nport As Integer, _
                             ByVal node As Integer, _
                             ByVal regular As Integer, _
                             ByVal address As Integer, _
                             ByVal Count As Integer, _
                             ByRef TxdBuffer As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtufcn16Float", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtufcn16Float(ByVal nport As Integer, _
                            ByVal node As Integer, _
                            ByVal regular As Integer, _
                            ByVal address As Integer, _
                            ByVal Count As Integer, _
                            ByRef TxdBuffer As Single) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtuWordBitWrite", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtuWordBitWrite(ByVal nport As Integer, _
                             ByVal node As Integer, _
                             ByVal address As Integer, _
                             ByVal Bit As Integer, _
                             ByVal value As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="mbrtuWordBitSetReset", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function mbrtuWordBitSetReset(ByVal nport As Integer, _
                             ByVal node As Integer, _
                             ByVal address As Integer, _
                             ByVal Bit As Integer) As Integer
    End Function
    '混合读写时等情况所需拓展函数
    <DllImport("modbus_rtu.dll", EntryPoint:="DecBitBin", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function DecBitBin(ByVal value As Integer, _
                               ByVal Bitaddress As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="Int32ToInt_16h", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function Int32ToInt_16h(ByVal value As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="Int32ToInt_16l", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function Int32ToInt_16l(ByVal value As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="Int16ToInt32", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function Int16ToInt32(ByVal valueH As Integer, _
                               ByVal valueL As Integer) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="Float32ToInt_16h", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function Float32ToInt_16h(ByVal value As Single) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="Float32ToInt_16l", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function Float32ToInt_16l(ByVal value As Single) As Integer
    End Function
    <DllImport("modbus_rtu.dll", EntryPoint:="Int16ToFloat32", CharSet:=CharSet.Ansi, SetLastError:=True)> _
    Private Shared Function Int16ToFloat32(ByVal valueH As Integer, _
                               ByVal valueL As Integer) As Single
    End Function
    Private Sub Formmodbus_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load
        Combnode.SelectedIndex = 0
        CombCOM.SelectedIndex = 0
        CombBaudRate.SelectedIndex = 1
        ComPort = 1
        modbusInt = -1
        Readtrue = -1
    End Sub

    Private Sub CommandOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CommandOpen.Click
        Dim k, BaudRate As Integer
        Dim Userstr, Paritstr As String

        ComPort = CombCOM.SelectedIndex + 1
        Userstr = Usertxt.Text
        Paritstr = "e" '这里是偶校验      

        If mbrtuComTrue(ComPort) = -1 Then
            '设定DLL函数的超时参数8~80
            Call mbrtuSetDelay(32)
            '将DLL用户名及端口号传入打开串口，串口设定9600,8,e,1
            BaudRate = Val(CombBaudRate.Text)
            k = mbrtuComOpen(ComPort, BaudRate, 8, Paritstr, 1, Userstr)
            If k = 1 Then         'k=-1 表示串口打开失败，可能串口不存在或已被占用
                Me.Text = "施耐德modbus rtu协议通信demo----DLL已注册"
            ElseIf k = 0 Then
                Me.Text = "施耐德modbus rtu协议通信demo----DLL未注册"
            End If
            If mbrtuComTrue(ComPort) = 1 Then
                CombCOM.Enabled = False
                Combnode.Enabled = False
            End If
            TimerPlc.Enabled = True
        End If
    End Sub

    Private Sub CommandClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CommandClose.Click
        If mbrtuComTrue(ComPort) = 1 Then
            Readtrue = -1
            modbusInt = -1
            BtnReadW.Text = "读PLC值"

            If mbrtuComClose(ComPort) = -1 Then
                Exit Sub '关闭串口=-1表示失败  
            End If
            CombCOM.Enabled = True
            Me.Text = "施耐德modbus rtu协议通信demo"
        End If
    End Sub

    Private Sub modbusForm_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        mbrtuComClose(ComPort)
    End Sub

    Private Sub BtnReadW_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnReadW.Click
        If Readtrue = 1 Then
            Readtrue = -1
            BtnReadW.Text = "读PLC值"
        ElseIf mbrtuComTrue(ComPort) = 1 Then
            BtnReadW.Text = "停止读值"
            Readtrue = 1
        End If
    End Sub

    Private Sub BtnWriteW_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnWriteW.Click
        If (mbrtuComTrue(ComPort) = 1) And (modbusInt < 0) Then
            modbusInt = 1 '选择向设备偶发读写命令
        End If
    End Sub

    Private Sub BtnWriteM_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnWriteM.Click
        If (mbrtuComTrue(ComPort) = 1) And (modbusInt < 0) Then
            modbusInt = 2 '选择向设备偶发读写命令
        End If
    End Sub

    Private Sub BtnReadM_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnReadM.Click
        If (mbrtuComTrue(ComPort) = 1) And (modbusInt < 0) Then
            modbusInt = 3 '选择向设备偶发读写命令
        End If
    End Sub

    Private Sub Btn_Set_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn_Set.Click
        If (mbrtuComTrue(ComPort) = 1) And (modbusInt < 0) Then
            modbusInt = 4 '选择向设备偶发读写命令
        End If
    End Sub

    Private Sub Btn_ReSet_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn_ReSet.Click
        If (mbrtuComTrue(ComPort) = 1) And (modbusInt < 0) Then
            modbusInt = 5 '选择向设备偶发读写命令
        End If
    End Sub

    Private Sub TimerPlc_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerPlc.Tick
        Dim addrI, nodeI, ReadInt, tempDInt As Integer
        Dim buffer(1024) As Integer
        Dim tempInt As Short
        Dim strreal As String
        Dim tempFloat As Single

        TimerPlc.Enabled = False
        nodeI = Val(Combnode.Text)

        If modbusInt > 0 Then    '选择零时的通信命令
            Select Case modbusInt
                Case 1 '向PLC写数据
                    '将混合的数据转换成16位整数,数组
                    tempInt = Val(SendText0.Text) '16位整数
                    buffer(0) = tempInt
                    tempInt = Val(SendText1.Text) '16位整数
                    buffer(1) = tempInt
                    tempDInt = Val(SendText2.Text) '32位整数
                    If OptionWord01.Checked Then    '不同品牌的下位机在双字和浮点的数据存储上有所不同，有高位在前和低位在前之分
                        buffer(2) = Int32ToInt_16l(tempDInt)
                        buffer(3) = Int32ToInt_16h(tempDInt)
                    Else
                        buffer(2) = Int32ToInt_16h(tempDInt)
                        buffer(3) = Int32ToInt_16l(tempDInt)
                    End If
                    tempInt = Val(SendText3.Text) '16位整数
                    buffer(4) = tempInt
                    tempInt = Val(SendText4.Text) '16位整数
                    buffer(5) = tempInt
                    tempFloat = Val(SendText5.Text) '32位浮点数
                    If OptionWord01.Checked Then              '不同品牌的下位机在双字和浮点的数据存储上有所不同，有高位在前和低位在前之分
                        buffer(6) = Float32ToInt_16l(tempFloat)
                        buffer(7) = Float32ToInt_16h(tempFloat)
                    Else
                        buffer(6) = Float32ToInt_16h(tempFloat)
                        buffer(7) = Float32ToInt_16l(tempFloat)
                    End If
                    '将混合的数据转换成16位整数,数组
                    addrI = 0                               'modbus地址从40001开始，偏移地址0-7,8个存储器值
                    '将混合的数据转换成16位整数,数组
                    Call mbrtufcn16(ComPort, nodeI, addrI, 8, buffer(0))  '按16位整数写入PLC
                Case 2 '逻辑线圈写值
                    addrI = Val(EditbitAddr.Text) '逻辑线圈modbus地址范围00001~0XXXX 函数调用按偏移地址从0开始
                    tempInt = Val(EditBitvalue.Text) '只能是0或者1
                    buffer(0) = tempInt
                    Call mbrtufcn15(ComPort, nodeI, addrI, 1, buffer(0)) '对逻辑线圈进行多位模式写
                Case 3 '读逻辑线圈
                    addrI = Val(EditbitAddr.Text)  '逻辑线圈modbus地址范围00001~0XXXX 函数调用按偏移地址从0开始
                    If mbrtufcn01(ComPort, nodeI, addrI, 1, buffer(0)) = 1 Then EditBitvalue.Text = Trim(Str(buffer(0)))
                Case 4 '置位
                    addrI = Val(EditbitAddr.Text) '逻辑线圈modbus地址范围00001~0XXXX 函数调用按偏移地址从0开始
                    Call mbrtufcn05(ComPort, nodeI, addrI, 1)  '逻辑线圈置1
                Case 5 '复位
                    addrI = Val(EditbitAddr.Text) '逻辑线圈modbus地址范围00001~0XXXX 函数调用按偏移地址从0开始
                    Call mbrtufcn05(ComPort, nodeI, addrI, 0)  '逻辑线圈置0
            End Select
            modbusInt = -1
        ElseIf Readtrue = 1 Then '循环读取的通信命令
            addrI = 0           'modbus地址从40001开始，偏移地址0-7,8个存储器值
            ReadInt = mbrtufcn03(ComPort, nodeI, addrI, 8, buffer(0)) '读取字元件值
            If ReadInt = 8 Then
                ReadText0.Text = Trim(Str(buffer(0)))
                ReadText1.Text = Trim(Str(buffer(1)))
                If OptionWord01.Checked Then              '不同品牌的下位机在双字和浮点的数据存储上有所不同，有高位在前和低位在前之分
                    ReadText2.Text = Trim(Str(Int16ToInt32(buffer(3), buffer(2))))
                Else
                    ReadText2.Text = Trim(Str(Int16ToInt32(buffer(2), buffer(3))))
                End If
                ReadText3.Text = Trim(Str(buffer(4)))
                ReadText4.Text = Trim(Str(buffer(5)))
                If OptionWord01.Checked Then              '不同品牌的下位机在双字和浮点的数据存储上有所不同，有高位在前和低位在前之分
                    strreal = Trim(Str(Int16ToFloat32(buffer(7), buffer(6))))
                Else
                    strreal = Trim(Str(Int16ToFloat32(buffer(6), buffer(7))))
                End If
                ReadText5.Text = Trim(Str(strreal))
            End If
        End If
        TimerPlc.Enabled = True
    End Sub
End Class