CIP通信

概略

Ethernetで接続されているPLCの変数をCIP通信を使って読み書きします
フォームにはNJCompoletをnjCompolet1というインスタンス名で貼って置きます

NJCompolet

以下サンプルコードはC#で書いてあります
フォームの作成(ボタンの配置など)は省略しているので適宜ボタンなどは配置してください


njCompolet1をアクティブにする

通信をするには通信相手のPLCのIPアドレスと、ActiveプロパティをTrueにします
サンプルではフォームロード時にセットします

private void Form1_Load(object sender, EventArgs e)
{
    njCompolet1.PeerAddress = "192.168.250.1";		//PLCのIPアドレス
    njCompolet1.Active = true;
}
							

解説

3-4行目


njCompolet1.PeerAddress = "192.168.250.1";		//PLCのIPアドレス
njCompolet1.Active = true;
								

送信先のPLCのIPアドレスをPeerAddressに設定してActiveをTrueにします
ActiveをTrueにすることでPeerAddressのPLCとコネクションを開設します

変数の読出し

button1をクリックするとReadVariableメソッドを実行して変数の値を読み出します

private void button1_Click(object sender, EventArgs e)
{
    try
    {
        // 数値型 実数型
        Int32 vInt = (Int32)njCompolet1.ReadVariable("variableInt");
        float vReal = (float)njCompolet1.ReadVariable("variableReal");

        // 日付時刻
        DateTime vDate = (DateTime)njCompolet1.ReadVariable("variableDate");
        TimeSpan vTime = (TimeSpan)njCompolet1.ReadVariable("variableTime");
        DateTime vDateTime = (DateTime)njCompolet1.ReadVariable("variableDateAndTime");

        // 文字列
        string vStr = (string)njCompolet1.ReadVariable("variableString");

        // 配列
        int[] vAryInt = (int[])njCompolet1.ReadVariable("variableAryInt");

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
							

解説

6行目


Int32 vInt = (Int32)njCompolet1.ReadVariable("variableInt");
								

ReadVariableメソッドを使ってPLCにあるvariableIntという変数を読み出してvIntという変数に格納します
ReadVariableメソッドの戻り値はObject型なのでInt型にキャストしています
PLCのvariableIntはグローバル変数でネットワーク公開を「公開のみ」、「入力」、「出力」のどれかに設定しておきます

7-18行目


float vReal = (float)njCompolet1.ReadVariable("variableReal");

// 日付時刻
DateTime vDate = (DateTime)njCompolet1.ReadVariable("variableDate");
TimeSpan vTime = (TimeSpan)njCompolet1.ReadVariable("variableTime");
DateTime vDateTime = (DateTime)njCompolet1.ReadVariable("variableDateAndTime");

// 文字列
string vStr = (string)njCompolet1.ReadVariable("variableString");

// 配列
int[] vAryInt = (int[])njCompolet1.ReadVariable("variableAryInt");
								

同様にReal型、Date型、Time型、DateTime型、String型を読み出します
配列も同様に配列にキャストして読み出すことができます

変数の書込み

button2をクリックするとWriteVariableメソッドを実行して変数に書込みます

private void button2_Click(object sender, EventArgs e)
{
    try
    {
				// 数値型 実数型
        njCompolet1.WriteVariable("variableInt", 1);
        njCompolet1.WriteVariable("variableReal", 1.23);

				// 日付時刻
        njCompolet1.WriteVariable("variableDate", DateTime.Now);
        njCompolet1.WriteVariable("variableTime", new TimeSpan(1, 0, 0));
        njCompolet1.WriteVariable("variableDateAndTime", DateTime.Now);

				// 文字列
        njCompolet1.WriteVariable("variableString", "ABC");

				// 配列
        int[] intValue = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        njCompolet1.WriteVariable("variableAryInt", intValue);

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
							

解説

6行目


njCompolet1.WriteVariable("variableInt", 1);
								

WriteVariableメソッドを使ってPLCにあるvariableIntという変数に数値1を書込みします

7-19行目


njCompolet1.WriteVariable("variableReal", 1.23);

// 日付時刻
njCompolet1.WriteVariable("variableDate", DateTime.Now);
njCompolet1.WriteVariable("variableTime", new TimeSpan(1, 0, 0));
njCompolet1.WriteVariable("variableDateAndTime", DateTime.Now);

// 文字列
njCompolet1.WriteVariable("variableString", "ABC");

// 配列
int[] intValue = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
njCompolet1.WriteVariable("variableAryInt", intValue);
								

同様にReal型、Date型、Time型、DateTime型、String型を書き込みます
配列も同様に書き込むことができます


構造体の読み書き

読出し
構造体をReadVariableで読み出すとバイト配列でデータが読み出されます
読み出す構造体のメンバのデータ型(サイズ)が違う場合にはアライメントに注意してください

以下の構造体の場合
Struct

下図のようなアライメントになります
alignment

読み出したバイト配列を先頭から順番にBitConverterを使ってそれぞれのデータ型に変換します
String型の場合はnull文字を検索して文字数分をバイト配列からString型の変数に変換します
private void button3_Click(object sender, EventArgs e)
{
    Encoding enc = Encoding.GetEncoding("utf-8");
    byte[] byteArray = new byte[256];
    int pos = 0;

    try
    {
        byte[] bytesTestStruct = (byte[])njCompolet1.ReadVariable("TestStruct");

        UInt16 variableBool = BitConverter.ToUInt16(bytesTestStruct, 0);
        Int16 variableInt = BitConverter.ToInt16(bytesTestStruct, 2);
        UInt16 variableUInt = BitConverter.ToUInt16(bytesTestStruct, 4);
        Int32 variableDint = BitConverter.ToInt32(bytesTestStruct, 8);

        Array.Copy(bytesTestStruct, 12, byteArray, 0, 256);
        pos = Array.IndexOf(byteArray, (byte)0);		//nullを検索して、バイト数にする
        if (pos == -1) pos = 256;			//nullが見つからなければ最大値
        string variableStr = enc.GetString(byteArray, 0, pos);
        Console.WriteLine(variableStr);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
							

解説

3行目


Encoding enc = Encoding.GetEncoding("utf-8");
								

PLCの文字列コードはUTF-8なのでエンコードをUTF-8で用意しておきます

4行目


byte[] byteArray = new byte[256];
								

文字列を格納するバイト配列を用意しておきます

9行目


byte[] bytesTestStruct = (byte[])njCompolet1.ReadVariable("TestStruct");
								

ReadVariableで構造体を読み出してbytesTestStructのバイト配列に格納します

11-14行目


UInt16 variableBool = BitConverter.ToUInt16(bytesTestStruct, 0);
Int16 variableInt = BitConverter.ToInt16(bytesTestStruct, 2);
UInt16 variableUInt = BitConverter.ToUInt16(bytesTestStruct, 4);
Int32 variableDint = BitConverter.ToInt32(bytesTestStruct, 8);
								

BitConverterを使ってbyte配列の指定位置の値を数値に変換します
まず、先頭はBOOL型10個が2byteに入っているので一旦UInt16型で読み出します(BitConverterはBOOL型は対応していないため)
次の12行目はINT型、13行目はUINT型、14行目はDINT型をそれぞれ2,4,8byte目から読出します

16-19行目


Array.Copy(bytesTestStruct, 12, byteArray, 0, 256);
pos = Array.IndexOf(byteArray, (byte)0);		//nullを検索して、バイト数にする
if (pos == -1) pos = 256;			//nullが見つからなければ最大値
string variableStr = enc.GetString(byteArray, 0, pos);
								

16行目から19行目まではバイト配列の12byte目から入っている文字列を読み出します
16行目で12byte目から256byteをbyteArrayに取り出します
17行目で文字列の終端のNullを探すためにIndexOfを使って(byte)0を探します
18行目はNullが見つからないときは256byte全てが文字として扱います
19行目でバイト配列を文字列にエンコードしてvariableStringに格納します


書込み
書込むデータをバイト配列にセットしてPLCに書込みします
読み出す時と同様にアライメントに注意して書き込みます
private void button4_Click(object sender, EventArgs e)
{
    Encoding enc = Encoding.GetEncoding("utf-8");
    byte[] bytedata = new byte[1000];
    byte[] writedata = new byte[268];		//構造体のバイト数

    UInt16 variableBool = 0x10;
    Int16 variableInt = -10;
    UInt16 variableUInt = 20;
    Int32 variableDint = 100000;

    try
    {
        Array.Copy(BitConverter.GetBytes(variableBool), 0, bytedata, 0, 2);
        Array.Copy(BitConverter.GetBytes(variableInt), 0, bytedata, 2, 2);
        Array.Copy(BitConverter.GetBytes(variableUInt), 0, bytedata, 4, 2);
        Array.Copy(BitConverter.GetBytes(variableDint), 0, bytedata, 8, 4);
        byte[] byteArray = enc.GetBytes("ABC");
        Array.Copy(byteArray, 0, bytedata, 12, 3);

        Array.Copy(bytedata, writedata, 16);
        njCompolet1.WriteVariable("TestStruct", writedata);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
							

解説

3行目


Encoding enc = Encoding.GetEncoding("utf-8");
								

PLCの文字列コードはUTF-8なのでエンコードをUTF-8で用意しておきます

4-5行目


byte[] bytedata = new byte[1000];
byte[] writedata = new byte[268];		//構造体のバイト数
								

4行目のbytedataは作業用のバイト配列で1000byte用意しました
5行目のwritedataは構造体に書き込むためのバイト配列で構造体のバイト数の268byteを用意します

7-10行目


UInt16 variableBool = 0x10;
Int16 variableInt = -10;
UInt16 variableUInt = 20;
Int32 variableDint = 100000;
								

各変数に書き込むデータを用意します

14-19行目


Array.Copy(BitConverter.GetBytes(variableBool), 0, bytedata, 0, 2);
Array.Copy(BitConverter.GetBytes(variableInt), 0, bytedata, 2, 2);
Array.Copy(BitConverter.GetBytes(variableUInt), 0, bytedata, 4, 2);
Array.Copy(BitConverter.GetBytes(variableDint), 0, bytedata, 8, 4);
byte[] byteArray = enc.GetBytes("ABC");
Array.Copy(byteArray, 0, bytedata, 12, 3);
								

BitConverter.GetBytesを使って数値をバイト配列に変換してbytedataへ格納していきます
18行目は文字列のためGetBytesで文字列をバイト配列にエンコードしてから19行目でbytedataにコピーして格納します

21-22行目


Array.Copy(bytedata, writedata, 16);
njCompolet1.WriteVariable("TestStruct", writedata);
								

21行目で作業用のbytedataから書込み用のwritedataにコピーします
22行目でWriteVariableを使ってPLCのTestStruct構造体にwritedataの値を書き込みます


DATE_AND_TIME型がメンバにある時の注意
NJ/NXの時刻は1970-01-01を起点に1nsでカウントしています
Windowsの時刻は0001/01/01 00:00:00.000を起点に100nsでカウントしています
構造体のメンバに日付時刻がある場合はバイト配列で上記の経過時間(カウント)が入っているため読み出した値を1970-01-01からの経過時間でWindowの日付時刻に変換してください
double msec =(double)(BitConverter.ToUInt64(bytesTestStruct, 0)) / 1000000.0;
DateTime variableDateTime = new DateTime(1970, 1, 1).AddMilliseconds(msec);
							

時刻書込み

button5をクリックするとPCの時刻をPLCに書き込みます

private void button5_Click(object sender, EventArgs e)
{
    try
		{
        njCompolet1.Clock = DateTime.Now;
    }
    catch(Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
							

解説

5行目


njCompolet1.Clock = DateTime.Now;
								

PCの時刻をそのままClockプロパティに書き込むことでPLCの時刻を変更できます


その他よく使いそうなメンバ

名前 説明
プロパティ ReceiveTimeLimit Compoletの受信待ちがタイムアウトするまでの時間を取得または設定します
IsConnected ノードに接続しているかどうかを取得します
TypeName PLCの形式情報を取得します
RunStatus PLCの運転状態を表します
メソッド ReadVariableMultiple PLCの複数のタグの値を読み出します
GetEventLogs PLCのイベントログを取得します

全てのメンバはヘルプファイルを参照してください
ヘルプファイルは [スタート] - [OMRON] - [CX-Compolet]にあります