はじめてのModbus (1) 電力量モニタKM-N1-FLK

 もうすぐUSB4.0という規格が決まるそうです。そうすると、マウスから8Kディスプレイの接続まで、周辺機器は全部USBのシリアル通信で統一される時代がやってきます。
 IBM/PCが世の中に出たとき、シリアル通信はRS-232Cでした。プリンタはセントロニクスという8ビット・パラレル、拡張カード類はISAというパラレル・バス、ハードディスクもIDEというパラレル・バスでした。

 RS-232Cは最終的にはEIA-232Dという正式な規格になりました。RS-232Cと呼ばれた時代が長かったので、非同期シリアル通信規格は現在UARTという呼び名が使われますが、RS-232Cという刷り込みがあります。最大±15V振幅で距離10mの通信を行います。
 よく似た規格にRS-422があります。これはAppleのMacintoshがAppleTalk用の物理層で使っていました。もう一つRS-485があります。

  • 差動で信号を伝送するので、ノイズ耐性が上がり1,200m以上まで装置間を伸ばせる
  • 振幅を抑えることでビット・レートが上がり、最大10Mbps
  • 装置は最大32+32の64個までぶら下げられるマルチドロップ

 これらの特徴をもつため、ビル内、監視カメラの制御、工場内のデータ通信などに使われています。
 RS-485は物理層なので、実際の通信を行うには通信プロトコルが規定されていないと、機器間はデータのやり取りをできません。こちらの記事でも、さまざまな事例を使いました。ここでは、工場などで一般的なModbusを使います。Modbusには次の3種類があります。

  • Modbus/ASCII データはASCIIコード。あまり使われていない
  • Modbus/RTU RTU(Remote Terminal Unit)のデータは16進値。
  • Modbus/TCP RS-485ではなくイーサネットにModbus/RTUのコードを載せる

 Arduino UNOの時代、純正のRS-485インターフェースはありませんでした。IoTを標榜するMKRシリーズの製品が増えたころ、ここで用いるArduino MKR 485 Shieldが出荷を始めました。入出力はノイズの影響を少なくするために絶縁されていますが、実験ではそうでない機器でもつないで使えます。
 ライブラリは半年ほど遅れ、2018年夏に出ました。

 次の写真は、MKRZEROの上にArduino MKR 485 Shieldを挿しこんで利用している様子です。このシールドの左の端子は外部電源をつなげられます。右の緑色の端子に出ている電源はそれらとは絶縁されています。

 Modbusの仕様 日本語の参考資料 

USB-RS485ボードをPCに挿す

 Windows10が物理レイヤのRS-485をアクセスできるように、USB-RS485アダプタを用意します。
 入手したボードではUSB-シリアル変換にCP210xやCH34xが使われていました。Windows10では自動でドライバが入ると思います。アマゾンやebayでは千円前後で入手できます。

接続するのはオムロンの小型電力量モニタKM-N1-FLK

 KM-N1-FLKは、最大で四つの交流電流センサCTをつなげられるコンパクトな形状をした電力計です。RS-485でアクセスできます。電流センサCTは5A/50Aの最小容量KM-NCT-5A/50Aを、接続ケーブル KM-NCB-1Mをアマゾンで入手しました。測定を兼ねているAC100Vをつなげることで、別途電源は不要です。

 デフォルトの通信プロトコルはオムロン独自のCompoWay/Fです。パネルの操作でも変更できますが、PCのユーティリティKM-NSettingToolを用いてModbus/RTUに変更する手順は、こちらの記事を参照してください。通信条件は、8ビット、パリティなし、ストップ・ビット2です。このKM-N1-FLKでは、8ビット、パリティなし、ストップ・ビット1は設定できません。

接続

 Arduino MKR 485 ShieldとKM-N1-FLK を2本のケーブルで接続します。結線は次のようにします。

 

 Arduino MKR 485 Shield上のDIPスイッチは全部OFFで動きます。RS-485の終端抵抗は両端に入れるのが正しいので、Y-ZのターミネイトをONにします。

スケッチ

 ライブラリはArduinoModbusとArduino RS485の二つをインストールします。サンプルのModbusRTUTemperatureSensorを修正します。8ビット、ストップ・ビット2、パリティなしに設定したので、初期化のところにその指定を入れます。

if (!ModbusRTUClient.begin(9600,SERIAL_8N2)) {

 計測データはHOLDING_REGISTERSを読み出します。電圧は0x0000、電流は0x0006を読み出すと得られます。

if (!ModbusRTUClient.requestFrom(1, HOLDING_REGISTERS, 0x0006, 2)) {

 この2か所を修正してコンパイル、実行します。AC100V側の電圧97V前後が読み出せました。

 上記のスケッチをベースに電力計の電圧を読み出すスケッチを作りました。レジスタ0x0000を読み出した電圧のフォーマットは、データシートには次のように書かれています。

  H'00000000~H'0098967F(0~9999999) 電圧の10倍値

 ArduinoModbusライブラリのリードは16ビット単位と思われるので、二度読み出し、32ビットの値を10で割ります。

// created 8 August 2018 by Riccardo Rizzo

#include <ArduinoModbus.h>

void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println("Modbus KM-N1-FLK AC Voltage");
// start the Modbus RTU client
if (!ModbusRTUClient.begin(9600, SERIAL_8N2)) {
Serial.println("Failed to start Modbus RTU Client!");
while (1);
}
}

void loop() {
// send a Holding registers read request to (slave) id 1, for 2 registers
if (!ModbusRTUClient.requestFrom(1, HOLDING_REGISTERS, 0x0000, 2)) {
Serial.print("failed to read registers! ");
Serial.println(ModbusRTUClient.lastError());
} else {
int32_t ACV = ModbusRTUClient.read();
ACV = ACV <<16 | ModbusRTUClient.read();
Serial.println(ACV / 10.0);
}
delay(2000);
}

 実行中の様子です。

コラム 波形

 PicoScopeでrequestFrom()の波形を観測しました。

前へ

はじめてのMKR ZERO (8) 透過OLEDディスプレイ②

次へ

はじめてのModbus (2) Lチカ