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