【実践プログラミング編:第7回】
本連載では、FA現場で戦うための実務特化型プログラミングを解説します。
- 「サーボの目標位置を転送したら、いきなりマイナス方向へ暴走した」
- 「タッチパネルから設定値を変更しても、一瞬で元の数値に戻ってしまう」
- 「プログラムを修正していないのに、隣のDレジスタのタイマ設定値が勝手に狂う」
MOV命令はデータを運ぶだけの単純な命令ですが、仕様の勘違いから設備を暴走させる事故が起こりえます。放置すれば深夜のデバッグ地獄や機械破損に直結します。
実務で数多くの制御盤・PLC設計を手掛けてきた筆者が、現場で泣かないための「MOV/DMOV命令の鉄則」を伝授します。この記事を読めば、データの型やメモリ領域を意識したバグのない堅牢なラダーが組めるようになります。
結論として、16ビット整数はMOV、32,767を超える大きな数値はDMOVを使い、かつ一括設定時はパルス化(MOVP)するのが鉄則です。
ただし、ただDMOVへ置き換えるだけでは「隣のメモリを勝手に破壊する致命的な落とし穴」にハマります。現場で冷や汗をかかないための具体的な防衛策を順番に見ていきましょう。
【本連載の前提】
本記事内のプログラム例や命令語は、国内FA業界で最もシェアの高い「三菱電機製PLC(MELSEC)」をベースに解説しています。しかし、ここで解説する「なぜその命令が必要なのか」「現場でどう使うのか」という設計思想は、オムロンやキーエンスなど、すべてのメーカーのPLCで共通して使える普遍的な技術です。メーカーの違いを恐れず、本質的な「設計の根幹」を身につけてください。
MOV命令の正体は「移動」ではなく「上書きコピー」

MOV命令を学ぶ上で最初に押さえるべき事実は、英語の「Move(移動)」という名称に反して、実際の動作は「上書きコピー(複製)」であるという点です。
基本書式とデータの残り方
三菱電機MELSEC(GX Works2/3)における基本書式は以下の通りです。
- 書式:
[MOV S D]- S(転送元):コピー元のデータレジスタや定数(例:
D100、K10) - D(転送先):コピー先のデータレジスタ(例:
D200)
- S(転送元):コピー元のデータレジスタや定数(例:
例えば [MOV D100 D200] を実行すると、D100 の中身が D200 へコピーされます。このとき、転送元である D100 の数値は消えずにそのまま残ります。一方で、転送先である D200 に元々入っていた古い数値は、新しい数値によって上書きされます。
また、転送元(S)によく使う定数の記号も確実に暗記してください。
- K(10進数定数):
K100と書けば「100」を転送する。人間の直感と同じ数値。 - H(16進数定数):
H10と書けば16進数の10(10進数の「16」)を転送する。通信コマンドやビットパターンの指定で使用する。
まずは「MOV命令は転送元を消さずに、転送先を上書きするコピー命令である」と認識してください。
常時実行(MOV)とパルス実行(MOVP)の明確な使い分け

実務1年目の設計者が頻繁に起こすトラブルが、「常時実行(MOV)」と「パルス実行(MOVP)」の選択ミスです。
パルス化忘れが招く「設定値が変更できない」怪現象
例えば、設備の起動時に初期値として速度データ「100」を D200 へセットするため、自動運転中ずっとONする接点の後ろに [MOV K100 D200] と書いたとします。
PLCは1秒間に何百回という猛スピード(スキャンタイム)でラダーを繰り返し実行しています。そのため、MOV を使うと毎スキャン執拗に「100」を上書きし続けます。
この状態で現場の作業者がタッチパネルから D200 の速度を「120」に微調整しても、0.01秒後の次スキャンでPLCが「100」に書き戻してしまいます。
現場における使い分けの基準
2つの命令は、用途に応じて以下のように明確に使い分けます。
- 常時実行(
MOV)を使う場面:- センサーの現在値やタイマの経過時間を、表示用レジスタへリアルタイムに反映し続けたいとき。
- ワークの現在位置など、常に最新の値で上書きし続ける必要があるとき。
- パルス実行(
MOVP)を使う場面:- 品種切り替え時や初期化時に、設定値を「1回だけ」セットしたいとき。
- 異常が発生した瞬間のエラーコードや現在位置を、履歴としてラッチ(保持)したいとき。
- ステートマシン(歩進制御)で、次の工程番号へ更新するとき。
MOVPを活用した実践的な歩進制御の作り方は、『【第5回】自己保持の地獄から脱却!Dレジスタで作るステートマシン歩進制御の型』で詳しく解説しています。
つまり、「後からタッチパネルや別回路で書き換える可能性があるレジスタには、パルス実行(MOVP)を使う」のが現場の鉄則です。
【最大の罠】16ビット(MOV)と32ビット(DMOV)の境界線
MOV命令において最も凶悪なバグを生むのが、「16ビット(1ワード)」と「32ビット(2ワード)」のデータ型の壁です。ここを理解していないと、設備を物理的に破壊する重大事故を引き起こします。
罠① 「32,767の壁」によるマイナス暴走事故
PLCの通常のデータレジスタ(D)は、1個あたり「16ビット(符号付き整数)」の器を持っています。この16ビットの器で表現できる数値の範囲は、-32,768 〜 +32,767 までと決まっています。
そのため、例えばサーボモータの目標座標として「40,000 パルス」をセットしようと [MOV K40000 D500] と入力すると、GX Works上で以下のエラーが表示されます。

「デバイスの設定に誤りがあります」と弾かれる原因は、16ビット命令である MOV に対して上限(32,767)を超える定数を指定したためです。
しかし、本当に恐ろしいのはここからです。
定数(K)を直接書くときはソフトがエラーで止めてくれますが、「データレジスタ同士の転送([MOV D100 D200])」ではエラーが出ず、素通りしてしまうのです。
例えば、以下のような現場あるあるの状況を想像してください。
- タッチパネルの数値入力(32ビット設定)や掛け算(
*)の結果として、D100(およびD101)に目標座標「40,000」が入っている。 - この値を実動作エリアの
D200へ移そうとして、うっかり通常の16ビット命令で[MOVP D100 D200]と書いてしまった。
この瞬間、PLCは 40,000 というデータのうち、下位16ビット(D100単体)だけを無理やり切り取って転送します。16ビットの上限である 32,767 を超えた領域のデータは、2進数の最上位ビット(符号ビット)が「1(マイナス)」として解釈されるため、転送先の D200 の中身が -25,536 というマイナス値に化けてしまいます。
その結果、プラス方向へ進むはずのサーボモータが猛スピードでマイナス方向(原点側)へ逆走し、メカストッパーに激突する重大事故を引き起こします。
解決策:32,767を超える数値は「DMOV(32ビット命令)」を使う
数万〜数億といった大きな数値を扱う場合は、命令の先頭に「D(Double)」を付けた DMOV(または DMOVP) を使用します。
- MOV(16ビット転送):扱える範囲は
-32,768 〜 +32,767 - DMOV(32ビット転送):扱える範囲は
-2,147,483,648 〜 +2,147,483,647(約21億)
サーボの位置データ、累積の生産数カウンタ、長時間のタイマ演算など、少しでも「3万」を超える可能性があるデータはすべて32ビット(DMOV)で統一するのが基本です。
罠② 裏でこっそり2ワード食う!「隣接レジスタ破壊」の惨劇

「じゃあ、全部 DMOV にしておけば安心ですね!」と考えるのが1年目の罠です。ここに、初心者が必ず一度は踏む「2ワード占有(隣接メモリ破壊)」の落とし穴があります。
D レジスタ1個には16ビットしか入りません。そのため、32ビットのデータを扱う [DMOVP K100000 D100] という命令を実行すると、PLCは指定された D100 だけでなく、隣の D101 までを自動的に連結して「2個イチ(D100+D101)」としてデータを格納します。
ラダー図の画面上には D100 としか表示されないため、設計者自身が「D101 も使われている」という事実に気づきにくいのが最大の恐怖です。
もし D101 が空いていると勘違いして、別の回路で [MOVP K50 D101](シリンダ遅延タイマ5.0秒の設定など)と書いてしまったらどうなるでしょうか?
D100の32ビットデータの上位ビットがD101の値で破壊され、サーボの目標位置が数百万パルスという異常値に跳ね上がる。- 逆に
DMOVが実行された瞬間、D101のタイマ設定値が上書きされて消滅する。
このように、デバイスの重複使用は原因特定が極めて困難なバグを生みます。
32ビット命令(DMOV、D+、D* など)を使う際は、裏で2ワード占有する仕組みを頭に入れ、32ビットを扱うエリアは最初から「偶数番号(D100、D102、D104…)」のように1つ飛ばしで割り当てるルールを徹底してください。
これだけで隣接データの破壊事故は確実に防げます。
世界が広がる応用技「ビットデバイスの一括転送(桁指定 KnM)」
最後に、第1章で学んだ「ビットデバイス(X, Y, M)」と、第2章の「ワードデバイス(D)」を繋ぐ応用技を紹介します。
MOV命令は D レジスタ同士だけでなく、連続するビット(ON/OFF)を「数値」として一括で転送・クリアすることができます。このときに使うのが 桁指定(K1〜K4) です。
【画像:K4M0の構造図(K1=4ビット単位で、K4M0ならM0〜M15の16個が1ワードとして扱われる図解)】
桁指定(Kn)のルール

ビットデバイスの先頭に K1〜K4 を付けると、「1桁=4ビット分」として複数のビットをひとまとめの塊(ワードデータ)として扱えます。
K1M0:M0 〜 M3の 4ビット分K2M0:M0 〜 M7の 8ビット分K4M0:M0 〜 M15の 16ビット分(1ワードと同じサイズ!)
現場で多用する2つの定番パターン
① 複数の異常ビットや出力を一撃で全OFF(リセット)する
異常解除ボタンを押したとき、M100 から M115 までの16個の異常保持ビットをすべてOFFしたいとします。RST 命令を16行並べる必要はありません。
X10(異常リセット)
───[ ↑ ]───────────────────────[ MOVP K0 K4M100 ]
このように書けば、M100 〜 M115 の16ビットすべてに「0」が転送され、たった1行で16個のコイルを一括リセットできます。非常停止時の出力一括遮断([MOV K0 K2Y0] など)でも大活躍するテクニックです。
② ビットのON/OFF状態をタッチパネル表示用や通信用にDレジスタへ格納する
SM400(常時ON)
───[ ]───────────────────────[ MOV K4X0 D50 ]
この回路は、入力 X0 〜 X1F(16点分)のON/OFF状態をそのまま D50 の各ビットへ丸ごとコピーします。上位システムとの通信でIO状態をまとめて送りたいときや、どのセンサーが反応したかを一括監視したいときに重宝します。
ビットとワードを自在に行き来できるようになれば、ラダー設計の自由度は一気に跳ね上がります。
まとめ & 次回予告
たかがMOV命令と侮らず、データの「実行タイミング」と「器のサイズ(ビット数)」を正確に支配することが、バグのない美しいプログラムへの第一歩です。
- MOVの本質:移動ではなく「上書きコピー」。転送元のデータは消えない。
- パルス化の鉄則:設定値のセットや歩進番号の更新には、毎スキャン上書きを防ぐ
MOVP(パルス実行) を使う。 - 32ビットの境界線:
32,767を超える数値はDMOVを使う。ただし裏で隣のレジスタまで2ワード分(D100+D101)を占有するため、必ず1つ飛ばし(偶数アドレス等)で割り当てる。 - ビット一括処理:
[MOVP K0 K4M0]を使えば、16点分のビットを1行で一括クリアできる。
まずはご自身の組んでいるラダーを見直し、「DMOV の隣りのアドレスを誤って使っていないか」「必要な箇所が MOVP になっているか」を点検してみてください。
次回予告
今回は1点のデータ(16ビット/32ビット)を確実に運ぶ方法をマスターしました。
しかし、実際の生産設備では「品種Aのレシピデータ(速度、圧力、温度、タイマ値など計20個)」をまとめて切り替えたい場面が必ず出てきます。このとき、MOVP を20行ズラズラと並べて書いてはいけません。
次回は、連続する大量のデータをたった1行で一括コピー・一括初期化するプロの必須スキル、【第8回】1点ずつMOVするな!BMOVとFMOVで組む「レシピ管理」と「一括リセット」の鉄則 をお届けします。プログラムの行数を劇的に減らすブロック転送の極意を解説しますので、ぜひお楽しみに!
※本記事で使用している画面は、三菱電機株式会社「GX Works2」の操作画面です。
※GX Works2、MELSECは、三菱電機株式会社の登録商標です。
※本記事で紹介しているプログラムや回路図は、技術解説のためのサンプルです。実機での動作を保証するものではありません。
※実際に使用する際は、十分な検証を行った上で、安全に配慮して運用してください。