【実践プログラミング編:第9回】
本連載では、FA現場で戦うための実務特化型プログラミングを解説します。
- 「品種が50種類に増え、BMOV命令を50行もコピペしてラダーが画面から溢れている」
- 「先輩が組んだラダーに『D100Z1』という見慣れない記号があり、どこにデータが入っているのか追えない」
- 「Zレジスタを使った回路を改造したら、突然PLCがエラー停止してラインが止まった」
- 「Zレジスタを使った回路を改造したら、全く関係ない場所のデータが勝手に書き換わって設備が誤動作した」
同じような回路を何十行も並べる力技の設計は、修正漏れによるバグを生むだけでなく、プログラムの可読性を著しく低下させます。一方で、仕組みを理解しないまま見よう見まねで「Zレジスタ」に手を出すと、意図しないメモリ領域を次々と破壊する大事故を引き起こします。
実務で数多くの制御盤・PLC設計を手掛けてきた筆者が、中級者への壁を突破する「インデックス修飾(Zレジスタ)の鉄則」を伝授します。この記事を読めば、100行のラダーをたった1行に圧縮しつつ、暴走リスクを抑えた堅牢なプログラムが組めるようになります。
結論として、インデックス修飾は「ベースアドレス+Zの中身」で対象デバイスを動的に変化させる機能であり、実務では必ず「Zの上限・下限リミット回路」とセットで使うのが基本です。
なぜなら、Zレジスタの数値が計算ミスで暴走すると「設備の重要パラメータを次々と破壊し、最悪の場合PLCが演算エラーで即停止する致命的な罠」が待っているからです。魔法の杖を安全に使いこなす具体的な設計作法を順番に見ていきましょう。
【本連載の前提】
本記事内のプログラム例や命令語は、国内FA業界で最もシェアの高い「三菱電機製PLC(MELSEC)」をベースに解説しています。しかし、ここで解説する「なぜその命令が必要なのか」「現場でどう使うのか」という設計思想は、オムロンやキーエンスなど、すべてのメーカーのPLCで共通して使える普遍的な技術です。メーカーの違いを恐れず、本質的な「設計の根幹」を身につけてください。
インデックス修飾(Zレジスタ)とは?基本の仕組み
インデックス修飾とは、データレジスタ(D)や内部リレー(M)などのデバイス番号の後ろに Z0 〜 Z15(インデックスレジスタ) をくっつけることで、「参照するアドレスの位置を、Zの中身の数値分だけズラす(オフセットする)」機能です。

アドレスが変化する「足し算」のルール
仕組みは驚くほどシンプルで、ただの「足し算」です。
- 書式:
D100Z0と記述した場合- 実際に参照されるアドレス =
D(100 + Z0の中身)
- 実際に参照されるアドレス =
つまり、Z0 という箱の中にどんな数値が入っているかによって、D100Z0 が指し示す実際の場所が以下のように自動で切り替わります。
Z0 = 0のとき:D(100 + 0)=D100を参照するZ0 = 5のとき:D(100 + 5)=D105を参照するZ0 = 100のとき:D(100 + 100)=D200を参照するZ0 = -10のとき:D(100 - 10)=D90を参照する(※マイナス方向にもズレる)
なぜインデックス修飾を使うのか?
最大のメリットは、「同じ構造の繰り返し回路を、たった1行にまとめられること」です。
例えば、100品種分のレシピ転送を組む場合、通常の書き方では品種1〜100の分岐接点と BMOV 命令を100行並べる必要があります。しかし、インデックス修飾を使えば、品種番号に応じて Z0 の数値を変えるだけで、転送命令自体は [BMOV D1000Z0 D200 K10] のたった1行 で完結します。
まずは「インデックス修飾とは、デバイス番号にZの中身を足し算して、アクセス先を自在にスライドさせる仕組みである」と押さえてください。
100行が1行に縮む!品種レシピ切り替えの実践回路
前回の第8回で解説した「1品種あたり10ワード枠のレシピ転送」を、インデックス修飾を使って1行に圧縮する実践回路を見ていきましょう。
1品種あたりのブロック設計や BMOV / FMOV の基本については、前回の『【第8回】PLCのBMOVとFMOVの決定的な違い!レシピ管理と一括初期化の鉄則(https://yada-blog.com/plc-bmov-fmov/3609/)』で詳しく解説しています。

メモリマップの前提条件
- 実動作エリア:
D200 〜 D209(10ワード) - 品種1 マスター:
D1000 〜 D1009(先頭D1000= 基準から+0) - 品種2 マスター:
D1010 〜 D1019(先頭D1010= 基準から+10) - 品種3 マスター:
D1020 〜 D1029(先頭D1020= 基準から+20) - 以降、品種100(
D1990 〜 D1999)まで10ワード刻みで配置。
オフセット量(Zの中身)の計算式
タッチパネルで入力された「品種番号(D0:1〜100)」から、どれくらいアドレスをズラせばよいか(Z0 に入れる値)を計算します。
品種1のときにズレ量を 0、品種2のときに 10、品種3のときに 20 にしたいので、計算式は以下のようになります。
- オフセット計算式:
(品種番号 - 1)× 10ワード
実装ラダー回路
レシピ展開ボタン(M50)が押された瞬間に、上記の計算とブロック転送を一気に実行します。
// ① 品種番号(D0)から「1」を引いて作業用D10へ格納(品種1を「0」起点にする)
M50(レシピ展開指令)
───[ ↑ ]───────────────────────[ - D0 K1 D10 ]
// ② 1品種あたりの枠サイズ「10」を掛けて、結果をD12(32bit)へ格納
M50
───[ ↑ ]───────────────────────[ * D10 K10 D12 ]
// ③ 計算結果(オフセット量)をインデックスレジスタ Z0 へセット
M50
───[ ↑ ]───────────────────────[ MOV D12 Z0 ]
// ④ 算出された先頭アドレス(D1000 + Z0)から10ワード分を実動作エリアへ一括コピー!
M50
───[ ↑ ]───────────────────────[ BMOV D1000Z0 D200 K10 ]
💡 掛け算(
*)の32ビット仕様に注意!
第6回・第7回で学んだ通り、16ビットの掛け算命令[ * D10 K10 D12 ]の結果はD12とD13の2ワード(32ビット) に格納されます。今回の計算結果(最大990)は16ビットの範囲内(32,767以下)に収まるため、下位ワードであるD12をそのままMOVでZ0に移して問題ありませんが、D13も裏で使用されている点は忘れないでください。
この4行を書いておくだけで、品種が50個に増えようが100個に増えようが、ラダーを1行も追加することなく全ての品種切り替えに対応できます。
このように、「(番号 − 1)× ブロックサイズ でオフセット量を計算し、Zレジスタへ入れてBMOVで抜く」のが、現場におけるデータテーブル処理の王道パターンです。
現場で起きる3大惨事(インデックス修飾の罠)
インデックス修飾は劇的にラダーを短縮できる反面、バグが起きたときの破壊力は通常の命令の比ではありません。新人が現場で引き起こす代表的な3つの惨事を知っておきましょう。
罠① 加算のパルス化忘れによる「青天井の暴走とCPU停止」
最も恐ろしいのが、ロギング(履歴保存)などでデータを順番に記録しようとして、Zレジスタへの加算(+ や INC)を常時実行してしまうミスです。
M20(記録トリガ)
───[ ]───────────────────────[ + K10 Z0 ] ←NG!毎スキャン+10され続ける
もし M20 が0.5秒間ONし続けただけで、Z0 の値は1スキャンごとに +10、+20、+30… と猛烈な勢いで跳ね上がります。
その直後に [MOV D50 D1000Z0] のような書き込み命令があると、D1000 から始まり D2000、D5000…と、PLC内のあらゆるデータレジスタをマシンガンのように次々と上書き破壊しながら暴走します。
さらに厄介なことに、GX Works2のシミュレータ等で確認すると分かりますが、インデックス修飾で入力可能な D レジスタの最大番号(例:D22527)を超える値を Z0 に入れても、条件や設定によってはエラー停止すら起きず、そのままPLCが動き続けてしまうケースがあります。
ウォッチウィンドウや使用デバイスリストで確認すらできない範囲外へアクセスしてしまうため、何が起きているか把握できない危険な状態に陥ります(※実際に上限を超えた際に内部メモリ上でどこへ書き込まれるかや、エラー停止するかどうかはCPUの機種やパラメータ設定によって挙動が異なるため、上限を超える値自体を発生させない設計が不可欠です)。
罠② 品種番号「0」入力による「マイナス方向へのメモリ破壊」
先ほどのレシピ回路で、もし作業者がタッチパネルにまだ品種番号を入力しておらず、D0(品種番号)が 0(初期値) のまま展開ボタンを押したらどうなるでしょうか?
計算式 (品種番号 - 1)× 10 に当てはめると、(0 - 1)× 10 = -10 となり、Z0 には -10 が入ります。
すると、D1000Z0 は D(1000 - 10) = D990 に化けます。結果として、マスター領域の手前にある D990〜D999 の無関係なデータをレシピとして読み込んでしまい、設備がデタラメな速度や位置へ暴走します。書き込み命令だった場合は、手前のメモリ領域を上書きして破壊してしまいます。
罠③ 同じZレジスタ(Z0)の使い回しによる「値の先祖返り」
インデックスレジスタ Z0 は、プログラム全体で共有される「1つの箱」です。
回路Aで Z0 に 100 を入れて使っている最中に、別の回路Bでもうっかり同じ Z0 に 0 を書き込んでしまうと、回路Aに戻ったときにアドレスがズレて誤動作します。
これを防ぐためには、以下のいずれかのルールを徹底する必要があります。
- 機能ごとに使うZ番号を分ける(レシピ用は
Z0、異常履歴用はZ1、通信用はZ2など)。 - 使う直前の行で毎回必ず
Zに値をセット(MOV)してから、すぐ次の行でインデックス修飾を実行する(スキャンをまたいでZの値を保持する前提で組まない)。
つまり、「Zレジスタは一歩間違えるとメモリ破壊や引き起こす劇薬である」と肝に銘じて設計する必要があります。
暴走を100%防ぐ「上限・下限リミット回路」の鉄則
前章で見た「マイナス方向へのズレ」や「「想定外の領域へのアクセス」を確実に防ぐため、実務でインデックス修飾を使う際は、必ず「入り口(番号)」または「出口(Zの値)」にリミット(ガード)をかけるのが鉄則です。
実践!安全ガード付きのレシピ展開ラダー
品種番号(D0)が 「1以上、かつ、100以下」の正常な範囲に入っているときだけ、Zの計算と転送を許可するインターロックを組み込みます。
比較命令(>=、<=)の使い方は、『【第6回】数値を支配する比較命令(CMP・接点)と四則演算〜ヒステリシスで設備を守る〜』で解説した通りです。
// 品種番号(D0)が「1以上」かつ「100以下」のときだけ M51(品種番号正常)をON
───[>= D0 K1]─────[<= D0 K100]──────────────────( M51:品種番号正常 )
// M51(正常範囲内)がONしているときだけ、レシピ展開を実行する
M50(展開指令) M51(正常)
───[ ↑ ]───────────[ ]───────┬───────────────[ - D0 K1 D10 ]
├───────────────[ * D10 K10 D12 ]
├───────────────[ MOV D12 Z0 ]
└───────────────[ BMOV D1000Z0 D200 K10 ]
このガード回路が防ぐ2つの事故
- 下限ガード(
>= D0 K1): 品種番号が0やマイナス値のときは実行されないため、Z0がマイナスになってD1000より手前のメモリ(D990など)を誤参照・破壊するトラブルを防げます。 - 上限ガード(
<= D0 K100): 万が一タッチパネルの入力ミスや通信バグでD0に9999のような異常値が入っても実行がブロックされるため、マスター領域(D1999)を飛び出して別領域を破壊するトラブルを防げます。
現場でインデックス修飾を使うなら、「Zを動かす前には、必ず比較命令で上限・下限の範囲チェック(インターロック)を入れる」というルールを自身の設計標準に組み込んでください。
まとめ & 次回予告
インデックス修飾(Zレジスタ)は、初級者の「コピペラダー」から脱却し、プロフェッショナルな「データ駆動型ラダー」へと進化するためのスキルです。
- インデックス修飾の本質:
D100Z0=D(100 + Z0の中身)。ベースアドレスにZの値を足し算して参照先をスライドさせる機能。 - ブロック処理との組み合わせ:
(番号 − 1)× 枠サイズでオフセット量を計算してZに入れれば、100品種のBMOVもたった1行に圧縮できる。 - Zの直前セット原則:他の回路と
Zが競合してバグるのを防ぐため、インデックス修飾を使う直前の行で毎回Zに値をセットする。 - 絶対の安全対策:加算暴走によるメモリ破壊や範囲外アクセスを防ぐため、必ず上限・下限の比較インターロック(リミット回路)とセットで組む。
まずは手元のテスト環境で Z0 の数値を変えながら、モニタ画面で D100Z0 の中身がどう切り替わるかを実際に体験してみてください。
次回予告
今回は、インデックス修飾(Zレジスタ)を使って大量のレシピデータを1行で扱う方法と、暴走を防ぐリミット回路を解説しました。
ここまで「整数(-32,768〜+32,767等)」を使ったデータ処理を学んできましたが、先輩が組んだラダーを開くと [FLT D100 D200] や [DE* D200 E1.25 D202]、[EMOV] といった見慣れない「E」や「FLT」の命令が並んでいることがあります。
これは、整数の割り算では消えてしまう「小数点以下の数値(0.01mmや1.5倍など)」を正確に計算するための「実数(浮動小数点)命令」です。
次回は、メカのパルス換算やセンサー値の計算を読むために欠かせない、【第10回】PLCの実数(浮動小数点)演算とは?FLT・EMOVの使い方と割り算の罠 をお届けします。整数と実数が混ざる際のデータ化けを防ぐ鉄則を解説しますので、ぜひ続けてご覧ください!
※本記事で使用している画面は、三菱電機株式会社「GX Works2」の操作画面です。
※GX Works2、MELSECは、三菱電機株式会社の登録商標です。
※本記事で紹介しているプログラムや回路図は、技術解説のためのサンプルです。実機での動作を保証するものではありません。
※実際に使用する際は、十分な検証を行った上で、安全に配慮して運用してください。