matlabでMODBUS③WAGOのPLC 750-469熱電対

　WAGOのPLCを取り上げます。多くのマニュアルが日本語になっています。MODBUS/TCPを使うために、

- TCPインターフェース　750-842
- 2チャネル・リレー出力　750-512
- 熱電対モジュール　750-469/003-000
- アナログ入力のモジュール　750-479
- 終端　750-600

を組み合わせました。
![IMG_4797a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/0189597a-76cd-5885-89c0-a29b895a3f66.png)


　2チャネル・リレー出力は、メカのリレーが2チャネル入っています。出力モジュールには、PNPの半導体出力のモデルもあります。

　熱電対モジュールも2チャネル構成です。デフォルトはK型で、変更できるモデルです。K型の計測範囲は-100～+1370℃です。読み出した値は摂氏の10倍です。

　アナログ入力モジュールは2チャネルです。13ビット＋符号（左詰め、下2ビットはエラー・コード。通常'00'）の、2の補数形式で保持レジスタから読み取れます。

　TCPインターフェース750-842の外側にはMACアドレスが書かれています。これをもとに、TCP/IPアドレスを振ります。750-842のマニュアルを読んで設定しました。具体的な説明は、[こちらの記事](https://www.denshi.club/pc/modbus/modbus-10-wago-750-8421ip.html)を参照してください。

###まずは、Modbus Explorer
　Modbus Explorerを起動します。
![2020-08-29_12h41_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/caa49d95-75fc-411c-5540-1985f702db51.png)

　Deviceをクリックして、出てきたModbus TCP/IPのアイコンをクリックします。
![コメント 2020-08-29 124628.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/410e2120-fe47-63b0-d10b-003c79e1951c.png)

　Device Addressに、設定した192.168.111.25を入れ、Register TypeはInput Registerを選択します。Register Addressは'1'、Readアイコンをクリックすると、268が読み出されました。10で割って26.8℃です。
![スクリーンショット 2020-10-14 08.50.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/ba109883-68d3-769e-a4c5-d137ec6a55d4.png)



　Confirm Parametersをクリックします。次の画面が立ち上がって、連続してreadが実行されてグラフが描かれます。

![スクリーンショット 2020-10-14 08.53.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/bf433501-9b01-7508-f71a-ffa59a2e87d2.png)



　Reg_1の横にチェックをし、Generate Scripts CODEをクリックします。
　ライブエディタが立ち上がります。

###プログラム
　自動で生成された、データ入力部分です。

```matlab
% Input Registers
% Read 1 Input Register of type 'int16' starting from address 1.
modbusData.Reg_1 = read(m, 'inputregs', 1, 1, serverId, 'int16');
```


　先ほどの作業を、Register Addressを1から2に変更して実行します。ServerIDは1のままです。上記の入力部分と合体します。

```matlab
% Input Registers
% Read 1 Input Register of type 'int16' starting from address 1.
modbusData.Reg_1 = read(m, 'inputregs', 1, 1, serverId, 'int16');
modbusData.Reg_2 = read(m, 'inputregs', 2, 1, serverId, 'int16');
fprintf('\ntype K  TC1= %.1f C  TC2=%.1f C ', modbusData.Reg_1/10.0, modbusData.Reg_2/10.0);
```
　二つの熱電対の値を読み出し、10で割って摂氏を求めます。

　同様の作業を、Register Addressを3に変更して実行します。ServerIDは1のままです。Input RegisterはHolding Registerに変更します。
　もう1回、Register Addressを4に変更して実行します。

　読み出したデータは、16ビット長 2の補数形式なので、一度dec2bin()でバイナリの文字列に変換します。この文字列の前に接頭語'0b'をくっつけ、後ろに桁数？を表す's16'をつなげます。その文字列をbin2dec()で10進数に変換すると、先頭が'1'であればマイナスの符号の処理が行われます（R2020a以降）。
　アナログ・データのフォーマットは±10Vなので、2^15で割って10をかけると電圧に変換されます。2チャネル分の読み出しと、電圧に変換したプログラムです。

```matlab
modbusData.Reg_3 = read(m, 'holdingregs', 3, 1, serverId, 'int16');
modbusData.Reg_4 = read(m, 'holdingregs', 4, 1, serverId, 'int16');
binStr0 = dec2bin(modbusData.Reg_3,16);
binStr1 = dec2bin(modbusData.Reg_4,16);
Vin0 = bin2dec(append('0b',binStr0,'s16')) / 32768 * 10;
Vin1 = bin2dec(append('0b',binStr1,'s16')) / 32768 * 10;
fprintf('Vin0 = %.5fV  Vin1 = %.5fV\n', Vin0, Vin1);
```

 Pythonでは、熱電対のアドレスは0x0000、0x0001、アナログ入力のアドレスは、0x0002、0x0003でした。[こちらの記事を参照してください。](https://www.denshi.club/pc/modbus/modbus-16-wago-750-8422.html)
　全体のプログラムです。

```matlab
% Create a Modbus Object.
m = modbus('tcpip', '192.168.111.25');
m.Timeout = 3;

% Save the Server ID specified.
serverId = 1;
% Clear the Server ID.
clear serverId

% Input Registers
% Read 1 Input Register of type 'int16' starting from address 1.
modbusData.Reg_1 = read(m, 'inputregs', 1, 1, serverId, 'int16');
modbusData.Reg_2 = read(m, 'inputregs', 2, 1, serverId, 'int16');
fprintf('\ntype K  TC1= %.1f C  TC2=%.1f C ', modbusData.Reg_1/10.0, modbusData.Reg_2/10.0);

modbusData.Reg_3 = read(m, 'holdingregs', 3, 1, serverId, 'int16');
modbusData.Reg_4 = read(m, 'holdingregs', 4, 1, serverId, 'int16');
binStr0 = dec2bin(modbusData.Reg_3,16);
binStr1 = dec2bin(modbusData.Reg_4,16);
Vin0 = bin2dec(append('0b',binStr0,'s16')) / 32768 * 10;
Vin1 = bin2dec(append('0b',binStr1,'s16')) / 32768 * 10;
fprintf('Vin0 = %.5fV  Vin1 = %.5fV\n', Vin0, Vin1);

% Clear the Modbus Object created.
clear m

% Clear the Server ID.
clear serverId
```

###ディジタル出力
　WAGOのマニュアルによれば、出力と入力は、別々に（別個に）0x0000からアドレスが振られます。先ほどまでのアナログ**入力**は、0x0000～0x0003がふられ、matlabの指定ではRegister Addressが1から4に対応しました。
　いずれかのDevice Listの右側で、Write Registerを下記の条件で実行します。

- Address **1**
- Register Type **Holding Register**
- Write Value **1**

　[write]のボタンを押します。カチッとリレーの動く音がし、2チャネル・リレー出力750-512のDO1-LEDが点灯します。Write Value 0で消灯します。Write Value 2でDO2-LEDが点灯します。Write Value 3で両方のリレーがONになります。
　Generate Scriptでコードをみます。Write Value 2のときのコードです。

```matlab
% Holding Registers
% Write a value 2 of type 'int16' to a Holding Register at address 1.
% write(m, 'holdingregs', 1, 2, serverId, 'int16');
```

　実際は、Holding Registerではなく、ファンクションはwrite single registerなのですが、動きます。実際にやり取りされるデータを表示するモニタがあればいいのですが、見つかっていません。
　温度、電圧の読み取り、出力リレーのON/OFFを10回繰り返すプログラムです。

```matlab
% Create a Modbus Object.
m = modbus('tcpip', '192.168.111.25');
m.Timeout = 3;

% Save the Server ID specified.
serverId = 1;

for i = 1:10
    modbusData.Reg_1 = read(m, 'inputregs', 1, 1, serverId, 'int16');
    modbusData.Reg_2 = read(m, 'inputregs', 2, 1, serverId, 'int16');
    fprintf('\ntype K  TC1= %.1f C  TC2=%.1f C ', modbusData.Reg_1/10.0, modbusData.Reg_2/10.0);
    
    modbusData.Reg_3 = read(m, 'holdingregs', 3, 1, serverId, 'int16');
    modbusData.Reg_4 = read(m, 'holdingregs', 4, 1, serverId, 'int16');
    binStr0 = dec2bin(modbusData.Reg_3,16);
    binStr1 = dec2bin(modbusData.Reg_4,16);
    Vin0 = bin2dec(append('0b',binStr0,'s16')) / 32768 * 10;
    Vin1 = bin2dec(append('0b',binStr1,'s16')) / 32768 * 10;
    fprintf('Vin0 = %.5fV  Vin1 = %.5fV\n', Vin0, Vin1);
    
    write(m, 'holdingregs', 1, 0, serverId, 'int16');
    pause(1);
    write(m, 'holdingregs', 1, 2, serverId, 'int16');
    pause(1);
    write(m, 'holdingregs', 1, 0, serverId, 'int16');
    pause(0.1);
    write(m, 'holdingregs', 1, 1, serverId, 'int16');
    pause(1);
    write(m, 'holdingregs', 1, 0, serverId, 'int16');
    pause(0.1);
    write(m, 'holdingregs', 1, 3, serverId, 'int16');
    pause(1);
end

% Clear the Modbus Object created.
clear m

% Clear the Server ID.
clear serverId
```


###30℃以上になったらリレーをON
　熱電対のTC1で温度を測り、30℃以上になったら、ディジタル出力のDO1をONにするプログラムを作ります。メイン部分です。

```matlab
write(m, 'holdingregs', 1, 0, serverId, 'int16');
for i = 1:10
    modbusData.Reg_1 = read(m, 'inputregs', 1, 1, serverId, 'int16');
    fprintf('\ntype K  TC1= %.1f C  TC2=%.1f C ', modbusData.Reg_1/10.0, modbusData.Reg_2/10.0);
    
    if modbusData.Reg_1 > 300
        write(m, 'holdingregs', 1, 1, serverId, 'int16');
        pause(1);
    else
        write(m, 'holdingregs', 1, 0, serverId, 'int16');
    end
    pause(1);
end
```