MELSEC MX Component を VB.NET で使う (2016/07/22 修正)
■VB.NET (Visual Studio 2015) で MX Componet を使ってみました。
・FX5UCPU の Ethernet ポート直結接続です。
・起動と同時に通信を開始し、オープン中は、100 ミリ秒周期でデバイスの値を取得します。
・通信異常時は、1 秒周期で再接続を試みます。
※VS 2015 の場合、メニュー - [プロジェクト] - 「既存の項目の追加」で、
C:\MELSEC\Act\Include フォルダの ActDefine.vb を追加すると、
UNIT_FXVETHER_DIRECT, CPU_FX5UCPU ... 等の定義が、使用できるようになります。
※変換関数は、MX Component の サンプル SampleTypeConv を参考にしています。
Imports System.Text 'Encodingクラスを含む名前空間 Module Module1 '' ************************************** '' 参考:MX Component の SampleTypeConv '' ************************************** '' ASCIIコードページにエンコードするインスタンス生成 Dim objAsciiCodePageEncoding As Encoding = Encoding.Default '' シーケンサ取得データを16ビット整数に Public Function IntArrayToShort(ByVal sharrBufferForDeviceValue() As Integer) As Short Dim byarrBufferByte(1 * 2 - 1) As Byte ' 編集用バイトバッファの宣言 Dim byarrTemp() As Byte ' シーケンサ用データを一時的に受ける配列 Dim i As Integer ' ループ用カウンタ '' シーケンサ用データバッファからバイト配列に変換 byarrTemp = BitConverter.GetBytes(sharrBufferForDeviceValue(0)) byarrBufferByte(0) = byarrTemp(0) byarrBufferByte(1) = byarrTemp(1) Return BitConverter.ToInt16(byarrBufferByte, 0) End Function '' シーケンサ取得データを32ビット整数に Public Function IntArrayToInt(ByVal sharrBufferForDeviceValue() As Integer) As Integer Dim byarrBufferByte(2 * 2 - 1) As Byte ' 編集用バイトバッファの宣言 Dim byarrTemp() As Byte ' シーケンサ用データを一時的に受ける配列 Dim i As Integer ' ループ用カウンタ '' シーケンサ用データバッファからバイト配列に変換 For i = 0 To 1 byarrTemp = BitConverter.GetBytes(sharrBufferForDeviceValue(i)) byarrBufferByte(i * 2) = byarrTemp(0) byarrBufferByte(i * 2 + 1) = byarrTemp(1) Next i Return BitConverter.ToInt32(byarrBufferByte, 0) End Function '' シーケンサ取得データを32ビット実数(単精度)に Public Function IntArrayToSingle(ByVal sharrBufferForDeviceValue() As Integer) As Single Dim byarrBufferByte(2 * 2 - 1) As Byte ' 編集用バイトバッファの宣言 Dim byarrTemp() As Byte ' シーケンサ用データを一時的に受ける配列 Dim i As Integer ' ループ用カウンタ '' シーケンサ用データバッファからバイト配列に変換 For i = 0 To 1 byarrTemp = BitConverter.GetBytes(sharrBufferForDeviceValue(i)) byarrBufferByte(i * 2) = byarrTemp(0) byarrBufferByte(i * 2 + 1) = byarrTemp(1) Next i Return BitConverter.ToSingle(byarrBufferByte, 0) End Function '' シーケンサ取得データを64ビット実数(倍精度)に Public Function IntArrayToDouble(ByVal sharrBufferForDeviceValue() As Integer) As Double Dim byarrBufferByte(4 * 2 - 1) As Byte ' 編集用バイトバッファの宣言 Dim byarrTemp() As Byte ' シーケンサ用データを一時的に受ける配列 Dim i As Integer ' ループ用カウンタ '' シーケンサ用データバッファからバイト配列に変換 For i = 0 To 3 byarrTemp = BitConverter.GetBytes(sharrBufferForDeviceValue(i)) byarrBufferByte(i * 2) = byarrTemp(0) byarrBufferByte(i * 2 + 1) = byarrTemp(1) Next i Return BitConverter.ToDouble(byarrBufferByte, 0) End Function '' 16ビット整数をシーケンサ転送用データに Public Sub ShortToIntArray(ByVal shtValue As Short, ByRef sharrBufferForDeviceValue() As Integer) Dim byarrBufferByte() As Byte '' 入力されたデータをSingle型数値に変換し、バイト配列に代入(データ量は2バイト固定) byarrBufferByte = BitConverter.GetBytes(shtValue) '' バイト配列からシーケンサ用データバッファに代入 sharrBufferForDeviceValue(0) = BitConverter.ToInt16(byarrBufferByte, 0) End Sub '' 32ビット整数をシーケンサ転送用データに Public Sub IntToIntArray(ByVal intValue As Integer, ByRef sharrBufferForDeviceValue() As Integer) Dim byarrBufferByte() As Byte Dim i As Integer '' 入力されたデータをSingle型数値に変換し、バイト配列に代入(データ量は4バイト固定) byarrBufferByte = BitConverter.GetBytes(intValue) For i = 0 To 1 '' バイト配列からシーケンサ用データバッファに代入 sharrBufferForDeviceValue(i) = BitConverter.ToInt16(byarrBufferByte, i * 2) Next i End Sub '' 32ビット実数(単精度)をシーケンサ転送データに Public Sub SingleToIntArray(ByVal sngValue As Single, ByRef sharrBufferForDeviceValue() As Integer) Dim byarrBufferByte() As Byte Dim i As Integer '' 入力されたデータをSingle型数値に変換し、バイト配列に代入(データ量は4バイト固定) byarrBufferByte = BitConverter.GetBytes(sngValue) '' バイト配列からシーケンサ用データバッファに代入 For i = 0 To 1 sharrBufferForDeviceValue(i) = BitConverter.ToInt16(byarrBufferByte, i * 2) Next i End Sub '' 64ビット実数(倍精度)をシーケンサ転送データに Public Sub DoubleToIntArray(ByVal dblValue As Double, ByRef sharrBufferForDeviceValue() As Integer) Dim byarrBufferByte() As Byte Dim i As Integer '' 入力されたデータをSingle型数値に変換し、バイト配列に代入(データ量は8バイト固定) byarrBufferByte = BitConverter.GetBytes(dblValue) '' バイト配列からシーケンサ用データバッファに代入 For i = 0 To 3 sharrBufferForDeviceValue(i) = BitConverter.ToInt16(byarrBufferByte, i * 2) Next i End Sub '' シーケンサ取得データを文字列に Function ShortArrayToString(ByVal sharrBufferForDeviceValue() As Short, ByVal txtlen As Integer) As String Dim byarrBufferByte(txtlen - 1) As Byte '編集用バイトバッファの宣言 Dim byarrTemp() As Byte 'シーケンサ用データを一時的に受ける配列 Dim i As Integer 'ループ用カウンタ '' シーケンサ用データバッファからバイト配列に変換 For i = 0 To txtlen / 2 - 1 byarrTemp = BitConverter.GetBytes(sharrBufferForDeviceValue(i)) byarrBufferByte(i * 2) = byarrTemp(0) byarrBufferByte(i * 2 + 1) = byarrTemp(1) Next i '' コードページバイト配列からUnicodeに変換して、読出し用テキストボックスに格納 Return objAsciiCodePageEncoding.GetString(byarrBufferByte) End Function '' 文字列をシーケンサ転送データに Sub StringToShortArray(ByVal s As String, ByVal txtlen As Integer, ByRef sharrBufferForDeviceValue() As Short) Dim byarrBufferByte() As Byte ' 編集用バイトバッファの宣言 Dim iLengthOfBuffer As Integer ' シーケンサ用バッファに書き込む文字数 Dim i As Integer ' ループ用カウンタ '' 文字列からコードページのByte配列に変換 byarrBufferByte = objAsciiCodePageEncoding.GetBytes(s) '' Byte配列からシーケンサ用データバッファに変換する文字数の設定 iLengthOfBuffer = Math.Min(byarrBufferByte.Length, txtlen) '' Byte配列からシーケンサ用データバッファに変換 '' Step 2 :2つのByte配列データをShort配列データに代入するため '' iLengthOfBuffer - 2 :文字数が奇数量の場合、最後のBitConverter実行時に領域外を参照しないため For i = 0 To iLengthOfBuffer - 2 Step 2 sharrBufferForDeviceValue(i / 2) = BitConverter.ToInt16(byarrBufferByte, i) Next i '' 文字数が奇数量だった場合の最後の文字の処理 If (iLengthOfBuffer Mod 2) = 1 Then sharrBufferForDeviceValue(Fix(iLengthOfBuffer / 2)) = byarrBufferByte(iLengthOfBuffer - 1) End If End Sub End Module Public Class Form1 Public GB_OpenFlag As Boolean Public GB_ReadCnt As Integer Public GB_OpenCnt As Integer Public GB_TmBusyFlag As Boolean '' PLCオープン Public Sub PlcOpen() Dim iRet As Integer '' FX5UCPU Ehernetポート 直結 With AxActProgType1 .ActUnitType = UNIT_FXVETHER_DIRECT ''&H2002 '' ユニットタイプ .ActCpuType = CPU_FX5UCPU ''&H210 '' CPUタイプ .ActProtocolType = PROTOCOL_UDPIP ''&H8 '' 通信プロトコルタイプ .ActHostAddress = "255.255.255.255" .ActDestinationPortNumber = &H15B8 .ActTimeOut = 500 iRet = .Open() '' TextBox1.Text = String.Format("{0:X8}", iRet) '' すでにオープンされている If iRet = &HF0000003 Then .Close() iRet = .Open() End If GB_OpenFlag = iRet = 0 End With End Sub '' クローズ Public Sub PlcClose() With AxActProgType1 .Close() GB_OpenFlag = False End With End Sub '' インターバルタイマー Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick Dim iRet As Integer Dim iData(4) As Integer Dim txtlen As Integer = 20 Dim shtData(txtlen / 2) As Short If Not GB_TmBusyFlag Then GB_TmBusyFlag = True If Not GB_OpenFlag Then GB_OpenCnt = GB_OpenCnt + 1 TextBox1.Text = GB_OpenCnt PlcOpen() If GB_OpenFlag Then '' 100 ミリ秒でデバイス読込 Timer1.Interval = 100 End If End If If GB_OpenFlag Then GB_ReadCnt = GB_ReadCnt + 1 TextBox2.Text = GB_ReadCnt With AxActProgType1 iRet = .ReadDeviceBlock("D0", 4, iData(0)) If iRet <> 0 Then GB_OpenFlag = False '' 2 秒周期で再接続 Timer1.Interval = 2000 Else '' D0 を 16ビット整数 TextBox11.Text = CStr(IntArrayToShort(iData)) '' D1, D0 を 32ビット整数 TextBox12.Text = CStr(IntArrayToInt(iData)) '' D1, D0 を 32ビット実数(単精度) TextBox13.Text = CStr(IntArrayToSingle(iData)) '' D3 ~ D0 を 64ビット実数(倍精度) TextBox14.Text = CStr(IntArrayToDouble(iData)) '' 文字列(最大20文字) .ReadDeviceBlock2("D0", txtlen / 2, shtData(0)) TextBox16.Text = ShortArrayToString(shtData, txtlen) End If End With End If GB_TmBusyFlag = False End If End Sub Private Sub Form1_Activated(sender As Object, e As EventArgs) Handles Me.Activated Timer1.Interval = 100 Timer1.Enabled = True End Sub '' 16 ビット整数 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim iData(1) As Integer Try If GB_OpenFlag Then 'iData(0) = CShort(TextBox10.Text) 'AxActProgType1.WriteDeviceBlock("D0", 1, iData(0)) ShortToIntArray(CShort(TextBox10.Text), iData) AxActProgType1.WriteDeviceBlock("D0", 1, iData(0)) End If Catch ex As Exception '' End Try End Sub '' 32 ビット整数 Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Dim iData(2) As Integer Try If GB_OpenFlag Then IntToIntArray(CInt(TextBox9.Text), iData) AxActProgType1.WriteDeviceBlock("D0", 2, iData(0)) End If Catch ex As Exception '' End Try End Sub '' 32ビット実数(単精度) Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click Dim iData(2) As Integer Try If GB_OpenFlag Then SingleToIntArray(CSng(TextBox8.Text), iData) AxActProgType1.WriteDeviceBlock("D0", 2, iData(0)) End If Catch ex As Exception '' End Try End Sub '' 64 ビット実数(倍精度) Private Sub Button4_Click_1(sender As Object, e As EventArgs) Handles Button4.Click Dim iData(4) As Integer Try If GB_OpenFlag Then DoubleToIntArray(CDbl(TextBox7.Text), iData) AxActProgType1.WriteDeviceBlock("D0", 4, iData(0)) End If Catch ex As Exception '' End Try End Sub '' 文字列 Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click Dim txtlen As Integer = 20 '最大文字列数 Dim shtData(txtlen / 2 - 1) As Short 'シーケンサ用バッファの宣言 StringToShortArray(TextBox15.Text, txtlen, shtData) If GB_OpenFlag Then AxActProgType1.WriteDeviceBlock2("D0", txtlen / 2, shtDatae(0)) End If End Sub End Class