MITSUBISHI MX Component を Excel VBA で使う (2016/07/16)
■Excel VBA で MX Componet を使ってみました。
・FX5UCPU の Ethernet ポート直結接続です。
・通信エラー中のみ、Application.OnTime で、2 秒周期で、再接続を試みます。
・デバイスの値の取得は、MX Component のイベント OnDeviceStatus を使って 1 秒周期で取得しています。
Option Explicit '' ■概要 '' ワークブックを開くと、自動でPLCに接続する '' 接続失敗、通信異常の場合は、2秒周期で接続を試みる '' ダミーのビットデバイスを ONにし、状態監視のOnDeviceStatusイベントを '' 1秒周期で発生させ、この時に、必要なデバイスの情報を取得する '’■注意事項 '' セル入力中は通信が止まる(マルチスレッドでは無い) '' Application.OnTime で1秒ごとにデバイスの値を取得するより、 '' OnDeviceStatus イベント発生時に取得するほうが、負担が少ない '' VBA コード編集時は、Application.OnTime、OnDeviceStatusイベントは、 '' 停止させたほうが良い '' インタプリタのため、編集中のコードが周期的に走り、編集しにくくなる '' 定数 Global Const CPU_FX5UCPU = &H210 ' FX5UCPU Global Const UNIT_FXVETHER_DIREC = &H2002 ' FX5UCPU直結 ' Global Const PROTOCOL_TCPIP = &H5 ' TCP/IP経由 Global Const PROTOCOL_UDPIP = &H8 ' UDP/IP経由 '' グローバル変数 Public GB_OpenFlag As Boolean Public GB_TmBusyFlag As Boolean '' 今回取得データ Public GB_DataThis(2) As Long Public GB_DataThis2(2) As Integer Public GB_sDevice As String '' ***************** '' Module1 '' ***************** '' 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 PLC_Open() On Error Resume Next Dim lRet As Long With Worksheets("Sheet1").ActProgType1 If Not GB_OpenFlag Then ''******************************* ''FX5UCPU Ethernetポート 直結接続 ''******************************* .ActUnitType = UNIT_FXVETHER_DIREC 'ユニットタイプ .ActProtocolType = PROTOCOL_UDPIP '通信プロトコルタイプ .ActNetworkNumber = 0 'ネットワーク番号(0=自局) .ActStationNumber = 255 '局番号(自局指定時は“255”(0xFF) を指定) .ActUnitNumber = 0 'ユニット番号(自ネットワーク内アクセスの場合は“0”(0x00)固定) .ActConnectUnitNumber = 0 'ユニット番号 .ActIONumber = &H3FF 'ユニットI/O 番号(自局CPUは、“1023”(0x3FF)固定) .ActCpuType = CPU_FX5UCPU 'CPUタイプ '' 直結接続の場合 .ActHostAddress = "255.255.255.255" '接続ホスト名(IP アドレス)文字列 .ActDestinationPortNumber = &H15B8 .ActDestinationIONumber = 0 .ActCpuTimeOut = 0 'CPU 監視タイマ(単位は"×250ms") .ActTimeOut = 500 '通信のタイムアウト値(単位は"ms") '' オープン lRet = .Open() '' 正常終了 If (lRet = 0) Then GB_OpenFlag = True '' すでにオープン済 ElseIf (lRet = &HF0000003) Then '' 一度クローズ Call .Close '' 再度オープン lRet = .Open() If (lRet = 0) Then: GB_OpenFlag = True End If '' 状態監視のため、ダミー点をON If GB_OpenFlag Then Call .SetDevice(GB_sDevice, 1) End If End If End With End Sub '' クローズ Sub PLC_Close() On Error Resume Next With Worksheets("Sheet1").ActProgType1 If GB_OpenFlag Then .Close GB_OpenFlag = False End If End With End Sub '' 状態監視デバイスを登録 Sub SetDeviceStatus() '' リセットされた時のため If GB_sDevice = "" Then: GB_sDevice = "M96" Dim lEntryData(1) As Long '' ONを監視 lEntryData(0) = 1 With Worksheets("Sheet1") '' 状態監視削除 Call .ActProgType1.FreeDeviceStatus '' 状態監視登録(M96 の 1 個、1 秒周期 Call .ActProgType1.EntryDeviceStatus(GB_sDevice, 1, 1, lEntryData(0)) End With End Sub '' オープン再試行タイマー Sub TimerProc2() If Not GB_TmBusyFlag Then GB_TmBusyFlag = True With Worksheets("Sheet1").Cells(1, 1) '' 通信中「青色」点滅表示 If .Font.Color <> RGB(255, 0, 255) Then: .Font.Color = RGB(255, 0, 0) If .Value <> "■" Then: .Value = "■": Else .Value = "□" End With If Not GB_OpenFlag Then '' オープン Call PLC_Open '' 状態監視を登録 If GB_OpenFlag Then: Call SetDeviceStatus End If '' オープン失敗 If Not GB_OpenFlag Then '' タイマー起動 Application.OnTime Now + TimeValue("00:00:02"), "TimerProc2" End If GB_TmBusyFlag = False End If End Sub '' ビットデータの結果を表示 Sub ResDisp1() Dim i As Integer Dim s As String Dim lTemp As Long With Worksheets("Sheet1") lTemp = .Cells(5, 1).Value For i = 0 To 15 s = .Cells(5 + i, 3).Value If (lTemp And 2 ^ i) > 0 Then If s <> "●" Then: .Cells(5 + i, 3).Value = "●" Else If s <> "○" Then: .Cells(5 + i, 3).Value = "○" End If Next End With End Sub -------------------------------- Option Explicit '' ***************** '' ThisWorkbook '' ***************** '' クローズ Private Sub Workbook_BeforeClose(Cancel As Boolean) '' 通信クローズ Call PLC_Close End Sub '' ワークブックオープン Private Sub Workbook_Open() '' オープンフラグを初期化 GB_OpenFlag = False '' 状態監視のためのダミーデバイス GB_sDevice = "M96" '' 初期状態 Dim obj As Object With Worksheets("Sheet1") Set obj = .OLEObjects("CommandButton1").Object obj.Caption = "通信許可中" '' バックカラ―:ボタン色 obj.BackColor = &H8000000F '' 文字色:黒 obj.ForeColor = RGB(0, 0, 0) '' オープン Call PLC_Open If GB_OpenFlag Then '' 状態監視を登録 Call SetDeviceStatus Else '' オープン再試行 Call TimerProc2 End If End With End Sub -------------------------------- Option Explicit '' ***************** '' Sheet1 (Sheet1) '' ***************** '' デバイス状態監視 '' GB_sDevice に設定されたビットデバイス("M96"等)がONの時は、1秒周期で実行される Private Sub ActProgType1_OnDeviceStatus(ByVal szDevice As String, ByVal lData As Long, ByVal lReturnCode As Long) On Error Resume Next Dim lRet As Long Dim dTemp As Double Dim lTemp As Long Dim iTemp As Integer Dim s As String If szDevice = GB_sDevice Then If lReturnCode = 0 Then '' 通信中「青色」点滅表示 With Worksheets("Sheet1").Cells(1, 1) If .Font.Color <> RGB(0, 0, 255) Then: .Font.Color = RGB(0, 0, 255) If .Value <> "■" Then: .Value = "■": Else .Value = "□" End With '' 読込処理 With Worksheets("Sheet1") '' M0 から M15 までの 16 点を読み出す lRet = .ActProgType1.ReadDeviceBlock("M0", 1, GB_DataThis(0)) If lRet = 0 Then If .Cells(5, 1).Value <> GB_DataThis(0) Then .Cells(5, 1).Value = GB_DataThis(0) '' 結果を表示 Call ResDisp1 End If End If '' D0 を 16 ビット整数として読みだす lRet = .ActProgType1.ReadDeviceBlock2("D0", 1, GB_DataThis2(0)) If lRet = 0 Then ''16ビット整数 iTemp = GB_DataThis2(0) '' ReadDeviceBlock(LONGで取得)の時は、マイナス値表示のために必要 ''If lTemp >= 2 ^ 15 Then: lTemp = lTemp - 2 ^ 16 If .Cells(21, 1).Value <> iTemp Then: .Cells(21, 1).Value = iTemp End If '' D0, D1 を 32 ビット整数として読みだす lRet = .ActProgType1.ReadDeviceBlock("D0", 2, GB_DataThis(0)) If lRet = 0 Then dTemp = GB_DataThis(1) * 2 ^ 16 + GB_DataThis(0) If dTemp >= 2 ^ 31 Then: dTemp = dTemp - 2 ^ 32 If .Cells(22, 1).Value <> dTemp Then: .Cells(22, 1).Value = dTemp End If End With End If End If '' エラー時、一度クローズし、再度オープンする If lReturnCode <> 0 Then With Worksheets("Sheet1").Cells(1, 1) '' 通信異常「赤色」点灯表示 If .Font.Color <> RGB(255, 0, 0) Then: .Font.Color = RGB(255, 0, 0) .Value = "■" End With '' オープン再試行 GB_OpenFlag = False Call TimerProc2 End If End Sub '' 通信許可/禁止ボタン '' !!コード編集時は、通信禁止にすること!! Private Sub CommandButton1_Click() Dim obj As Object With Worksheets("Sheet1") '' 値がリセットされてしまった時のため If GB_sDevice = "" Then GB_sDevice = "M96" Set obj = .OLEObjects("CommandButton1").Object If obj.Caption <> "通信許可中" Then obj.Caption = "通信許可中" '' バックカラ―:ボタン色 obj.BackColor = &H8000000F '' 文字色:黒 obj.ForeColor = RGB(0, 0, 0) GB_TmBusyFlag = False GB_OpenFlag = False '' オープン Call PLC_Open If GB_OpenFlag Then '' 状態監視を登録 Call SetDeviceStatus Else '' オープン再試行 Call TimerProc2 End If Else obj.Caption = "通信禁止中" '' バックカラ―:赤 obj.BackColor = RGB(255, 0, 0) '' 文字色:白 obj.ForeColor = RGB(255, 255, 255) '' 状態監視のためのダミー点を OFF '' これにより、OnDeviceStatus イベントは発生しなくなる If GB_OpenFlag Then Call .ActProgType1.SetDevice(GB_sDevice, 0) End If '' 再接続を行わない GB_TmBusyFlag = True .Cells(1, 1).Value = "□" .Cells(1, 1).Font.Color = RGB(0, 0, 0) End If End With DoEvents End Sub