テクセル

PowerShellでPLCシリアル通信(三菱iQ-R,Qシリーズ)


powershellスクリプトで三菱電機(株)製PLC(シーケンサ)iQ-R,Qシリーズとシリアル通信を行います。実行環境は、以下となります。

項目 内容
対象としたシリアルポート シリアルコミュニケーションユニット:RJ71C24,RJ71C24-R2,QJ71C24N,QJ71C24N-R2 QCPUのシリアルポート(RS-232C)
通信手順  MCプロトコル、QnA互換3Cフレーム形式4、サムチェックあり
通信仕様  通信速度9600bps、データ長8ビット、1ストップビット、奇数パリティ

□ PLCでの設定

1.シリアルコミュニケーションユニット RJ71C24,RJ71C24-R2 での設定例

GX Works3のナビゲーションウインドウのプロジェクトから[パラメータ]-[ユニット情報]-[****:RJ71C24]の「ユニットパラメータ」を マウスダブルクリックし設定シートを表示します。(RJ71C24は、ユニットパラメータに登録されているものとします。) CH1に設定します。交信プロトコル「MCプロトコル(形式4)」、通信速度「9600bps」、動作設定「独立」、データビット「8」、 パリティビット「あり」、奇数/偶数パリティ「奇数」、ストップビット「1」、サムチェックコード「あり」、RUN中書込み「許可」 と設定します。

2.シリアルコミュニケーションユニット QJ71C24N,QJ71C24N-R2 での設定例

GX Works2のナビゲーションウインドウのプロジェクトからインテリジェント機能ユニット「QJ71C24N-R2」の「スイッチ設定」を マウスダブルクリックしスイッチ設定ダイアログを表示します。(QJ71C24N-R2は、インテリジェント機能ユニットに登録されている ものとします。)
CH1に設定します。データビット「8」、パリティビット「あり」、奇数/偶数パリティ「奇数」、ストップビット「1」、 サムチェックコード「あり」、RUN中書込み「許可」、通信速度「9600bps」、交信プロトコル「MCプロトコル(形式4)」 と設定します。

3.QシリーズCPUのRS-232Cシリアルポートでの設定例

GX Works2のナビゲーションウインドウのプロジェクトから PCパラメータ マウスダブルクリックでQパラメータ設定ダイアログを表示します。 シリアルコミュニケーション設定ダブを選択します。
「シリアルコミュニケーション機能を使用する」にチェックを入れます。伝送速度を「9.6kBPS」、サムチェック「あり」にチェックを入れ、 伝送ウエイト時間を「ウエイト無し」、RUN中書込設定を「許可する」にチェックを入れます。

□ 通信プログラムの例

下記サンプルソフトは、レジスタのD0100より10ワード読み込みを行ってます。受信時のサムチェック及び その他のエラー処理は行ってません。「Q」キーで終了します。
プログラム実行は、コンソールウインドウで実行して下さい。ISEでは、エラーとなります。
iQ-Rではコマンドが追加されています。(サブコマンド) 追加されたコマンドではデバイスコードが4バイド、デバイス番号が8バイトとなっています。下記プログラムでは、変数 $iQRExMode で iQ-R 追加コマンド使用ありなしを指定しています。


# C24MC_3C4.pas1
# 三菱PLC シリアル通信 MCプロトコル
# QnA互換3Cフレーム形式4

Set-StrictMode -Version latest

# キー入力
function Keyin{

   $rtkey = $null
   if ([Console]::KeyAvailable){
      $rtkey = [Console]::ReadKey($true)
   }
   return $rtkey
}

# 受信処理
function receive{

   $il = $compt.BytesToRead
   if ($il -gt 0){
      [byte[]] $brbuf = New-Object byte[] $il
      $ir = $compt.Read($brbuf, 0, $il)     # 受信
      for($ip = 0; $ip -lt $ir; $ip++){
         $ba = $brbuf[$ip]
         if ($icstep -eq 1 -and ($ba -eq 0x02 -or $ba -eq 0x15)){ # STX,NAK
            $Script:brcv[$ircvLen] = $ba
            $Script:icstep = 2
            $Script:ircvLen++
         }
         else{
            if ($icstep -eq 2){
               $Script:brcv[$ircvLen] = $ba
               $Script:ircvLen++
               if ($ba -eq 0x0a){      # LF
                  $Script:icstep = 3
                  break;
               }
            }
         }
      }
   }
}

# サム値計算
function sumCal([byte[]] $bar){

   $isum = 0
   foreach($ia in $bar){
      $isum += $ia
   }
   $shex = $isum.ToString("X4")
   $Script:basum[0] = [byte]$shex[2]
   $Script:basum[1] = [byte]$shex[3]
}

# メイン
function main{

   switch($Script:irstep){
      1 {$ssa = "F90000FF00" + $srcmd + $srsbcmd + $sdv + $itopad.ToString($dvketa) + $ireadsu.ToString("X4")
         [byte[]] $baa = [System.Text.Encoding]::ASCII.GetBytes($ssa)
         sumCal $baa
         [byte[]] $baSend = $bENQ + $baa + $basum + $bCRLF
         $compt.Write($baSend, 0, $baSend.Length)     # 送信
         $Script:icstep = 1
         $Script:irstep = 2
         $Script:ircvLen = 0
      }
      2 {
         receive
         if ($icstep -eq 3){
            $ik = 0
            if ($sdv.substring(0, 1) -eq "D"){$ik = 4}
            if ($sdv.substring(0, 1) -eq "M"){$ik = 1}
            $sv = ""
            [byte[]] $bar = New-Object byte[] $ik
            for($ip = 0; $ip -lt $Script:ireadsu; $ip++){
               [System.Array]::Copy($Script:brcv, 11 + $ip * $ik, $bar, 0, $ik)
               $sv += [System.Text.Encoding]::ASCII.GetString($bar) + ","
            }
            Write-Host $sv
            $Script:irstep = 1
            $Script:icstep = 0
         }
      }
   }
}

$iQRExMode = 0       # 1:iQ-R追加モード
$irstep = 1
$icstep = 0
$srcmd = "0401"         # 読み込みコマンド

# Dデバイス読み込み
if ($iQRExMode -eq 0){  # 通常
   $srsbcmd = "0000"    # サブコマンド
   $sdv = "D*"          # Dデバイス(デバイスコード)
   $dvketa = "D6"       # デバイス桁
}
else{    # iQ-R追加拡張
   $srsbcmd = "0002"    # サブコマンド
   $sdv = "D***"        # Dデバイス(デバイスコード)
   $dvketa = "D8"       # デバイス桁
}
$itopad = 100           # 読み込み先頭
$ireadsu = 10           # 読み込み個数

# Mデバイス読み込み
<#if ($iQRExMode -eq 0){ # 通常
   $srsbcmd = "0001"    # サブコマンド
   $sdv = "M*"          # Mデバイス(デバイスコード)
   $dvketa = "D6"       # デバイス桁
}
else{    # iQ-R追加拡張
   $srsbcmd = "0003"    # サブコマンド
   $sdv = "M***"        # Mデバイス(デバイスコード)
   $dvketa = "D8"       # デバイス桁
}
$itopad = 100           # 読み込み先頭
$ireadsu = 20           # 読み込み個数
#>

if ($iQRExMode -eq 0){
   Write-Host "通常モードで実行"
}
else{
   Write-Host "iQ-R追加拡張モードで実行"
}

[byte[]] $bENQ = @(0x05)
[byte[]] $bCRLF = @(0x0d, 0x0a)

[byte[]] $basum = New-Object byte[] 2
[byte[]] $brcv = New-Object byte[] 512

$ircvLen = 0

$compt = New-Object System.IO.Ports.SerialPort "COM3", 9600
$compt.DataBits = 8
$compt.Parity = [System.IO.Ports.Parity]::Odd
$compt.StopBits = [System.IO.Ports.StopBits]::One
$compt.DtrEnable = $true
$compt.RtsEnable = $true

try{
   $compt.Open()
}
catch{
   Write-Host("COMポートOpen失敗")
   exit
}
Write-Host("COMポートopen")

while($true){
   main
   $inkey = Keyin
   if ($inkey -ne $null -and $inkey.Key -eq "Q"){
      break;
   }
   Start-Sleep -m 50
}
$compt.Close()
Write-Host("COMポートclose")


   
参考資料
・MELSECコミュニケーションプロトコルリファレンスマニュアル(三菱電機(株))
PowerShellメモ
©2021-2022 TEXCELL CORPORATION
テクセル株式会社