こんにちは。テラロイドです。
最近、PLCと通信するソフトを作成しましたが、記事が少なかったため投稿します。
本記事では、三菱電機のPLCと通信するためのプロトコル「SLMP」もしくは「MCプロトコル」の伝文作成について書きました。
伝文は条件により若干変わりますので条件書いときます。
PLCの型式:Qシリーズ(iQシリーズや他のシリーズではコマンドが変わることがあります。)
コードはASCIIとバイナリが可能ですが、本記事はバイナリで伝文を作成しています。
伝文フォーマットは下記の様な構成になっていますが、要求データを作成してから他の項目を作成していくようにしています。
伝文フォーマット = ヘッダ + サブヘッダ + アクセス経路 + 応答データ長 + 監視タイマー + 要求データ
要求データ作成(一括読出し)
/// <summary>一括読出し(batch read)</summary>
/// <param name="NumberOfDevicePoints">読出しデバイス点数</param>
/// <returns></returns>
public override byte[] ReadInBulkInWordUnits(int NumberOfDevicePoints)
{
IEnumerable<byte> createCommand;
//コマンド
createCommand = new byte[]{0x01,0x04};
//サブコマンド
createCommand = createCommand.Concat(new byte[]{0x00,0x00});
//先頭デバイス番号
createCommand = createCommand.Concat(new byte[]{0x00,0x00,0x00});
//デバイスコード
createCommand = createCommand.Concat(new byte[]{0xA8});
//デバイス点数
byte upperHex = (byte)(numberOfDevicePoints / 256);
byte lowerHex = (byte)(numberOfDevicePoints % 256);
createCommand = createCommand.Concat(new byte[] {lowerHex,upperHex});
return createSendMessage((byte[])createCommand.ToArray());
}
要求データ作成(一括書込み)
/// <summary>一括書込み(ワード単位)(batch write)</summary>
/// <param name="WriteData">書込みデータ</param>
/// <returns></returns>
public override byte[] WriteInBulkInWordUnits(byte[] WriteData)
{
IEnumerable<byte> createCommand;
//コマンド
createCommand = new byte[]{0x01,0x14};
//サブコマンド
createCommand = createCommand.Concat(new byte[]{0x00,0x00});
//先頭デバイス番号
createCommand = createCommand.Concat(new byte[]{0x00,0x00,0x00});
//デバイスコード
createCommand = createCommand.Concat(new byte[]{0xA8});
//デバイス点数
createCommand = createCommand.Concat(createNumberOfDevicePoints(WriteData.Length / 2));
//書込みデータ
createCommand = createCommand.Concat(WriteData);
return createSendMessage((byte[])createCommand.ToArray());
}
要求伝文作成
protected override byte[] createSendMessage(byte[] command)
{
IEnumerable<byte> createMessage;
//要求伝文フォーマット
//伝文フォーマット = ヘッダ + サブヘッダ + アクセス経路 + 応答データ長 + 監視タイマー + 要求データ
//①TCPヘッダーの為、不要
//②サブヘッダ―
////サブヘッダ― = 要求伝文
createMessage = new byte[]{0x50,0x00};
//③アクセス経路
//アクセス経路 = ネットワーク番号 + PC番号 + 要求先ユニットI/O番号 + 要求先ユニット局番号
createMessage = createMessage.Concat(new byte[]{0x00});
createMessage = createMessage.Concat(new byte[]{0xFF});
createMessage = createMessage.Concat(new byte[]{0xFF,0x03});
createMessage = createMessage.Concat(new byte[]{0x00});
//④データ長
byte upperHex = (byte)((2 + command.Length) / 256);
byte lowerHex = (byte)((2 + command.Length) % 256);
if ((upperHex / 256) >= 1) { throw new Exception("データ長に不正な値が設定されました。(桁数オーバー)"); }
createMessage = createMessage.Concat(new byte[]{ lowerHex });
createMessage = createMessage.Concat(new byte[]{ upperHex });
//⑤監視タイマー
byte upperHex2 = (byte)((monitoringTimer) / 256);
byte lowerHex2 = (byte)((monitoringTimer) % 256);
if ((upperHex2 / 256) >= 1) { throw new Exception("監視タイマーに不正な値が設定されました。(桁数オーバー)"); }
createMessage = createMessage.Concat(new byte[]{ upperHex2 });
createMessage = createMessage.Concat(new byte[]{ lowerHex2 });
//⑥要求データ
//要求データ = コマンド + サブコマンド + 先頭デバイス +
createMessage = createMessage.Concat(command);
//ログ出力
string tmp = "";
string text = "";
foreach (byte b in (byte[])createMessage){text = string.Format("{0,3:X2}", b);tmp = tmp + text;}
log.OutputDebug("[S]" + tmp);
return (byte[])createMessage.ToArray();
}