powershellスクリプトで三菱電機(株)製PLC(シーケンサ)iQ-R,Qシリーズとイーサネット通信を行います。実行環境は、以下となります。
項目 | 内容 |
---|---|
対象としたイーサネットポート | イーサネットユニット:RJ71EN71,QJ71E71-100,CPUのイーサネットポート |
通信手順 | MCプロトコル QnA互換3Eフレーム ASCIIコード |
GX Works3 ナビゲーションウインドウのプロジェクトからユニット情報の RJ71EN71(*+*) から [ポート1ユニットパラメータ] をマウスダブルクリックし設定シートを表示します。IPアドレスを設定し、RUN中の書込許可/禁止設定を「一括で許可する(SLMP)」に、交信データコードを「ASCII」とします。
次に「相手機器接続構成設定」の<詳細設定>をマウスダブルクリックしEthernet構成(先頭I/O:****)ダイアログを開きます。
ユニット一覧より「SLMP接続機器」をマウス選択し左下の自局右にドラッグします。プロトコルを「TCP」としポート番号を設定します。
「設定を反映して閉じる」をマウスクリックしダイアログを閉じます。「適用」ボタンをマウスクリックします。
GX Works3 ナビゲーションウインドウのプロジェクトから[R**CPU]の[ユニットパラメータ]をマウスダブルクリックし設定シートを
表示します。IPアドレスを設定し、RUN中の書込許可/禁止設定を「一括で許可する(SLMP)」に、交信データコードを「ASCII」とします。
次に「相手機器接続構成設定」の<詳細設定>をマウスダブルクリックしEthernet構成(内蔵Ethernetポート)ダイアログを開きます。
ユニット一覧より「SLMP接続機器」をマウス選択し左下の自局右にドラッグします。プロトコルを「TCP」としポート番号を設定します。
「設定を反映して閉じる」をマウスクリックしダイアログを閉じます。「適用」ボタンをマウスクリックします。
GX Works2 ナビゲーションウインドウのネットワークパラメータから[Ethernet/CC IE/MELSECNET]をマウスダブルクリックし、ネットワークパラメータ を開きます。ユニットX欄のネットワーク種別を[Ethernet]とし、先頭I/O No.、ネットワークNo.、グループNo.、局番 を設定します。[モード]を[オンライン]とします。次に[動作設定]をマウスクリックし、[Ethernet 動作設定]ダイアログを開き以下のように設定します。
項目 | 内容 |
---|---|
交信データコード設定 | [ASCIIコード交信] を選択 |
イニシャルタイミング設定 | [常にOPEN待ち(STOP中交信可能)] を選択 |
IPアドレス設定 | 入力形式を10進数としIPアドレスを設定します。 |
RUN中書込を許可する | チェックを入れます。 |
送信フレーム設定 | [Ethernet(V2.0)]を選択。 |
TCP生存確認設定 | [KeepAliveを使用] を選択。 |
「設定終了」ボタンマウスクリックで [Ethernet 動作設定]ダイアログを閉じます。
次に[オープン設定]をマウスクリックし、ネットワークパラメータを開きます。任意の行に以下のように設定します。
項目 | 内容 |
---|---|
プロトコル | 「TCP」を選択 |
オープン方式 | 「Unpassive」(受動的オープン)を選択 |
固定バッファ | 「送信」を選択 MCプロトコルの場合は、「送信」、「受信」どちらでも良い |
固定バッファ交信手順 | 「手順あり」を選択 |
ペアリングオープン | 「ペアにしない」を選択 |
生存確認 | 「確認する」を選択 |
自局ポート番号 | ここでは、「4000」(10進)と設定します。 |
交信相手IPアドレス | 設定不要 |
交信相手ポート番号 | 設定不要 |
「設定終了」ボタンで終了します。
GX Works2 ナビゲーションウインドウのプロジェクトから[PCパラメータ]をマウスダブルクリックし、Qパラメータ設定 ダイアログを
表示します。IPアドレスを設定し、交信データコード設定を[ASCIIコード交信]とします。[RUN中書込みを許可する]にチェックを
入れます。
「オープン設定」ボタンをマウスクリックし、内蔵Ethernetポートオープン設定 ダイアログを表示します。
任意の行にポート設定を行います。[プロトコル]を「TCP」に、[オープン方式]を「MCプロトコル」とし、[自局ポート番号]を設定します。
「設定終了」ボタンで 内蔵Ethernetポートオープン設定 ダイアログ、Qパラメータ設定 ダイアログ を閉じます。
下記ソフトは、レジスタのD0100より10ワード読み込みを行ってます。エラー処理は行ってません。「q」キーで終了します。プログラムは、コンソールウインドウで実行して下さい。ISEでは、エラーとなります。
iQ-Rではコマンドが追加されています。(サブコマンド) 追加されたコマンドではデバイスコードが4バイド、デバイス番号が8バイトとなっています。下記プログラムでは、変数 $iQRExMode で iQ-R 追加コマンド使用ありなしを指定しています。
# MelEthTcpASCII3E.ps1
# 三菱PLC MCプロトコルイーサネット通信
# TCP QnA互換3E ASCII
Set-StrictMode -Version latest
# キー入力
function Keyin{
$rtkey = $null
if ([Console]::KeyAvailable){
$rtkey = [Console]::ReadKey($true)
}
return $rtkey
}
# 受信
function receive([byte[]]$bydt, [ref][int]$ipt, [ref][int]$irlen){
$ir = 0
try{
$il = $stream.Read($bydt, $ipt.Value, 100)
$ipt.Value += $il
if ($irlen.Value -eq 0 -and $ipt.Value -ge 18){
[byte[]] $bywk = New-Object byte[] 4
[System.Array]::Copy($bydt, 14, $bywk, 0, 4) # 応答データ長
$sa = [System.Text.Encoding]::ASCII.GetString($bywk)
$irlen.Value = [int]("0x" + $sa) + 18
}
if ($irlen.Value -gt 0 -and $ipt.Value -ge $irlen.Value){
$ir = 1 # 受信完了
}
}
catch{
}
return $ir
}
$iQRExMode = 0 # 1:iQ-R追加コマンド
# サブヘッダー Qヘッダー
$ched = "5000" + "00" + "FF" + "03FF" + "00" + "0000" + "0010"
# D100より10ワード読み込み
if ($iQRExMode -eq 0){ # Q
$srsbcmd = "0000" # サブコマンド
$sdv = "D*" # Dデバイス(デバイスコード)
$sdvketa = "D6" # デバイス番号桁
}
else{ # iQ-R
$srsbcmd = "0002" # サブコマンド
$sdv = "D***" # Dデバイス(デバイスコード)
$sdvketa = "D8" # デバイス番号桁
}
$itopad = 100 # 読み込み先頭(デバイス番号)
$ireadsu = 10 # 読み込み個数
# M100より20ビット読み込み
<#
if ($iQRExMode -eq 0){ # Q
$srsbcmd = "0001" # サブコマンド
$sdv = "M*" # Mデバイス(デバイスコード)
$sdvketa = "D6" # デバイス番号桁
}
else{ # iQ-R
$srsbcmd = "0003" # サブコマンド
$sdv = "M***" # Mデバイス(デバイスコード)
$sdvketa = "D8" # デバイス番号桁
}
$itopad = 100 #読み込み先頭(デバイス番号)
$ireadsu = 20 #読み込み個数
#>
$cscmd = "0401" + $srsbcmd + $sdv + $itopad.ToString($sdvketa) + $ireadsu.ToString("X4")
$ilen = $cscmd.Length + 4 # 要求データ長
$slen = $ilen.ToString("X4")
$bylen = [System.Text.Encoding]::ASCII.GetBytes($slen)
$bya = [System.Text.Encoding]::ASCII.GetBytes($ched + $cscmd)
[System.Array]::Copy($bylen, 0, $bya, 14, 4)
[byte[]] $brcdata = New-Object byte[] 512
$ip = 0
$ircvlen = 0
$irsstp = 1
if ($iQRExMode -eq 0){
Write-Host "Qモードで実行"
}
else{
Write-Host "iQ-R追加モードで実行"
}
$soc = New-Object System.Net.Sockets.tcpClient
try{
$soc.Connect("192.168.1.59", 4000)
}
catch{
Write-Host("接続失敗")
exit
}
$stream = $soc.GetStream()
$stream.ReadTimeout = 50 # 受信タイムアウト時間 msec
while($true){
switch($irsstp){
1{
$stream.Write($bya, 0, $bya.Length) # 送信
$irsstp = 2
}
2{
$ir = receive $brcdata ([ref]$ip) ([ref]$ircvlen)
if ($ir -eq 1){ # 受信完了?
$srd = [System.Text.Encoding]::ASCII.GetString($brcdata, 0, $ircvlen)
$sdd = [string]::Empty
if ($sdv.Substring(0, 1) -eq "D"){$ik = 4}
if ($sdv.Substring(0, 1) -eq "M"){$ik = 1}
for($iq = 0; $iq -lt $ireadsu; $iq++){
$sdd += $srd.Substring(22 + $iq * $ik, $ik) + ","
}
Write-Host($sdd)
$ip = 0
$ircvlen = 0
$irsstp = 1
}
}
}
$inkey = Keyin
if ($inkey -ne $null -and $inkey.Key -eq "Q"){
break;
}
Start-Sleep -m 100
}
$soc.Close()
$stream.ReadTimeout で受信タイムアウト時間(msec)を設定します。受信関数 receive 内の 受信 $stream.Read にてタイムアウト時間内に受信がない場合例外を発生して受信関数を抜けますので try catch で処理します。