Delphi XE5, 10.1 Berlin で Rotronic HC2 (ロトロニック社温湿度計) を、読む (2015/08/14, 2017/03/03 更新)
ロトロニック社 (http://www.rotronic.jp/index.html) の温湿度計を、簡単に Delphi から使うサンプルです。
2017/03/03 (追加)
--------------------------------------------------------------------
HC2 センサーの UART 信号を RS232C にレベル変換すると、とても簡単に読めました。DLL や VCP は不要です。
使用したレベル変換器(¥930) : http://www.mycomkits.com/SHOP/MK-205.html
RS232C の通信設定、送信するコマンド "{ 99RDD}"+#13 は、下記のサンプルと同じです。
MK205 にラトックシステムのWi-Fi - RS232C変換器 (REX-WF60)、Bluetooth - RS232C 変換器 (REX-BT60)
を接続すると、
ワイヤレスで、Windows, Android 端末から、温度、湿度、露点温度の計測が可能になります。
どちらの機器も 5V の電源が必要ですが、モバイルバッテリーでも使用できました。
--------------------------------------------------------------------
※専用のUSBケーブル(UART信号をUSB信号に変換)が必要で、ケーブルだけで ¥24,000. (定価)します。
ハンディタイプ温湿度計(HP22等)の場合、電源は、USBから給電されます。変換器(HF5等)では、無理でした。
USBドライバーのインストール手順 http://www.rotronic.jp/faq_005.html
Windows 8.1 の場合は、「Windows 8 (8.1) でPC接続したとき、正常にインストールできない。」 http://www.rotronic.jp/faq.html も参考に。
VB.NET、C#、VC++、Excel 等から使えるRo3xdrv.dll が公開されていますが、残念ながら、Delphi からでは使えないようです。
VB.NETのサンプルをダブルクリックで試してみたところ、簡単にビルドできました。.NET環境の方は、こちらのほうが良さそうです。
■VCPを使用する
USBドライバのVCP(バーチャルコムポート)機能を使うと、通常のRS-232C機器として、
Delphi からでも簡単に使えます。
「USB Serial Converter」 を右クリックし、「プロパティー」 をクリック。
「詳細設定」タブで、「VCPをロードする」にチェックを付け、[OK]ボタンをクリック。
「USB Serial Port (COM No)」 が追加されます。(追加されない場合は、再起動してみて下さい。)
これを右クリックし、プロパティーを表示します。
「ポートの設定」タブでボーレート等の設定を行います。
■Delphi + ComPort (CPort Lib) でバーチャル COM ポートを使う
送信コマンドは、'{ 99RDD}' + #13
※ '{' と '99RDD}' の間には半角スペースが必要です。要注意です。
50msecほどの時間をおいて受信すると、文字列が返ってきます。
これを、';' 区切りで読むと、計測値等の情報が取得できます。
■FTD2XX.dll をそのまま使う
VCP のチェック、設定は不要です。
専用のUSBケーブルを接続し、ドライバをインストールしただけで、使用できます。
送信文字列、受信文字列は、VCP を使う時とまったく同じです。
DLL を使うために、D2XXUnit2.pas (ソースコードを参照) が必要です。
FTD2XX.dll の日本語説明 PDF は、こちら((株)西日本常盤商行様)
サンプルEXE (現場での温湿度計測のための最少機能ツール)
・相対湿度、温度、露点温度(演算値) 表示
・トレンド表示(直近5分のみ)
・トレンドグラフのスクリーンショット保存
・直近5分間の測定データCSVファイル保存
ダウンロード(サンプルEXE本体のみ.ソースコードなし)
■スクリーンショット
サンプルEXE(マルチスレッドで、1秒に1回程度計測しています。)↓
■ソースコード
unit Rotronic232cUnit; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, CPort; type TForm2 = class(TForm) ComPort1: TComPort; Button1: TButton; Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Edit1Change(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; var Form2: TForm2; implementation {$R *.dfm} uses D2XXUnit2; // VCP(バーチャル COM ポート) 使用 // ComPort コンポーネント(CPort Lib)が必要です procedure TForm2.Button1Click(Sender: TObject); var s : string; begin try with ComPort1 do begin Port := 'COM6'; BaudRate := br19200; DataBits := dbEight; StopBits := sbOneStopBit; Parity.Bits := prNone; Parity.Check := False; FlowControl.FlowControl := fcNone; end; ComPort1.Open; // コマンド送信 ComPort1.WriteStr('{ 99RDD}'+#13); Sleep(100); // レスポンス受信 ComPort1.ReadStr(s, 1024); Edit1.Text := s; ComPort1.Close; except ShowMessage('通信エラーです.'); end; end; // USB 使用(VCPを使わない場合は、こちら) procedure TForm2.Button2Click(Sender: TObject); var res : string; begin // デバイスオープン if OpenUsbDevice = FT_OK then begin // 通信設定 SetUsbDeviceBaudRate; // タイムアウト設定(必須) SetUsbDeviceTimeOuts(500, 500); // 読み込みコマンドを送信 if WriteHc2ReadCommand = FT_OK then // レスポンス受信 if ReadHc2Result(res) = FT_OK then Edit1.Text := res else ShowMessage('返信エラーです.'); // デバイスクローズ CloseUsbDevice; end else begin // USBケーブルが接続されていない ShowMessage('通信エラーです.'); end; end; procedure TForm2.Edit1Change(Sender: TObject); var sl: TStringList; s: string; begin sl := TStringList.Create; try s := StringReplace(Edit1.Text, ' ', '_', [rfReplaceAll]); sl.Delimiter := ';'; sl.DelimitedText := s; if sl.Count > 10 then begin // 相対湿度 Edit2.Text := sl[1]; // 温度 Edit3.Text := sl[5]; // 演算値(露点温度) Edit4.Text := sl[10]; end else begin Edit2.Text := ''; Edit3.Text := ''; Edit4.Text := ''; end; finally sl.Free; end; end; end. // VCP を使う場合は、不要です。 unit D2XXUnit2; { *************************************************** FTD2XX.DLL 通信ユニット for HygroClip2 f.izawa (http://www.izawa-web.com) 2015/08/07 *************************************************** 参考: ・FTDI社 D2XXUnit.pas ・神栄テクノロジー株式会社 VB6 サンプル通信モジュール ・株式会社西日本常盤商行 Ftd2xxドライバー説明日本語訳 } interface Uses Windows,Forms,Dialogs, Messages, SysUtils, Variants, Classes, Graphics, Controls, System.UITypes; const // Return codes FT_OK = 0; FT_INVALID_HANDLE = 1; FT_DEVICE_NOT_FOUND = 2; FT_DEVICE_NOT_OPENED = 3; FT_IO_ERROR = 4; FT_INSUFFICIENT_RESOURCES = 5; FT_INVALID_PARAMETER = 6; FT_INVALID_BAUD_RATE = 7; FT_DEVICE_NOT_OPENED_FOR_ERASE = 8; FT_DEVICE_NOT_OPENED_FOR_WRITE = 9; FT_FAILED_TO_WRITE_DEVICE = 10; FT_EEPROM_READ_FAILED = 11; FT_EEPROM_WRITE_FAILED = 12; FT_EEPROM_ERASE_FAILED = 13; FT_EEPROM_NOT_PRESENT = 14; FT_EEPROM_NOT_PROGRAMMED = 15; FT_INVALID_ARGS = 16; FT_NOT_SUPPORTED = 17; FT_OTHER_ERROR = 18; // Flags for FT_OpenEx FT_OPEN_BY_SERIAL_NUMBER = 1; FT_OPEN_BY_DESCRIPTION = 2; // Flags for FT_ListDevices FT_LIST_NUMBER_ONLY = $80000000; FT_LIST_BY_INDEX = $40000000; FT_LIST_ALL = $20000000; FT_LIST_BY_INDEX_AND_NO = $40000001; // RS232C FT_BITS_8 = 8; FT_BITS_7 = 7; FT_STOP_BITS_1 = 0; FT_STOP_BITS_2 = 2; FT_PARITY_NONE = 0; FT_PARITY_ODD = 1; FT_PARITY_EVEN = 2; FT_PARITY_MARK = 3; FT_PARITY_SPACE = 4; FT_FLOW_NONE = $0000; FT_FLOW_RTS_CTS = $0100; FT_FLOW_DTR_DSR = $0200; FT_FLOW_XON_XOFF = $0400; // Purge FT_PURGE_RX = 1; FT_PURGE_TX = 2; function OpenUsbDevice: long; function CloseUsbDevice: long; function WriteHc2ReadCommand: long; function ReadHc2Result(var res: string): long; function ReadUsbDevice(var res :string; var ReadLen : long): long; function SetUSBDeviceBaudRate: long; function SetUSBDeviceTimeOuts(ReadTimeOut, WriteTimeOut: DWord) : long; function GetUSBDeviceInfo(var DevType: DWord; var ID: DWord; var SerialNumber: array of AnsiChar; var Description: array of AnsiChar) : long; implementation var FT_HANDLE : Long; function FT_GetDeviceInfo(ftHandle: DWord; DevType,ID, SerNum,Desc,pvDummy:Pointer) :long; stdcall; external 'FTD2XX.DLL'; function FT_SetDataCharacteristics(ftHandle:Dword; WordLength,StopBits,Parity:Byte):Integer; stdcall; external 'FTD2XX.DLL' name 'FT_SetDataCharacteristics'; function FT_SetFlowControl(ftHandle:Dword; FlowControl:Word; XonChar,XoffChar:Byte):Integer; stdcall; external 'FTD2XX.DLL' name 'FT_SetFlowControl'; function FT_Open(Index:Integer; var ftHandle:Long): long ; stdcall; external 'FTD2XX.DLL' name 'FT_Open'; function FT_Read(ftHandle:Dword; FTInBuf:Pointer; BufferSize:LongInt; var ResultPtr: Long): Integer; stdcall; external 'FTD2XX.DLL' name 'FT_Read'; function FT_Write(ftHandle:Dword; FTOutBuf:Pointer; BufferSize:LongInt; var ResultPtr: Long): Integer; stdcall; external 'FTD2XX.DLL' name 'FT_Write'; function FT_ResetDevice(ftHandle:Dword):Integer; stdcall; external 'FTD2XX.DLL' name 'FT_ResetDevice'; function FT_Purge(ftHandle:Dword; Mask:Dword):Integer; stdcall; external 'FTD2XX.DLL' name 'FT_Purge'; function FT_Close(ftHandle:Dword):long; stdcall; external 'FTD2XX.DLL' name 'FT_Close'; function FT_SetBaudRate(ftHandle:Dword; BaudRate:DWord):Long; stdcall; external 'FTD2XX.DLL' name 'FT_SetBaudRate'; function FT_SetTimeouts(ftHandle:Dword; ReadTimeout,WriteTimeout:Dword):Long; stdcall; external 'FTD2XX.DLL' name 'FT_SetTimeouts'; function FT_GetStatus(ftHandle: DWord; RxBytes, TxBytes, EventStatus:Pointer):long; stdcall; external 'FTD2XX.DLL' name 'FT_GetStatus'; function FT_ListDevices(pvArg1: Dword; pvArg2:Pointer; dwFlags:Dword):Long; stdcall; external 'FTD2XX.DLL' name 'FT_ListDevices'; function FT_OpenEx(pvArg1: Pointer; dwFlags:Dword; var ftHandle: Long):Long; stdcall; external 'FTD2XX.DLL' name 'FT_OpenEx'; function FT_SetDivisor(ftHandle:Dword; Divisor:DWord):Long; stdcall; external 'FTD2XX.DLL' name 'FT_SetDivisor'; function OpenUsbDevice: long; begin result := FT_Open(0, FT_Handle); end; function CloseUsbDevice: long; begin result := FT_Close(FT_Handle); end; function WriteHc2ReadCommand: long; var WriteLen : long; cmd : string; i : integer; Buffer : array [0.. 63] of AnsiChar; begin cmd := '{ 99RDD}' + #13; for i := 0 to cmd.Length - 1 do FT_Out_Buffer[i] := AnsiChar(cmd[i + 1]); result := FT_Write(FT_Handle, @Buffer, 9, WriteLen); end; function ReadHc2Result(var res: string): long; var ReadLen : long; begin result := ReadUsbDevice(res, ReadLen); end; function ReadUsbDevice(var res :string; var ReadLen : long): long; var i : integer; ret : Long; c : AnsiChar; begin Result := -1; for i := 0 to 255 do begin Application.ProcessMessages; ret := FT_Read(FT_Handle, @c, 1, ReadLen); if ret = FT_OK then begin if (i = 0) and (c <> '{') then Break; res := res + String(c); if c = #13 then begin ReadLen := i; Result := FT_OK; break; end; end else begin Result := ret; Break; end; end; end; function SetUsbDeviceBaudRate: Long; begin FT_Purge(FT_Handle, FT_PURGE_RX or FT_PURGE_TX); FT_ResetDevice(FT_Handle); Result := FT_SetBaudRate(FT_Handle, 19200); FT_SetDataCharacteristics(FT_Handle, FT_BITS_8 ,FT_STOP_BITS_1, FT_PARITY_NONE); FT_SetFlowControl(FT_Handle, FT_FLOW_NONE, $11, $13); end; function SetUsbDeviceTimeOuts(ReadTimeOut, WriteTimeOut: DWord) : long; begin Result := FT_SetTimeouts(FT_Handle, ReadTimeout, WriteTimeout); end; // 未使用 function GetUsbDeviceInfo(var DevType: DWord; var ID: DWord; var SerialNumber:array of AnsiChar; var Description: array of AnsiChar) : long; begin Result := FT_GetDeviceInfo(FT_Handle, @DevType, @ID, @SerialNumber, @Description, nil); end;