【GX Works3】四則演算命令の使い方|+ - * /・32bit・INC/DEC・WANDマスク処理まで総まとめ
概要
D0やD10といったワードデバイスには、A/D変換した生の測定値や、良品数・不良品数のカウント値がそのまま入ってきます。これらを「良品数と不良数を足して総生産数を出す」「A/D値を換算係数で割って物理量に直す」というように、数値として計算してから次の判断に使う場面は、シーケンス制御では珍しくありません。ビットのON/OFFの組み合わせだけでは表現できない、この「数値そのものを計算する」部分を担うのが四則演算命令です。まずは現場でよくある場面と、対応する命令の対応表から見ていきます。
| やりたいこと | 使う命令 |
|---|---|
| 生産数・通過数を数えたい | INCP(±1するだけなら加算より簡単) |
| 2つの値の合計・差分がほしい | +P / -P |
| 掛け算・割り算(スケーリング等) | *P / /P(格納先の広がりに注意) |
| 32767を超える大きな値を扱う | D+P / D-P / D*P / D/P(32bit版) |
| ワードから特定ビットだけ取り出す・立てる | WANDP / WORP(マスク処理) |
16bit四則演算(+ / - / * / /)
書式
出典: MELSEC iQ-R プログラミングマニュアル(CPUユニット用命令/汎用FUN/汎用FB編)SH-081226 / ops/refs/instructions/05_arithmetic.md より転記。
| 命令記号 | 実行条件 | 主なオペランド/データ型 | 動作 |
|---|---|---|---|
+ / +P | 常時実行/立上り | (s1)(s2)(d) 符号付きBIN16/ANY16_S | 加算(2オペランド/3オペランド形式) |
- / -P | 常時実行/立上り | (s1)(s2)(d) | 減算 |
* / *P | 常時実行/立上り | (s1)(s2)(d) | 乗算。16bit×16bit=32bit(d下位・d+1上位) |
/ / /P | 常時実行/立上り | (s1)(s2)(d) | 除算。商はd、余りはd+1に格納 |
範囲 -32768〜32767(符号なし版_Uは0〜65535)。0除算はエラー(エラーコード3400H・SD0に格納)。オーバーフロー時は桁上げ無視・SM700(キャリフラグ)はONしない。
動作
動作の基本は3オペランド形式です。+P D0 D1 D2のように(s1)(s2)(d)を並べて書くと、D0とD1という2つの値はそのまま残り、答えだけがD2という別デバイスに出てきます。「何と何を足して、どこに入るか」が一目で分かるので、まずはこの形で書くのが基本になります。もう一つ(s)(d)の2オペランド形式もあり、こちらは(d)自身に(s)を加算して(d)へ上書きする書き方です。オペランドが1つ減るぶん短く書けますが、元のD0の値が演算後には残らないので、後から「元の値も見たい」場面には向きません。乗算(*P)は16bit×16bit=32bitとなるため、結果は(d)の下位16bitと(d)+1の上位16bitの2ワードに分かれて格納されます。除算(/P)は商が(d)に、余りが(d)+1に入り、除数が0のときはエラー(3400H)になります。
サンプルコード
①+Pで良品数と不良数の合計を出す
[X0 +P D0 D1 D2 ]
D0に良品数(例:145)、D1に不良数(例:5)が入っているとして、X0の立上りでD0とD1を加算し、総生産数150をD2へ格納します。生産実績を集計する画面や上位システムへ渡す値として、良品数と不良数を別々のカウンタで数えつつ、合計だけをまとめて出したいときの基本形です。
②/Pで総秒数を分と秒に分解する
[X0 /P D0 K60 D2 ]
D0に経過時間の総秒数(例:125秒)が入っているとして、X0の立上りでD0を定数K60で割ります。商である2がD2(分)に、余りである5がD3(秒)に自動で格納され、125秒=2分5秒として画面表示に使える形になります。商のD2しかラダーには書きませんが、余りのD3も予約されていることを忘れずにデバイス表へ書き留めておきましょう。
32bit四則演算(D+ / D- / D* / D/)
書式
出典: MELSEC iQ-R プログラミングマニュアル(CPUユニット用命令/汎用FUN/汎用FB編)SH-081226 / ops/refs/instructions/05_arithmetic.md より転記。
| 命令記号 | 実行条件 | 主なオペランド/データ型 | 動作 |
|---|---|---|---|
D+ / D+P | 常時実行/立上り | (s1)(s2)(d) 符号付きBIN32/ANY32_S | 32ビット加算 |
D- / D-P | 常時実行/立上り | (s1)(s2)(d) | 32ビット減算 |
D* / D*P | 常時実行/立上り | (s1)(s2)(d) | 32ビット乗算。32bit×32bit=64bit((d)〜(d)+3の4ワード) |
D/ / D/P | 常時実行/立上り | (s1)(s2)(d) | 32ビット除算。商→下位32bit((d),(d)+1)、余り→上位32bit((d)+2,(d)+3) |
範囲 -2147483648〜2147483647(符号なし版_Uは0〜4294967295)。各オペランドはデバイス2点をペアで使用。0除算はエラー(3400H)。
動作
生産数の累計のように、16bitの範囲(-32768〜32767)をいずれ超えることが分かっている値は、最初から32bit版で組んでおくのが安全です。オペランドの書き方は16bit版と同じくD0のように1つのデバイス番号を書くだけですが、D付き命令はすべて2点をペアで使用するため、D0を指定した時点でD0とD1の2ワードがまとめて予約されます。掛け算のD*はさらに結果が64bit幅になるため、(d)から(d)+3までの4ワードに広がります。割り算のD/は商が下位32bit((d)、(d)+1)、余りが上位32bit((d)+2、(d)+3)というように、商と余りがそれぞれ2ワードずつを使う点も16bit版の/Pと配置が違うので注意してください。実務でとくに気をつけたいのが、この「2点で1組」というデバイスの重なりです。D0を32bit演算に使うと決めた時点で、D1はもう別の用途には使えません。デバイス一覧表を作るときは、32bit演算で使うデバイスは最初から2個1組で予約しておくと事故を防げます。
INC / DEC(±1演算)
書式
出典: MELSEC iQ-R プログラミングマニュアル(CPUユニット用命令/汎用FUN/汎用FB編)SH-081226 / ops/refs/instructions/05_arithmetic.md より転記。
| 命令記号 | 実行条件 | 主なオペランド/データ型 | 動作 |
|---|---|---|---|
INC / INCP | 常時実行/立上り | (d) 符号付きBIN16/ANY16 | BIN16データを+1 |
DEC / DECP | 常時実行/立上り | (d) | BIN16データを-1 |
DINC / DDEC | 常時実行/立上り | (d) 符号付きBIN32 | 32ビットの+1/-1 |
キャリフラグには影響しない。32767のときINC(P)を実行すると-32768になる(符号付き指定時)。立上り(P)で1回ずつカウントするのが定番。
動作
動作はシンプルで、(d)で指定したデバイスの値を実行のたびに+1(INC)または-1(DEC)するだけです。ここで外せないのが、必ずP付き(INCP/DECP)で使うという点です。P無しのINCを常時ON条件でつないでしまうと、実行条件が成立している間は毎スキャンD0が+1され続け、狙った回数どころか一瞬で桁あふれまで暴走します。図4・図5のようにX0・X1の立上りに合わせて1パルスごとに実行するのが、INC/DECの基本の使い方です。もう一つ押さえておきたいのが、上限・下限に達したときの回り込みです。マニュアルには、D0の内容が32767のときにINC(P)を実行すると-32768が格納される、と明記されています。カウントアップを続けていると、桁あふれのエラーにもならないまま静かに符号が反転するので、上限に近い値を扱う設計では意識しておく必要があります(DEC(P)側も同様に-32768から32767へ回り込みます)。
INCPとカウンタC、どっち?
「数を数える」だけならカウンタC(OUT C)でも同じことができるため、どちらを使うか迷う場面が出てきます。あくまで実務上の目安ですが、設定値に到達した瞬間にON接点として使いたい・リセット入力で現在値を管理したい、という用途はカウンタCの方が素直です。カウンタは接点そのものが「設定値到達」を表してくれるので、比較接点を別に組む必要がありません。一方、数値としてそのまま演算・表示・転送に使いたいだけなら、INCPでDレジスタを直接+1していく方が回路がシンプルになります。「接点として使いたいか、数値として使いたいか」で選ぶのが実務上の目安です。
ワード論理演算(WAND / WOR / WXOR / WXNR)
書式
出典: MELSEC iQ-R プログラミングマニュアル(CPUユニット用命令/汎用FUN/汎用FB編)SH-081226 / ops/refs/instructions/06_logical-bit.md より転記。
| 命令記号 | 実行条件 | 主なオペランド/データ型 | 動作 |
|---|---|---|---|
WAND / WANDP | 常時実行/立上り | (s1)(s2)(d) 符号付きBIN16/ANY16 | 16ビット論理積(AND)。ビットマスク(クリア) |
WOR / WORP | 常時実行/立上り | (s1)(s2)(d) | 16ビット論理和(OR)。特定ビットをON |
WXOR / WXORP | 常時実行/立上り | (s1)(s2)(d) | 16ビット排他的論理和(XOR)。ビット反転 |
WXNR / WXNRP | 常時実行/立上り | (s1)(s2)(d) | 16ビット否定排他的論理和(XNOR) |
範囲 -32768〜32767。32bit版は先頭にD(DAND/DOR/DXOR)。マスク値はH(16進)で指定すると分かりやすい。
動作
WAND・WOR・WXORはいずれも16bitデータをビットごとに演算する命令で、算術演算のように数値としての大小を扱うわけではありません。よく使うのは、複数のビット情報がまとめて入っている1ワードから、必要なビットだけを取り出したり書き換えたりする場面です。WANDは特定ビットだけを残して残りを強制的に0にする「マスク」処理に向いていて、図6のようにWANDP D0 H00FF D1と書けば、D0の下位8bitだけをそのままD1に残し、上位8bitは問答無用で0になります。WORは逆に、特定ビットだけを強制的に1にしたい場合に使い、他のビットに影響を与えずフラグ用のビットを立てたいときの定番です。WXORは同じビット同士なら0、違えば1になる性質を利用して、値が変化したかどうかの検出や、特定ビットだけを反転させる用途に使われます。マスク値をH00FFのように16進数(H指定)で書くと、2進数の並びがそのまま透けて見えるため、K(10進)で書くよりもどのビットを操作しているかが一目で分かります。
よくある誤解
①Pなしの演算命令を常時ON条件で書いてしまう
+やD+など、P無しの演算命令は実行条件がONの間ずっと毎スキャン実行されます。常時ON条件のままうっかり+ D0 D1をつないでしまうと、1スキャンごとにD1がD0に加算され続け、狙った1回の計算どころか値が際限なく膨らんでいきます。演算命令は基本的に立上り実行(+P、D+Pなど)で使い、P無しの形は「意図的に毎スキャン計算し続けたい」特殊な用途のときだけに絞るのが安全です。
②乗算・除算は格納先が広がることを忘れる
16bitの乗算(*P)は結果が(d)と(d)+1の2ワードに、除算(/P)は商が(d)・余りが(d)+1にと、どちらも格納先が1ワードでは収まりません。32bit版になるとさらに広がり、D*Pは(d)〜(d)+3の4ワード、D/Pも商と余りでそれぞれ2ワードずつを使います。(d)に指定したデバイスの次、あるいは次の3つ分を別の用途で使っていると、演算を実行した瞬間にそのデータが黙って上書きされます。乗算・除算で(d)を決めるときは、その先のデバイスを空けておくのが鉄則です。
③オーバーフローはエラーにならず黙って起きる
+P・-P・D+P・D-Pなどの加減算で、演算結果が扱える範囲(16bitなら-32768〜32767)を超えても、マニュアルには桁上げ(桁下げ)は無視され、SM700(キャリフラグ)はONしないとあります。つまりオーバーフローが起きてもエラー表示も警告も出ず、ただ結果の数値がおかしくなるだけです。生産数の累計のようにいずれ大きくなることが分かっている値を16bitのままにしておくと、ある日突然マイナスの数値が表示されて初めて気づく、という事故につながります。桁あふれの可能性がある値は、最初から32bit版(D+など)で組んでおくのが実務上の対策です。
