MX Component Excel VBA で 実数値の読み書き 2020/10/13


Option Explicit

'' -----------------------------------------------------------
'' 情報元:「よく見かけるVBサンプル集」
'' 57「Single型をHex値(16進数)へ変換」、58「Double型をHex値(16進数)へ変換」
'' http://www.suvaru.com/pg/sampl/Sample100_50.html
'' Win32API
Declare Sub CopyValtoVal Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal length As Long)

Function SingleToHex(ByVal s As Single, _
             Optional ByVal direction As Boolean = False) As String
  Dim i As Integer
  Dim b(3) As Byte
  Dim st, st2 As String

  Call CopyValtoVal(b(0), s, 4)
  If direction = False Then
    For i = 0 To 3
      st = Hex(b(i))
      st2 = st2 + String(2 - Len(st), "0") + st
    Next i
  Else
    For i = 3 To 0 Step -1
      st = Hex(b(i))
      st2 = st2 + String(2 - Len(st), "0") + st
    Next i
  End If
  SingleToHex = st2
End Function

''
Function DoubleToHex(ByVal d As Double, _
              Optional ByVal direction As Boolean = False) As String
  Dim i As Integer
  Dim b(7) As Byte
  Dim st, st2 As String

  Call CopyValtoVal(b(0), d, 8) '' 7->8
  If direction = False Then
    For i = 0 To 7
      st = Hex(b(i))
      st2 = st2 + String(2 - Len(st), "0") + st
    Next i
  Else
    For i = 7 To 0 Step -1
      st = Hex(b(i))
      st2 = st2 + String(2 - Len(st), "0") + st
    Next i
  End If
  DoubleToHex = st2
End Function
'' -------------------------------------------------

'' 32 ビット実数(単精度)変換
'' Ex : HexToSingle("C2F6E666") result = -123.45
Public Function HexToSingle(sHex As String) As Single
  Dim sTemp As String
  Dim iSign, iExponent As Integer
  Dim fTemp, fFraction As Single
 
  ' 符号 1ビット
  sTemp = Mid(sHex, 1, 1)
  fTemp = Val("&H" & sTemp) And &H8
  iSign = IIf(fTemp = 8, -1, 1)
 
  ' 指数部 8ビット
  sTemp = Mid(sHex, 1, 3)
  fTemp = Val("&H" & sTemp) And &H7F8
  iExponent = fTemp / 2 ^ 3 - 127  '32ビット形式のバイアス=127
 
  ' 仮数部 23ビット
  sTemp = Mid(sHex, 3, 6)
  fTemp = Val("&H" & sTemp) And &H7FFFFF
  fFraction = 1# + (fTemp / 2 ^ 23)
 
  HexToSingle = iSign * fFraction * 2 ^ iExponent
 
End Function

'' 64 ビット実数(倍精度)変換
'' Ex : HexToDouble("C05EDD2F1A9FBE77") Result = -123.456
Public Function HexToDouble(sHex As String) As Double
  Dim sTemp As String
  Dim iSign, iExponent As Integer
  Dim fTemp, fFraction As Double
 
  ' 符号 1ビット
  sTemp = Mid(sHex, 1, 1)
  fTemp = Val("&H" & sTemp) And &H8
  iSign = IIf(fTemp = 8, -1, 1)
   
  ' 指数部 11ビット
  sTemp = Mid(sHex, 1, 3)
  fTemp = Val("&H" & sTemp) And &H7FF
  iExponent = fTemp - 1023  '64ビット形式のバイアス=1023
 
  ' 仮数部 52ビット
  sTemp = Mid(sHex, 4, 13)
  fTemp = CDbl("&H" & sTemp)
  fFraction = 1 + (fTemp / 2 ^ 52)
   
  HexToDouble = iSign * fFraction * 2 ^ iExponent
 
End Function


Sub ボタン2_Click()
  '' 単精度実数書き込み、読み出し
  Dim iData(1) As Integer
  Dim sData As String
  Dim i As Integer
  Dim st, st2 As String
  Dim f As Single
  
  f = -123.456
  sData = SingleToHex(f, True) '' "C2F6E666"
  
  '' 下位から格納(D0 = E666, D1 = C2F6 と格納すれば良い)
  For i = 0 To 1
    iData(i) = CInt("&H" & Mid(sData, (1 - i) * 4 + 1, 4))
  Next i
  
  With Worksheets("Sheet1").ActUtlType1
    .ActLogicalStationNumber = 6 ''通信設定ユーティリティーでの論理局番
    .Open
    '' 書き込み
    Call .WriteDeviceBlock2("D0", 2, iData(0))
    '' 読み出し
    Call .ReadDeviceBlock2("D0", 2, iData(0))
    For i = 1 To 0 Step -1
      st = Hex(iData(i))
      st2 = st2 + String(4 - Len(st), "0") + st
    Next i
    '' Debug.Print st2
    f = HexToSingle(st2)
    With Worksheets("Sheet1")
      .Cells(1, 1).Value = st2
      .Cells(1, 2).Value = f
    End With
    .Close
  End With
End Sub

Sub ボタン3_Click()
  '' 倍精度実数書き込み、読み出し
  Dim iData(3) As Integer
  Dim sData As String
  Dim i As Integer
  Dim st, st2 As String
  Dim d As Double
  
  d = -123.456
  sData = DoubleToHex(d, True) '' "C05EDD2F1A9FBE77"
  For i = 0 To 3
    iData(i) = CInt("&H" & Mid(sData, (3 - i) * 4 + 1, 4))
  Next i
  
  With Worksheets("Sheet1").ActUtlType1
    .ActLogicalStationNumber = 6 ''通信設定ユーティリティーでの論理局番
    .Open
    
    '' 書き込み
    Call .WriteDeviceBlock2("D0", 4, iData(0))
    '' 表示形式 : ワード、16bit、16 進表示の場合
    '' D3=C05E, D2=DD2F, D1=1A9F, D0=BE77
    
    '' 読み出し
    Call .ReadDeviceBlock2("D0", 4, iData(0))
    
    For i = 3 To 0 Step -1
      st = Hex(iData(i))
      st2 = st2 + String(4 - Len(st), "0") + st
    Next i
    '' Debug.Print st2
    d = HexToDouble(st2)
    With Worksheets("Sheet1")
      .Cells(1, 1).Value = st2
      .Cells(1, 2).Value = d
    End With
    .Close
  End With
End Sub