オムロン KM20-B40-FLK RS-485 通信 2020/10/04
オムロンの電力量センサ KM20-B40-FLK RS-485 通信です。
Modbus ではなく、CompoWay/F というオムロン独自の通信手順 + FINS-mini コマンドです。
現在 KM20-B40-FLK は廃番になっており、代替機種の KM-N1-FLK は Modbus RTU にも対応しているようです。
電力量ではなくて、簡単に交流電流値を計測(PLC に接続)するだけであれば、下記 URD 社製が良さそうです。
■平均値整流型 0-5V 出力(歪波形は誤差大)
https://jp.misumi-ec.com/vona2/detail/221000835720/
■実効値整流型 4-20mA 出力(2線式)
https://jp.misumi-ec.com/vona2/detail/221000835731/

{
OMRON KM20-B40-FLK (RS485タイプ)
CompoWay/F は、オムロンの汎用シリアル通信における統一通信手順。
FINS (Factory Interface Network service) とは、
オムロンの FA ネットワーク上のコントローラ間で、メッセージ通信を行うためのプロトコル。
}
unit uni232test;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Uni232C;
type
TForm5 = class(TForm)
Uni232C1: TUni232C;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form5: TForm5;
implementation
{$R *.dfm}
// 接続
procedure TForm5.Button1Click(Sender: TObject);
var
ret : integer;
begin
Uni232C1.Port := 3;
Uni232C1.BaudRate := 19200;
Uni232C1.ByteSize := Bit8;
Uni232C1.ParityBits := ParityNone;
Uni232C1.StopBits := Stopbit1;
Uni232C1.FlowControls := CtrlNone;
ret := Uni232c1.Open;
if ret < 0 then
ShowMessage('Cannot OPEN' + Uni232C1.Error2Str(ret));
end;
// 切断
procedure TForm5.Button2Click(Sender: TObject);
begin
if Uni232C1.Connect then
Uni232C1.Close;
end;
// データ読み込み
procedure TForm5.Button3Click(Sender: TObject);
var
txData, rxData : TBytes;
cmd, res : string;
bcc : Byte;
len : integer;
ret : integer;
i : integer;
begin
if Uni232C1.Connect then begin
cmd := #02; // STX
cmd := cmd + '01'; // ノードNo.
cmd := cmd + '00'; // サブアドレス = "00"
cmd := cmd + '0'; // SID = "0"
// 以下、FINS-mini コマンド・テキスト
cmd := cmd + '0101'; // MRC, SRC 変数エリア読出の場合
cmd := cmd + 'C0'; // 変数種別 "C0","C2"~"C3" のいずれか
// "0000" = P1-P2間電圧(瞬時値) 小数点以下 1 桁
// "0001" = P2-P3間電圧(瞬時値)小数点以下 1 桁
// "0002" = I1電流(瞬時値)(A) 小数点以下 2 桁
// "0003" = I2電流(瞬時値)(A) 小数点以下 2 桁
// "0004" = 有効電力(瞬時値)(kW) 小数点以下 2 桁
// "0005" (欠番)
// "0006" = 力率 (瞬時値) 小数点以下 2 桁
// "0007" = 周波数(Hz) 小数点以下 1 桁
// "0008" = 積算電力量(kWh) 小数点以下 1 桁
// "0009" (欠番)
// "000A" = ステータス
// "000B" = バージョン
cmd := cmd + '0000'; // 読み出し開始アドレス
cmd := cmd + '00'; // ビット位置 "00" 固定
cmd := cmd + '000B'; // 読み出し数(16進表記)最大 11 ($0B) 個まで Len = 105( 8 * 11 +17 )
cmd := cmd + #03; // ETX
txData := TEncoding.ANSI.GetBytes(cmd);
len := Length(txData);
// BCC (ブロックチェックキャラクタ)計算
// STX の次 ノードNo. から ETX までの XOR
bcc := 0;
for i := 1 to len - 1 do // ETX を含む
bcc := bcc xor txData[i];
SetLength(txData, len + 1);
txData[len] := bcc; // 最後に BCC を追加
// 送信
Uni232C1.Write(len + 1, @txData[0]);
Sleep(10);
SetLength(rxData, 128); // 受信データバイト数ピッタリ+1で良い
// 受信
ret := Uni232C1.Read(128, @rxData[0]);
Memo1.Lines.Add('Len = ' + ret.ToString); // 受信バイト数
// 正常時
// バイト数 = データ数 * 8 + 14 + 2(STX,ETX) + 1(#0)
// データ数が2の時は 2 * 8 + 17 = 33
// BCC エラー時
// バイト数 = 9 ; STX + "0100" (ノードNo.+ サブアドレス) + "13"(BCCエラー) + ETX + #0
res := TEncoding.ANSI.GetString(rxData);
res := Trim(res); // 制御文字を含まない
Memo1.Lines.Add(res);
if ret >= 8 * 11 + 17 then begin // データ数 = 11 の時
// "01" ノードNo.
// "00" サブアドレス
// "00" 終了コード "00" であれば正常終了
// "01" MRC,
// "01" SRC
// "00" MRES
// "00" SRES
// "000003FA" P1-P2 間の電圧 $3FA = 1018 これの 1/10 が電圧値 = 101.8 V
// "00000000" P2-P3 間の電圧
// ....以降データ数に応じて、8 桁 16 進表記の文字が続く
Memo1.Lines.Add('P1-P2 間電圧 = ' +
Format('%.1f V', [StrToIntDef('$' + Copy(res, 15, 8), 0) * 0.1]));
Memo1.Lines.Add('P2-P3 間電圧 = ' +
Format('%.1f V', [StrToIntDef('$' + Copy(res, 23, 8), 0) * 0.1]));
Memo1.Lines.Add('I1 電流 = ' +
Format('%.2f A', [StrToIntDef('$' + Copy(res, 31, 8), 0) * 0.01]));
Memo1.Lines.Add('I2 電流 = ' +
Format('%.2f A', [StrToIntDef('$' + Copy(res, 39, 8), 0) * 0.01]));
Memo1.Lines.Add('有効電力 = ' +
Format('%.2f kW', [StrToIntDef('$' + Copy(res, 47, 8), 0) * 0.01]));
// "0005" 欠番のデータは無視
Memo1.Lines.Add('力率 = ' +
Format('%.2f ', [StrToIntDef('$' + Copy(res, 63, 8), 0) * 0.01]));
Memo1.Lines.Add('周波数 = ' +
Format('%.1f Hz', [StrToIntDef('$' + Copy(res, 71, 8), 0) * 0.1]));
Memo1.Lines.Add('積算電力量 = ' +
Format('%.1f kWh', [StrToIntDef('$' + Copy(res, 79, 8), 0) * 0.1]));
end;
end;
end;
end.