Skip to content

Modbus ����Ӧ��

���ĵ����� Modbus ���ĸ߼����ܡ����ʵ���ͳ���Ӧ�ó�����


? Ŀ¼


�߼�����

1. ����վ��һģʽ

ijЩӦ�ó�����Ҫͬһ�豸����Ϊ��վ����Ϊ��վ:

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster
Private WithEvents mbSlave As cModbusSlave

Private Sub Form_Load()
    Set mbMaster = New cModbusMaster
    Set mbSlave = New cModbusSlave
    
    ' ��ʼ����վ - ����λ����������
    mbMaster.ProtocolType = MB_MASTER_PROTOCOL_TCP
    mbMaster.TCPHost = "192.168.1.100"
    mbMaster.TCPPort = 502
    mbMaster.SlaveID = 1
    
    ' ��ʼ����վ - ����λ���ṩ����
    mbSlave.ProtocolType = MB_SLAVE_PROTOCOL_TCP
    mbSlave.SlaveID = 2
    mbSlave.BindAddress = "0.0.0.0"  ' �������нӿ�
    mbSlave.Start 1502
End Sub

' ����վ�������ݺ�,���´�վ�ṩ����λ��
Private Sub tmrSync_Timer()
    On Error Resume Next
    
    ' ����λ����ȡ
    Dim iRegs() As Integer
    iRegs = mbMaster.ReadHoldingRegisters(0, 10)
    
    ' д�뱾�ش�վ,����λ����ȡ
    If UBound(iRegs) >= 0 Then
        Dim i As Long
        For i = 0 To UBound(iRegs)
            mbSlave.SetHoldingRegister i, iRegs(i)
        Next i
    End If
End Sub

2. �������

ʵ�ִ����Ե��������:

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster
Private Const MAX_RETRIES As Long = 3
Private Const RETRY_DELAY_MS As Long = 1000

Private Function ReadWithRetry(StartAddr As Long, Quantity As Long) As Integer()
    Dim iRetry As Long
    Dim bSuccess As Boolean
    Dim iRegs() As Integer
    
    For iRetry = 1 To MAX_RETRIES
        On Error Resume Next
        
        If mbMaster.State = MB_MASTER_STATE_DISCONNECTED Then
            mbMaster.Connect
        End If
        
        iRegs = mbMaster.ReadHoldingRegisters(StartAddr, Quantity)
        
        If UBound(iRegs) >= 0 Then
            bSuccess = True
            Exit For
        End If
        
        ' ʧ�ܺ�ȴ�
        If iRetry < MAX_RETRIES Then
            Sleep RETRY_DELAY_MS
        End If
    Next iRetry
    
    If bSuccess Then
        ReadWithRetry = iRegs
    Else
        ' �������Զ�ʧ��
        RaiseError "ReadWithRetry failed after " & MAX_RETRIES & " attempts"
    End If
End Function

3. �첽����ģʽ

ʹ�� Timer ʵ�ַ��������첽����:

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster
Private WithEvents tmrAsync As Timer
Private m_lPendingAddr As Long
Private m_lPendingCount As Long
Private m_bAsyncBusy As Boolean

Private Sub Form_Load()
    Set mbMaster = New cModbusMaster
    Set tmrAsync = New Timer
    
    tmrAsync.Interval = 100  ' 100ms �����
End Sub

' �����첽��ȡ����
Public Sub AsyncReadHoldingRegisters(StartAddr As Long, Quantity As Long)
    If m_bAsyncBusy Then
        Debug.Print "Async operation in progress"
        Exit Sub
    End If
    
    m_bAsyncBusy = True
    m_lPendingAddr = StartAddr
    m_lPendingCount = Quantity
    
    tmrAsync.Enabled = True
End Sub

' Timer �ص�ִ�ж�ȡ
Private Sub tmrAsync_Timer()
    On Error Resume Next
    
    tmrAsync.Enabled = False
    
    Dim iRegs() As Integer
    iRegs = mbMaster.ReadHoldingRegisters(m_lPendingAddr, m_lPendingCount)
    
    If UBound(iRegs) >= 0 Then
        ' ��ȡ�ɹ�,�����ص�
        OnAsyncReadComplete m_lPendingAddr, m_lPendingCount, iRegs
    Else
        ' ��ȡʧ��
        OnAsyncError "Read failed"
    End If
    
    m_bAsyncBusy = False
End Sub

' ��ȡ��ɻص�
Private Sub OnAsyncReadComplete(StartAddr As Long, Quantity As Long, ByRef Values() As Integer)
    ' ��������
    ProcessData Values
    
    RaiseEvent AsyncReadComplete(StartAddr, Quantity, Values)
End Sub

' ����ص�
Private Sub OnAsyncError(Description As String)
    Debug.Print "Async error: " & Description
    RaiseEvent AsyncError(Description)
End Sub

������

1. ������ȡ�Ż�

����ʹ�õ���������ȡ,����ͨ�Ŵ���:

vb
' ������� - ��ζ�ȡ
Private Sub BadReadApproach()
    Dim i As Long
    Dim iValue As Integer
    
    For i = 0 To 99
        iValue = mbMaster.ReadHoldingRegisters(i, 1)(0)
        ' ��������
    Next i
End Sub

' �õ����� - ������ȡ
Private Sub GoodReadApproach()
    Dim iRegs() As Integer
    Dim i As Long
    
    ' һ�ζ�ȡ100���Ĵ���
    iRegs = mbMaster.ReadHoldingRegisters(0, 100)
    
    For i = 0 To UBound(iRegs)
        ' ��������
    Next i
End Sub

2. ��ȡƵ�ʿ���

�������Ƶ���Ķ�ȡ����:

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster
Private WithEvents tmrPoll As Timer
Private m_dLastReadTime As Double
Private Const MIN_READ_INTERVAL_SEC As Double = 0.5  ' �����0.5��

Private Sub tmrPoll_Timer()
    Dim dNow As Double
    dNow = Timer
    
    ' ����Ƿ񵽴���С���
    If dNow - m_dLastReadTime < MIN_READ_INTERVAL_SEC Then
        Exit Sub
    End If
    
    ' ִ�ж�ȡ
    Dim iRegs() As Integer
    iRegs = mbMaster.ReadHoldingRegisters(0, 10)
    
    m_dLastReadTime = dNow
End Sub

3. ����Ԥ����

����ʱԤ���س�������:

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster
Private m_iRegCache() As Integer
Private Const CACHE_SIZE As Long = 100

Private Sub mbMaster_OnConnect()
    ' ���ӳɹ����������ػ���
    LoadCache
End Sub

Private Sub LoadCache()
    On Error Resume Next
    
    ReDim m_iRegCache(CACHE_SIZE - 1) As Integer
    
    Dim iRegs() As Integer
    iRegs = mbMaster.ReadHoldingRegisters(0, CACHE_SIZE)
    
    If UBound(iRegs) >= 0 Then
        Dim i As Long
        For i = 0 To UBound(iRegs)
            If i < CACHE_SIZE Then
                m_iRegCache(i) = iRegs(i)
            End If
        Next i
        
        Debug.Print "Cache loaded: " & (UBound(iRegs) + 1) & " registers"
    End If
End Sub

' �ӻ�����ٶ�ȡ
Public Function GetCachedRegister(Addr As Long) As Integer
    If Addr >= 0 And Addr < CACHE_SIZE Then
        GetCachedRegister = m_iRegCache(Addr)
    Else
        GetCachedRegister = -1  ' �������
    End If
End Function

' ���ڸ��»���
Private Sub tmrCacheUpdate_Timer()
    On Error Resume Next
    
    Dim iRegs() As Integer
    iRegs = mbMaster.ReadHoldingRegisters(0, CACHE_SIZE)
    
    If UBound(iRegs) >= 0 Then
        Dim i As Long
        For i = 0 To UBound(iRegs)
            If i < CACHE_SIZE Then
                m_iRegCache(i) = iRegs(i)
            End If
        Next i
    End If
End Sub

4. ���ӳع���

���ڶ��վ����,ʵ�����ӳ�:

vb
Option Explicit

Private Type ModbusDevice
    ID As Long
    Host As String
    Port As Long
    SlaveID As Byte
    LastUsed As Double
    Connected As Boolean
End Type

Private m_Devices() As ModbusDevice
Private m_MaxDevices As Long
Private m_ConnectionTimeout As Double  ' ��

Private Sub InitializeConnectionPool(MaxDevices As Long, TimeoutSeconds As Double)
    m_MaxDevices = MaxDevices
    m_ConnectionTimeout = TimeoutSeconds
    
    ReDim m_Devices(MaxDevices - 1) As ModbusDevice
    
    Dim i As Long
    For i = 0 To MaxDevices - 1
        m_Devices(i).Connected = False
        m_Devices(i).LastUsed = Timer - m_ConnectionTimeout - 1
    Next i
End Sub

' ��ȡ�豸����
Public Function GetDevice(DeviceID As Long) As cModbusMaster
    Dim mbDev As cModbusMaster
    Dim i As Long
    
    ' �����豸
    For i = 0 To m_MaxDevices - 1
        If m_Devices(i).ID = DeviceID Then
            ' ����ʹ��ʱ��
            m_Devices(i).LastUsed = Timer
            
            Set mbDev = New cModbusMaster
            mbDev.ProtocolType = MB_MASTER_PROTOCOL_TCP
            mbDev.TCPHost = m_Devices(i).Host
            mbDev.TCPPort = m_Devices(i).Port
            mbDev.SlaveID = m_Devices(i).SlaveID
            
            Set GetDevice = mbDev
            Exit Function
        End If
    Next i
    
    Set GetDevice = Nothing
End Function

' ������������
Public Sub CleanupConnections()
    Dim i As Long
    Dim dNow As Double
    dNow = Timer
    
    For i = 0 To m_MaxDevices - 1
        If m_Devices(i).Connected Then
            ' ������ʱʱ��
            If dNow - m_Devices(i).LastUsed > m_ConnectionTimeout Then
                ' ���Ϊ�Ͽ�
                m_Devices(i).Connected = False
                Debug.Print "Device " & m_Devices(i).ID & " connection timed out"
            End If
        End If
    Next i
End Sub

������

1. �ۺϴ�����

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster

' ��ȡ����������
Public Function SafeReadRegisters(StartAddr As Long, Quantity As Long) As Integer()
    On Error GoTo ErrorHandler
    
    ' �������״̬
    If mbMaster.State <> MB_MASTER_STATE_CONNECTED Then
        Err.Raise vbObjectError + 1, "SafeReadRegisters", "Not connected"
    End If
    
    ' ������
    If StartAddr < 0 Then
        Err.Raise vbObjectError + 2, "SafeReadRegisters", "Invalid start address"
    End If
    
    If Quantity < 1 Or Quantity > mbMaster.Defaults.MAX_REGISTERS Then
        Err.Raise vbObjectError + 3, "SafeReadRegisters", "Invalid quantity"
    End If
    
    ' ִ�ж�ȡ
    Dim iRegs() As Integer
    iRegs = mbMaster.ReadHoldingRegisters(StartAddr, Quantity)
    
    SafeReadRegisters = iRegs
    Exit Function
    
ErrorHandler:
    Dim sError As String
    sError = "Error " & Err.Number & ": " & Err.Description
    
    Debug.Print sError
    LogError sError
    
    ' ���ؿ�����
    SafeReadRegisters = Array()
End Function

' ������־
Private Sub LogError(sMessage As String)
    Dim iFile As Integer
    iFile = FreeFile
    
    Open App.Path & "\modbus_error.log" For Append As #iFile
    Print #iFile, Format$(Now, "yyyy-mm-dd hh:mm:ss") & " - " & sMessage
    Close #iFile
End Sub

2. �쳣�봦��

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster

Private Sub mbMaster_OnError(ByVal Description As String)
    Select Case True
        Case InStr(Description, "Illegal Function") > 0
            HandleIllegalFunction
            
        Case InStr(Description, "Illegal Data Address") > 0
            HandleIllegalDataAddress
            
        Case InStr(Description, "Illegal Data Value") > 0
            HandleIllegalDataValue
            
        Case InStr(Description, "Slave Device Failure") > 0
            HandleSlaveDeviceFailure
            
        Case InStr(Description, "Slave Device Busy") > 0
            HandleSlaveDeviceBusy
            
        Case InStr(Description, "Response timeout") > 0
            HandleTimeout
            
        Case Else
            HandleGenericError Description
    End Select
End Sub

Private Sub HandleIllegalFunction()
    Debug.Print "�����벻֧��"
    ' ������Ҫʹ�ò�ͬ�Ĺ�����
End Sub

Private Sub HandleIllegalDataAddress()
    Debug.Print "��ַ������Χ"
    ' ����ַ�Ƿ�����Ч��Χ��
End Sub

Private Sub HandleIllegalDataValue()
    Debug.Print "����ֵ�Ƿ�"
    ' ���д�������ֵ
End Sub

Private Sub HandleSlaveDeviceFailure()
    Debug.Print "��վ�豸����"
    ' ������Ҫ�������л��������豸
End Sub

Private Sub HandleSlaveDeviceBusy()
    Debug.Print "��վæ"
    ' �ȴ�������
    Sleep 1000
End Sub

Private Sub HandleTimeout()
    Debug.Print "��Ӧ��ʱ"
    ' �������򴮿�����
    ' ������Ҫ����
End Sub

Private Sub HandleGenericError(sDescription As String)
    Debug.Print "ͨ�ô���: " & sDescription
End Sub

���վ����

1. �豸���ù���

vb
Option Explicit

Private Type DeviceConfig
    DeviceID As Long
    Name As String
    ProtocolType As ModbusMasterProtocolType
    Host As String
    Port As Long
    SerialPort As String
    BaudRate As Long
    SlaveID As Byte
    PollInterval As Long  ' ��ѯ���(����)
    Enabled As Boolean
End Type

Private m_Devices() As DeviceConfig
Private m_MasterConnections() As cModbusMaster

' �����豸����
Public Sub AddDevice(DevID As Long, sName As String, Protocol As ModbusProtocolType, _
                      sHost As String, lPort As Long, sSerialPort As String, _
                      lBaudRate As Long, bSlaveID As Byte, lPollInterval As Long)
    
    Dim iCount As Long
    iCount = UBound(m_Devices) + 1
    
    ReDim Preserve m_Devices(iCount) As DeviceConfig
    ReDim Preserve m_MasterConnections(iCount) As cModbusMaster
    
    With m_Devices(iCount)
        .DeviceID = DevID
        .Name = sName
        .ProtocolType = Protocol
        .Host = sHost
        .Port = lPort
        .SerialPort = sSerialPort
        .BaudRate = lBaudRate
        .SlaveID = bSlaveID
        .PollInterval = lPollInterval
        .Enabled = True
    End With
    
    Set m_MasterConnections(iCount) = New cModbusMaster
    
    Debug.Print "Device added: " & sName & " (ID: " & DevID & ")"
End Sub

' ���������豸
Public Sub ConnectAllDevices()
    Dim i As Long
    
    For i = 0 To UBound(m_Devices)
        If m_Devices(i).Enabled Then
            ConnectDevice i
        End If
    Next i
End Sub

' ���ӵ����豸
Private Sub ConnectDevice(Index As Long)
    On Error Resume Next
    
    Dim mbDev As cModbusMaster
    Set mbDev = m_MasterConnections(Index)
    
    With m_Devices(Index)
        mbDev.ProtocolType = .ProtocolType
        mbDev.SlaveID = .SlaveID
        
        If .ProtocolType = MB_MASTER_PROTOCOL_TCP Then
            mbDev.TCPHost = .Host
            mbDev.TCPPort = .Port
            mbDev.Connect
        Else
            mbDev.SerialPort = .SerialPort
            mbDev.BaudRate = .BaudRate
            mbDev.DataBits = 8
            mbDev.Parity = "N"
            mbDev.StopBits = 1
            mbDev.Connect .SerialPort
        End If
    End With
    
    If Err.Number = 0 Then
        Debug.Print "Device " & m_Devices(Index).Name & " connected"
    Else
        Debug.Print "Device " & m_Devices(Index).Name & " connect failed: " & Err.Description
    End If
End Sub

2. ͳһ��ѯ����

vb
Option Explicit

Private WithEvents tmrPoll As Timer
Private m_CurrentDeviceIndex As Long

Private Sub StartPolling()
    Set tmrPoll = New Timer
    tmrPoll.Interval = 100  ' 100ms ��ѯ���
    m_CurrentDeviceIndex = 0
    tmrPoll.Enabled = True
End Sub

Private Sub tmrPoll_Timer()
    tmrPoll.Enabled = False
    
    ' ��ѯ��ǰ�豸
    PollDevice m_CurrentDeviceIndex
    
    ' �ƶ�����һ���豸
    m_CurrentDeviceIndex = m_CurrentDeviceIndex + 1
    If m_CurrentDeviceIndex > UBound(m_Devices) Then
        m_CurrentDeviceIndex = 0
    End If
    
    tmrPoll.Enabled = True
End Sub

Private Sub PollDevice(Index As Long)
    On Error Resume Next
    
    Dim mbDev As cModbusMaster
    Set mbDev = m_MasterConnections(Index)
    
    ' ����豸�Ƿ�����
    If Not m_Devices(Index).Enabled Then
        Exit Sub
    End If
    
    ' �������״̬
    If mbDev.State <> MB_MASTER_STATE_CONNECTED Then
        ConnectDevice Index
        Exit Sub
    End If
    
    ' ��ȡ�豸����
    Dim iRegs() As Integer
    iRegs = mbDev.ReadHoldingRegisters(0, 10)
    
    If UBound(iRegs) >= 0 Then
        ' ��������
        ProcessDeviceData m_Devices(Index).DeviceID, iRegs
        
        ' �������ͨ��ʱ��
        m_Devices(Index).LastUsed = Timer
    End If
End Sub

Private Sub ProcessDeviceData(DeviceID As Long, ByRef Values() As Integer)
    ' �����豸ID��������
    Select Case DeviceID
        Case 1
            ProcessDevice1Data Values
        Case 2
            ProcessDevice2Data Values
        ' ...
    End Select
End Sub

���ݻ������

1. �༶����

vb
Option Explicit

Private Enum CacheLevel
    CACHE_LEVEL_NONE = 0
    CACHE_LEVEL_L1 = 1      ' �ڴ滺��
    CACHE_LEVEL_L2 = 2      ' �����
    CACHE_LEVEL_L3 = 3      ' ���ݿ⻺��
End Enum

Private m_L1Cache() As Integer      ' �ڴ滺��
Private m_L1CacheValid() As Boolean ' ������Ч�Ա��
Private m_CacheLevel As CacheLevel

' ��ʼ������
Public Sub InitializeCache(Size As Long, Level As CacheLevel)
    ReDim m_L1Cache(Size - 1) As Integer
    ReDim m_L1CacheValid(Size - 1) As Boolean
    m_CacheLevel = Level
    
    Dim i As Long
    For i = 0 To Size - 1
        m_L1CacheValid(i) = False
    Next i
End Sub

' ��ȡ�Ĵ���(������)
Public Function ReadWithCache(Addr As Long) As Integer
    ' �ȼ��L1����
    If Addr >= 0 And Addr <= UBound(m_L1Cache) Then
        If m_L1CacheValid(Addr) And m_CacheLevel >= CACHE_LEVEL_L1 Then
            ReadWithCache = m_L1Cache(Addr)
            Debug.Print "Cache L1 hit: Reg[" & Addr & "] = " & m_L1Cache(Addr)
            Exit Function
        End If
    End If
    
    ' L1����δ����,���豸��ȡ
    Dim iRegs() As Integer
    iRegs = mbMaster.ReadHoldingRegisters(Addr, 1)
    
    If UBound(iRegs) >= 0 Then
        ' ����L1����
        If Addr >= 0 And Addr <= UBound(m_L1Cache) Then
            m_L1Cache(Addr) = iRegs(0)
            m_L1CacheValid(Addr) = True
        End If
        
        ReadWithCache = iRegs(0)
        Debug.Print "Cache miss: Reg[" & Addr & "] = " & iRegs(0)
    End If
End Function

' ��������
Public Sub InvalidateCache(Addr As Long)
    On Error Resume Next
    
    If Addr >= 0 And Addr <= UBound(m_L1Cache) Then
        m_L1CacheValid(Addr) = False
    End If
End Sub

' ���������
Public Sub InvalidateAllCache()
    Dim i As Long
    For i = 0 To UBound(m_L1Cache)
        m_L1CacheValid(i) = False
    Next i
    
    Debug.Print "All cache invalidated"
End Sub

2. д��ͬ������

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster
Private WithEvents mbSlave As cModbusSlave

' ��վ��ȡ��ͬ������վ
Private Sub SyncMasterToSlave()
    On Error Resume Next
    
    ' ����λ����ȡ
    Dim iMasterRegs() As Integer
    iMasterRegs = mbMaster.ReadHoldingRegisters(0, 10)
    
    If UBound(iMasterRegs) >= 0 Then
        ' �Ƚ������Ƿ�仯
        Dim bChanged As Boolean
        bChanged = CheckDataChanged(iMasterRegs)
        
        ' ����б仯,ͬ������վ
        If bChanged Then
            Dim i As Long
            For i = 0 To UBound(iMasterRegs)
                mbSlave.SetHoldingRegister i, iMasterRegs(i)
            Next i
            
            Debug.Print "Synced " & (UBound(iMasterRegs) + 1) & " registers"
        End If
    End If
End Sub

' ��������Ƿ�仯
Private Function CheckDataChanged(ByRef NewData() As Integer) As Boolean
    Static iLastData() As Integer
    Static bInitialized As Boolean
    
    If Not bInitialized Then
        ' �״γ�ʼ��
        iLastData = NewData
        bInitialized = True
        CheckDataChanged = True
        Exit Function
    End If
    
    Dim i As Long
    For i = 0 To UBound(NewData)
        If iLastData(i) <> NewData(i) Then
            iLastData(i) = NewData(i)
            CheckDataChanged = True
            Exit Function
        End If
    Next i
    
    CheckDataChanged = False
End Function

��־�����

1. ��ϸ��־��¼

vb
Option Explicit

Private Enum LogLevel
    LOG_LEVEL_DEBUG = 0
    LOG_LEVEL_INFO = 1
    LOG_LEVEL_WARNING = 2
    LOG_LEVEL_ERROR = 3
    LOG_LEVEL_CRITICAL = 4
End Enum

Private m_LogLevel As LogLevel
Private m_LogFile As String

' ��ʼ����־
Public Sub InitLog(sFilePath As String, Level As LogLevel)
    m_LogFile = sFilePath
    m_LogLevel = Level
    
    ' ������־Ŀ¼
    Dim sDir As String
    sDir = Left$(sFilePath, InStrRev(sFilePath, "\") - 1)
    
    On Error Resume Next
    MkDir sDir
    On Error GoTo 0
End Sub

' д����־
Public Sub WriteLog(Level As LogLevel, sMessage As String)
    ' ֻ��¼ָ���������ϵ���־
    If Level < m_LogLevel Then Exit Sub
    
    Dim sLevel As String
    Select Case Level
        Case LOG_LEVEL_DEBUG:    sLevel = "DEBUG"
        Case LOG_LEVEL_INFO:     sLevel = "INFO "
        Case LOG_LEVEL_WARNING:  sLevel = "WARN "
        Case LOG_LEVEL_ERROR:    sLevel = "ERROR"
        Case LOG_LEVEL_CRITICAL: sLevel = "CRIT "
    End Select
    
    Dim sLogLine As String
    sLogLine = Format$(Now, "yyyy-mm-dd hh:mm:ss") & " [" & sLevel & "] " & sMessage
    
    Debug.Print sLogLine
    
    On Error Resume Next
    Dim iFile As Integer
    iFile = FreeFile
    Open m_LogFile For Append As #iFile
    Print #iFile, sLogLine
    Close #iFile
    On Error GoTo 0
End Sub

' ��װ����־����
Public Sub LogDebug(sMessage As String)
    WriteLog LOG_LEVEL_DEBUG, sMessage
End Sub

Public Sub LogInfo(sMessage As String)
    WriteLog LOG_LEVEL_INFO, sMessage
End Sub

Public Sub LogWarning(sMessage As String)
    WriteLog LOG_LEVEL_WARNING, sMessage
End Sub

Public Sub LogError(sMessage As String)
    WriteLog LOG_LEVEL_ERROR, sMessage
End Sub

Public Sub LogCritical(sMessage As String)
    WriteLog LOG_LEVEL_CRITICAL, sMessage
End Sub

2. ���ݰ�����

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster

' ���ݰ����Կ���
Private m_bDebugPackets As Boolean

Public Sub EnablePacketDebug(bEnable As Boolean)
    m_bDebugPackets = bEnable
End Sub

' �����¼�����
Private Sub mbMaster_OnDataReceived(Data() As Byte)
    If Not m_bDebugPackets Then Exit Sub
    
    Dim sHex As String
    Dim i As Long
    
    For i = 0 To UBound(Data)
        sHex = sHex & Format$(Data(i), "00") & " "
    Next i
    
    Debug.Print "RX [" & Format$(Now, "hh:mm:ss") & "] " & sHex
    LogInfo "RX: " & sHex
End Sub

' �������ݰ�����
Private Sub DebugSendPacket(ByRef Data() As Byte)
    If Not m_bDebugPackets Then Exit Sub
    
    Dim sHex As String
    Dim i As Long
    
    For i = 0 To UBound(Data)
        sHex = sHex & Format$(Data(i), "00") & " "
    Next i
    
    Debug.Print "TX [" & Format$(Now, "hh:mm:ss") & "] " & sHex
    LogInfo "TX: " & sHex
End Sub

' ����Modbus���ݰ�
Public Sub ParseModbusPacket(ByRef Data() As Byte)
    If UBound(Data) < 2 Then Exit Sub
    
    Dim bFC As Byte
    bFC = Data(1)
    
    Debug.Print "=== Modbus Packet ==="
    Debug.Print "Slave ID: " & Data(0)
    Debug.Print "Function Code: 0x" & Hex$(bFC) & " (" & GetFunctionName(bFC) & ")"
    
    Select Case bFC
        Case &H1  ' Read Coils
            If UBound(Data) >= 3 Then
                Debug.Print "Byte Count: " & Data(2)
            End If
            
        Case &H3  ' Read Holding Registers
            If UBound(Data) >= 3 Then
                Dim iByteCount As Long
                iByteCount = Data(2)
                Debug.Print "Byte Count: " & iByteCount
                
                Dim i As Long
                For i = 0 To (iByteCount \ 2) - 1
                    Dim iReg As Integer
                    iReg = Data(3 + i * 2) * 256 + Data(4 + i * 2)
                    Debug.Print "  Reg[" & i & "] = " & iReg & " (0x" & Hex$(iReg) & ")"
                Next i
            End If
    End Select
    
    Debug.Print "====================="
End Sub

Private Function GetFunctionName(bFC As Byte) As String
    Select Case bFC
        Case &H1:  GetFunctionName = "Read Coils"
        Case &H2:  GetFunctionName = "Read Discrete Inputs"
        Case &H3:  GetFunctionName = "Read Holding Registers"
        Case &H4:  GetFunctionName = "Read Input Registers"
        Case &H5:  GetFunctionName = "Write Single Coil"
        Case &H6:  GetFunctionName = "Write Single Register"
        Case &HF:  GetFunctionName = "Write Multiple Coils"
        Case &H10: GetFunctionName = "Write Multiple Registers"
        Case Else: GetFunctionName = "Unknown"
    End Select
End Function

��ȫ����

1. ������֤

vb
Option Explicit

Private Type AuthConfig
    Enabled As Boolean
    Username As String
    Password As String
    Token As String
    TokenExpiry As Date
End Type

Private m_Auth As AuthConfig

' ��ʼ����֤
Public Sub SetAuthentication(bEnabled As Boolean, sUser As String, sPass As String)
    m_Auth.Enabled = bEnabled
    m_Auth.Username = sUser
    m_Auth.Password = sPass
    m_Auth.Token = ""
    m_Auth.TokenExpiry = #1/1/1900#
End Sub

' �����֤
Public Function CheckAuthentication() As Boolean
    If Not m_Auth.Enabled Then
        CheckAuthentication = True  ' δ������֤,ֱ��ͨ��
        Exit Function
    End If
    
    ' ���Token�Ƿ����
    If m_Auth.Token <> "" And Now < m_Auth.TokenExpiry Then
        CheckAuthentication = True
        Exit Function
    End If
    
    ' ִ����֤
    CheckAuthentication = Authenticate()
End Function

' ִ����֤
Private Function Authenticate() As Boolean
    ' ����ʵ��ʵ�ʵ���֤�߼�
    ' ������ͨ��Modbus������֤����
    ' ����ͨ������������֤
    
    ' ʾ��: ͨ��Modbus�ض��Ĵ�����֤
    Dim bSuccess As Boolean
    
    On Error Resume Next
    
    ' ������֤��Ϣ
    Dim iUserHash As Integer
    Dim iPassHash As Integer
    
    iUserHash = SimpleHash(m_Auth.Username)
    iPassHash = SimpleHash(m_Auth.Password)
    
    ' д����֤�Ĵ���
    mbMaster.WriteSingleRegister 998, iUserHash
    mbMaster.WriteSingleRegister 999, iPassHash
    
    ' ��ȡ��֤���
    Dim iResult() As Integer
    iResult = mbMaster.ReadHoldingRegisters(1000, 1)
    
    If UBound(iResult) >= 0 Then
        If iResult(0) = 1 Then
            ' ��֤�ɹ�
            m_Auth.Token = GenerateToken()
            m_Auth.TokenExpiry = DateAdd("h", 1, Now)  ' 1Сʱ����
            
            Authenticate = True
            Debug.Print "Authentication successful"
            Exit Function
        End If
    End If
    
    Authenticate = False
    Debug.Print "Authentication failed"
End Function

' �򵥹�ϣ(��ʾ��,ʵ��Ӧ��Ӧʹ�ø���ȫ�Ĺ�ϣ)
Private Function SimpleHash(sInput As String) As Integer
    Dim i As Long
    Dim lHash As Long
    
    For i = 1 To Len(sInput)
        lHash = lHash + Asc(Mid$(sInput, i, 1)) * (i Mod 7 + 1)
    Next i
    
    SimpleHash = lHash And &HFFFF
End Function

' ����Token(��ʾ��)
Private Function GenerateToken() As String
    GenerateToken = "TOKEN_" & Format$(Now, "yyyymmddhhmmss")
End Function

2. ���ݼ���(ʾ��)

vb
Option Explicit

Private m_bEncryptData As Boolean
Private m_EncryptionKey As String

' �������ݼ���
Public Sub EnableEncryption(bEnable As Boolean, sKey As String)
    m_bEncryptData = bEnable
    m_EncryptionKey = sKey
End Sub

' ��������(��XOR����,��ʾ��)
Public Function EncryptData(ByRef Data() As Byte) As Byte()
    If Not m_bEncryptData Then
        EncryptData = Data
        Exit Function
    End If
    
    Dim baEncrypted() As Byte
    ReDim baEncrypted(UBound(Data)) As Byte
    
    Dim i As Long
    Dim lKeyLen As Long
    lKeyLen = Len(m_EncryptionKey)
    
    For i = 0 To UBound(Data)
        Dim bKeyByte As Byte
        bKeyByte = Asc(Mid$(m_EncryptionKey, (i Mod lKeyLen) + 1, 1))
        baEncrypted(i) = Data(i) Xor bKeyByte
    Next i
    
    EncryptData = baEncrypted
End Function

' ��������
Public Function DecryptData(ByRef Data() As Byte) As Byte()
    ' XOR�����ǶԳƵ�,���ܺͼ�����ͬ
    DecryptData = EncryptData(Data)
End Function

ʵ��Ӧ�ó���

1. ��ҵ���ݲɼ�

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster
Private WithEvents tmrCollect As Timer

' ���ݲɼ�����
Private Type DataPoint
    RegisterAddr As Long
    Name As String
    Unit As String
    MinValue As Single
    MaxValue As Single
    AlarmHigh As Single
    AlarmLow As Single
    LastValue As Single
    LastUpdate As Date
End Type

Private m_DataPoints() As DataPoint

' ��ʼ�����ݵ�
Public Sub InitializeDataPoints()
    ReDim m_DataPoints(9) As DataPoint
    
    ' �¶�
    m_DataPoints(0).RegisterAddr = 0
    m_DataPoints(0).Name = "�¶�"
    m_DataPoints(0).Unit = "��C"
    m_DataPoints(0).MinValue = -50
    m_DataPoints(0).MaxValue = 150
    m_DataPoints(0).AlarmHigh = 120
    m_DataPoints(0).AlarmLow = -20
    
    ' ѹ��
    m_DataPoints(1).RegisterAddr = 1
    m_DataPoints(1).Name = "ѹ��"
    m_DataPoints(1).Unit = "kPa"
    m_DataPoints(1).MinValue = 0
    m_DataPoints(1).MaxValue = 10000
    m_DataPoints(1).AlarmHigh = 8000
    m_DataPoints(1).AlarmLow = 0
    
    ' ����
    m_DataPoints(2).RegisterAddr = 2
    m_DataPoints(2).Name = "����"
    m_DataPoints(2).Unit = "L/min"
    m_DataPoints(2).MinValue = 0
    m_DataPoints(2).MaxValue = 1000
    m_DataPoints(2).AlarmHigh = 900
    m_DataPoints(2).AlarmLow = 0
    
    ' ... �������ݵ�
End Sub

' ���ݲɼ�ѭ��
Private Sub tmrCollect_Timer()
    On Error Resume Next
    
    Dim i As Long
    Dim iRegs() As Integer
    
    ' ������ȡ���мĴ���
    iRegs = mbMaster.ReadHoldingRegisters(0, 10)
    
    If UBound(iRegs) >= 0 Then
        For i = 0 To UBound(m_DataPoints)
            If i <= UBound(iRegs) Then
                Dim fValue As Single
                
                ' ת��ԭʼֵ
                fValue = ConvertRawValue(iRegs(i), m_DataPoints(i))
                
                ' �������ݵ�
                m_DataPoints(i).LastValue = fValue
                m_DataPoints(i).LastUpdate = Now
                
                ' ��鱨��
                CheckAlarm i, fValue
                
                ' ��¼����
                LogDataPoint i, fValue
                
                ' ����UI��ʾ
                UpdateDataPointUI i, fValue
            End If
        Next i
    End If
End Sub

' ת��ԭʼֵ
Private Function ConvertRawValue(iRaw As Integer, pt As DataPoint) As Single
    ' ���ݵ�λת��ԭʼֵ
    Select Case pt.Unit
        Case "��C"
            ' �¶�: ֱ��ʹ��
            ConvertRawValue = CSng(iRaw)
            
        Case "kPa"
            ' ѹ��: ԭʼֵ * 10
            ConvertRawValue = CSng(iRaw) * 10
            
        Case "L/min"
            ' ����: ԭʼֵ * 0.1
            ConvertRawValue = CSng(iRaw) * 0.1
            
        Case Else
            ConvertRawValue = CSng(iRaw)
    End Select
End Function

' ��鱨��
Private Sub CheckAlarm(Index As Long, fValue As Single)
    With m_DataPoints(Index)
        If fValue >= .AlarmHigh Then
            TriggerAlarm .Name, "�߱���", fValue, .AlarmHigh
        ElseIf fValue <= .AlarmLow Then
            TriggerAlarm .Name, "�ͱ���", fValue, .AlarmLow
        End If
    End With
End Sub

' ��������
Private Sub TriggerAlarm(sPointName As String, sAlarmType As String, fValue As Single, fThreshold As Single)
    Dim sMessage As String
    sMessage = sPointName & " " & sAlarmType & ": " & Format$(fValue, "0.00") & _
              " (��ֵ: " & Format$(fThreshold, "0.00") & ")"
    
    Debug.Print "[ALARM] " & Format$(Now, "hh:mm:ss") & " - " & sMessage
    
    ' �����ʼ�֪ͨ
    ' SendAlarmEmail sMessage
    
    ' ��¼������־
    ' LogAlarm sMessage
    
    ' ���±���UI
    ' UpdateAlarmUI sPointName, sAlarmType, sMessage
End Sub

' ��¼���ݵ�
Private Sub LogDataPoint(Index As Long, fValue As Single)
    With m_DataPoints(Index)
        ' ���浽���ݿ���ļ�
        Dim sLine As String
        sLine = Format$(Now, "yyyy-mm-dd hh:mm:ss") & "," & _
                 .Name & "," & _
                 Format$(fValue, "0.00") & "," & _
                 .Unit
        
        ' WriteToFile sLine
    End With
End Sub

2. �豸����

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster

' �豸��������
Public Enum DeviceCommand
    CMD_START = 1
    CMD_STOP = 2
    CMD_RESET = 3
    CMD_EMERGENCY_STOP = 99
End Enum

' ������Ȧӳ��
Private Type CoilMapping
    Command As DeviceCommand
    Address As Long
    Value As Boolean
End Type

Private m_CoilMappings() As CoilMapping

' ��ʼ������ӳ��
Public Sub InitializeControlMappings()
    ReDim m_CoilMappings(3) As CoilMapping
    
    m_CoilMappings(0).Command = CMD_START
    m_CoilMappings(0).Address = 0
    m_CoilMappings(0).Value = True
    
    m_CoilMappings(1).Command = CMD_STOP
    m_CoilMappings(1).Address = 1
    m_CoilMappings(1).Value = True
    
    m_CoilMappings(2).Command = CMD_RESET
    m_CoilMappings(2).Address = 2
    m_CoilMappings(2).Value = True
    
    m_CoilMappings(3).Command = CMD_EMERGENCY_STOP
    m_CoilMappings(3).Address = 10
    m_CoilMappings(3).Value = True
End Sub

' ִ���豸��������
Public Function ExecuteCommand(Cmd As DeviceCommand) As Boolean
    On Error GoTo ErrorHandler
    
    Dim i As Long
    Dim bFound As Boolean
    
    ' ��������ӳ��
    For i = 0 To UBound(m_CoilMappings)
        If m_CoilMappings(i).Command = Cmd Then
            bFound = True
            Exit For
        End If
    Next i
    
    If Not bFound Then
        Debug.Print "Command not found: " & Cmd
        ExecuteCommand = False
        Exit Function
    End If
    
    ' д�������Ȧ
    Dim bSuccess As Boolean
    bSuccess = mbMaster.WriteSingleCoil(m_CoilMappings(i).Address, m_CoilMappings(i).Value)
    
    If bSuccess Then
        Debug.Print "Command executed: " & GetCommandName(Cmd)
        ExecuteCommand = True
    Else
        Debug.Print "Command failed: " & GetCommandName(Cmd)
        ExecuteCommand = False
    End If
    
    Exit Function
    
ErrorHandler:
    Debug.Print "ExecuteCommand error: " & Err.Description
    ExecuteCommand = False
End Function

' ��ȡ��������
Private Function GetCommandName(Cmd As DeviceCommand) As String
    Select Case Cmd
        Case CMD_START:          GetCommandName = "����"
        Case CMD_STOP:           GetCommandName = "ֹͣ"
        Case CMD_RESET:          GetCommandName = "��λ"
        Case CMD_EMERGENCY_STOP: GetCommandName = "����ֹͣ"
        Case Else:                GetCommandName = "δ֪"
    End Select
End Function

' ��ȫ����:��ȷ�ϵĿ���
Public Function SafeExecuteCommand(Cmd As DeviceCommand, bRequireConfirm As Boolean) As Boolean
    ' �����Ҫȷ��
    If bRequireConfirm Then
        Dim iResponse As Integer
        iResponse = MsgBox("ȷ��Ҫִ������: " & GetCommandName(Cmd) & "?", _
                           vbQuestion + vbYesNo + vbDefaultButton2, _
                           "ȷ�ϲ���")
        
        If iResponse <> vbYes Then
            Debug.Print "Command cancelled by user"
            SafeExecuteCommand = False
            Exit Function
        End If
    End If
    
    ' ִ������
    Dim bResult As Boolean
    bResult = ExecuteCommand(Cmd)
    
    ' ��¼������־
    LogCommand Cmd, bResult
    
    SafeExecuteCommand = bResult
End Function

' ��¼������־
Private Sub LogCommand(Cmd As DeviceCommand, bSuccess As Boolean)
    Dim sStatus As String
    sStatus = IIf(bSuccess, "�ɹ�", "ʧ��")
    
    Dim sLine As String
    sLine = Format$(Now, "yyyy-mm-dd hh:mm:ss") & "," & _
             GetCommandName(Cmd) & "," & _
             sStatus
    
    ' д����־�ļ�
    On Error Resume Next
    Dim iFile As Integer
    iFile = FreeFile
    Open App.Path & "\command_log.csv" For Append As #iFile
    Print #iFile, sLine
    Close #iFile
    On Error GoTo 0
End Sub

3. ��������

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster     ' �������
Private WithEvents mbSlave As cModbusSlave       ' �������

' ����ӳ������
Private Type DataMapping
    MasterAddr As Long      ' ��λ����ַ
    SlaveAddr As Long       ' ��λ����ַ
    Direction As Integer    ' 0=Master��Slave, 1=Slave��Master
    ScaleFactor As Single   ' ��������
    Offset As Single        ' ƫ����
    Enabled As Boolean
End Type

Private m_Mappings() As DataMapping

' ��ʼ������ӳ��
Public Sub InitializeDataMappings()
    ReDim m_Mappings(4) As DataMapping
    
    ' ӳ��1: ��λ���¶� -> ��λ���Ĵ���
    m_Mappings(0).MasterAddr = 0
    m_Mappings(0).SlaveAddr = 100
    m_Mappings(0).Direction = 1  ' Slave��Master
    m_Mappings(0).ScaleFactor = 1.0
    m_Mappings(0).Offset = 0
    m_Mappings(0).Enabled = True
    
    ' ӳ��2: ��λ���趨ֵ -> ��λ���Ĵ���
    m_Mappings(1).MasterAddr = 10
    m_Mappings(1).SlaveAddr = 200
    m_Mappings(1).Direction = 0  ' Master��Slave
    m_Mappings(1).ScaleFactor = 10.0
    m_Mappings(1).Offset = 0
    m_Mappings(1).Enabled = True
    
    ' ... ����ӳ��
End Sub

' ����ͬ��
Public Sub SyncGateway()
    On Error Resume Next
    
    Dim i As Long
    
    For i = 0 To UBound(m_Mappings)
        If Not m_Mappings(i).Enabled Then GoTo NextMapping
        
        Select Case m_Mappings(i).Direction
            Case 0  ' Master��Slave
                SyncMasterToSlave i
                
            Case 1  ' Slave��Master
                SyncSlaveToMaster i
        End Select
        
NextMapping:
    Next i
End Sub

' ͬ��Master��Slave
Private Sub SyncMasterToSlave(Index As Long)
    Dim iMasterReg As Integer
    iMasterReg = mbMaster.ReadHoldingRegisters(m_Mappings(Index).MasterAddr, 1)(0)
    
    Dim fScaled As Single
    fScaled = (CSng(iMasterReg) * m_Mappings(Index).ScaleFactor) + m_Mappings(Index).Offset
    
    ' �Slave
    mbSlave.SetHoldingRegister m_Mappings(Index).SlaveAddr, CInt(fScaled)
    
    Debug.Print "Sync M[" & m_Mappings(Index).MasterAddr & "] -> S[" & _
              m_Mappings(Index).SlaveAddr & "]: " & fScaled
End Sub

' ͬ��Slave��Master
Private Sub SyncSlaveToMaster(Index As Long)
    Dim iSlaveReg As Integer
    iSlaveReg = mbSlave.GetHoldingRegister(m_Mappings(Index).SlaveAddr)
    
    Dim fScaled As Single
    fScaled = (CSng(iSlaveReg) * m_Mappings(Index).ScaleFactor) + m_Mappings(Index).Offset
    
    ' �Master
    mbMaster.WriteSingleRegister m_Mappings(Index).MasterAddr, CInt(fScaled)
    
    Debug.Print "Sync S[" & m_Mappings(Index).SlaveAddr & "] -> M[" & _
              m_Mappings(Index).MasterAddr & "]: " & fScaled
End Sub

��������

Q1: ������������?

����:

  1. ������ȡ,ÿ�β��������Ĵ�����(125)
  2. ʹ�ö�ʱ����ʱ�ζ�ȡ
  3. ʵ�����ݻ������
vb
' ������ȡ��������
Public Sub ReadLargeData(StartAddr As Long, TotalCount As Long)
    Dim lOffset As Long
    Dim lRemaining As Long
    Dim lBatchSize As Long
    Dim iBatch As Long
    
    lBatchSize = mbMaster.Defaults.MAX_REGISTERS
    lOffset = 0
    lRemaining = TotalCount
    
    Do While lRemaining > 0
        Dim lThisBatch As Long
        lThisBatch = IIf(lRemaining > lBatchSize, lBatchSize, lRemaining)
        
        Dim iRegs() As Integer
        iRegs = mbMaster.ReadHoldingRegisters(StartAddr + lOffset, lThisBatch)
        
        ' ��������
        ProcessBatch iRegs, lOffset
        
        lOffset = lOffset + lThisBatch
        lRemaining = lRemaining - lThisBatch
        
        iBatch = iBatch + 1
        Debug.Print "Batch " & iBatch & " completed"
        
        ' �����������
        Sleep 10
    Loop
End Sub

Q2: ���ʵ���ȱ���?

����:

  1. ͬʱ����������̨�豸
  2. ���豸����ʱ��ȡ���豸
  3. ���豸����ʱ�Զ��л��������豸
vb
Option Explicit

Private WithEvents mbMasterPrimary As cModbusMaster
Private WithEvents mbMasterBackup As cModbusMaster
Private m_UsePrimary As Boolean

' �л��������豸
Private Sub SwitchToBackup()
    On Error Resume Next
    
    mbMasterPrimary.Disconnect
    
    Dim iRegs() As Integer
    iRegs = mbMasterBackup.ReadHoldingRegisters(0, 1)
    
    If UBound(iRegs) >= 0 Then
        m_UsePrimary = False
        Debug.Print "Switched to backup device"
        RaiseEvent DeviceSwitched("Backup")
    Else
        Debug.Print "Backup device also failed"
        RaiseEvent AllDevicesFailed
    End If
End Sub

' �����л������豸
Private Sub TrySwitchBack()
    On Error Resume Next
    
    mbMasterPrimary.Connect
    
    Dim iRegs() As Integer
    iRegs = mbMasterPrimary.ReadHoldingRegisters(0, 1)
    
    If UBound(iRegs) >= 0 Then
        m_UsePrimary = True
        Debug.Print "Switched back to primary device"
        RaiseEvent DeviceSwitched("Primary")
    End If
End Sub

' ���ܶ�ȡ(�Զ�ѡ���豸)
Public Function SmartRead(StartAddr As Long, Quantity As Long) As Integer()
    Dim iRegs() As Integer
    
    If m_UsePrimary Then
        ' ���Դ����豸��ȡ
        On Error Resume Next
        iRegs = mbMasterPrimary.ReadHoldingRegisters(StartAddr, Quantity)
        
        If UBound(iRegs) < 0 Then
            ' ���豸ʧ��,�л�������
            SwitchToBackup
            If Not m_UsePrimary Then
                iRegs = mbMasterBackup.ReadHoldingRegisters(StartAddr, Quantity)
            End If
        End If
    Else
        ' �ӱ����豸��ȡ
        iRegs = mbMasterBackup.ReadHoldingRegisters(StartAddr, Quantity)
        
        ' ���ڳ����л������豸
        Static lSwitchCount As Long
        lSwitchCount = lSwitchCount + 1
        If lSwitchCount > 10 Then
            TrySwitchBack
            lSwitchCount = 0
        End If
    End If
    
    SmartRead = iRegs
End Function

Q3: ���ʵ�ֶ�������?

vb
Option Explicit

Private WithEvents mbMaster As cModbusMaster
Private WithEvents tmrReconnect As Timer
Private m_bAutoReconnect As Boolean
Private m_lReconnectInterval As Long  ' ����

' �����Զ�����
Public Sub EnableAutoReconnect(bEnable As Boolean, lInterval As Long)
    m_bAutoReconnect = bEnable
    m_lReconnectInterval = lInterval
    
    Set tmrReconnect = New Timer
    tmrReconnect.Interval = lInterval
End Sub

Private Sub mbMaster_OnDisconnect()
    If m_bAutoReconnect Then
        Debug.Print "Disconnected, will reconnect in " & (m_lReconnectInterval \ 1000) & "s"
        tmrReconnect.Enabled = True
    End If
End Sub

Private Sub tmrReconnect_Timer()
    tmrReconnect.Enabled = False
    
    On Error Resume Next
    mbMaster.Connect
    
    If Err.Number = 0 And mbMaster.State = MB_MASTER_STATE_CONNECTED Then
        Debug.Print "Reconnected successfully"
    Else
        ' ����ʧ��,��������
        tmrReconnect.Enabled = True
    End If
End Sub

��һ��


������: 2026-01-16

������־

2026-01-16 (v1.1.0)

  • �����豸���ýṹ�壬ʹ�� ModbusMasterProtocolType
  • ���� BindAddress ����ʾ������վ��
  • ����ö�����ã����� v1.1.0 �����淶��

VB6及其LOGO版权为微软公司所有