デルタオーム社(イタリア) 温湿度トランスミッター HD9817T2R (RS-232C タイプ) を使ってみました (2018/02/24)
・2018/03/02 Android Bluetooth ソースコードを追加
下の画像で、2番目が RS-232C タイプです。D-sub9 ピンのプラグが付いています。
電源は不要で、RS-232C から供給されます。(RTS を ON にする必要があるようです)
RS-232C の他、USB、RS-485 (Modbus) タイプもあります。メーカーへのリンクトは、こちらです。

精度は、温度:±0.2℃±測定値の1.5%、湿度:±1.5%RH (0~90%RH) と高精度です。
同じようにプローブ単体でシリアル出力できる製品にロトロニック社の HC2A-S プローブがあります。
こちらの精度(@23℃)は、 温度:±0.1℃(0~30℃)、湿度:±0.8%RH(0~100%RH)と、より高精度です。
※H2A-Sプローブは、UART 出力のため、RS232C レベルに変換する必要があります。(例えば、秋月電子のこちら を使います。アマゾンだとこちら。)
また、接続用のHC2 丸7pin ソケットは市販されていないため、専用のケーブルを切断してハンダ付けすることになります。
ちなみに定価は、デルタオーム社トランスミッター HD9817T2R \67,400.。ロトロニック社プローブ HC2A-S \50,000.
+ 接続ケーブル \20,000.
■ デルタオームのサイトから、読み込みツール↓がダウンロードできます。

■ 通信テスト用にDelphiで読み込みツールを作ってみました。

■ Delphi 開発中のスクリーンショットです。

■ ソースコード
※ApdComPort を使っています。メニュー 「ツール」-「GetIt パッケージマネージャのインストール」からインストール可能です。
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, OoMisc, AdPort,
Vcl.ExtCtrls, AdStatLt, AdSelCom, AdPacket;
type
TForm2 = class(TForm)
ApdComPort1: TApdComPort;
Button1: TButton;
Edit1: TEdit;
Timer1: TTimer;
Button2: TButton;
ApdStatusLight1: TApdStatusLight;
ApdSLController1: TApdSLController;
ApdStatusLight2: TApdStatusLight;
Label1: TLabel;
Label2: TLabel;
ComboBox1: TComboBox;
ApdDataPacket1: TApdDataPacket;
Edit2: TEdit;
procedure Button1Click(Sender: TObject);
procedure ApdComPort1TriggerAvail(CP: TObject; Count: Word);
procedure Timer1Timer(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ApdDataPacket1StringPacket(Sender: TObject; Data: AnsiString);
private
{ Private 宣言 }
public
{ Public 宣言 }
buf : string;
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
// 受信 (ApdComPortコンポーネントのみを使用した時)
procedure TForm2.ApdComPort1TriggerAvail(CP: TObject; Count: Word);
var
i: Word;
c: AnsiChar;
begin
// 受信文字列の取得
for i := 1 to Count do begin
c := ApdComPort1.GetChar;
// 終端に#13 (CR) が付加されている
if c = #13 then
Edit2.Text := buf
else
buf := buf + string(c);
end;
end;
// 受信 (ApdDataPacketコンポーネントを使用した時)
procedure TForm2.ApdDataPacket1StringPacket(Sender: TObject; Data: AnsiString);
begin
Edit1.Text := String(Data);
end;
// OPEN
procedure TForm2.Button1Click(Sender: TObject);
var
comNo : integer;
begin
with ComboBox1 do begin
if ItemIndex >= 0 then
comNo := StrToIntDef(Items[ItemIndex].Substring (4), -1)
else
comNo := -1;
end;
if comNo >= 0 then begin
with ApdComport1 do begin
ComNumber := comNo;
Baud := 2400;
StopBits := 1;
DataBits := 8;
Parity := TParity.pNone;
RTS := True; // デフォルト
try
Open := True;
// ステータスモニタを ON
ApdSLController1.Monitoring := True;
except
ShowMessage('OPEN 失敗');
end;
end
end
else
ShowMessage('有効な COM ポートが見つかりません.');;
end;
// CLOSE
procedure TForm2.Button2Click(Sender: TObject);
begin
ApdComPort1.Open := False;
Edit1.Text := '';
Edit2.Text := '';
end;
// FormCreate
procedure TForm2.FormCreate(Sender: TObject);
var
i :integer;
begin
// 有効な COM ポートを列挙
for i := 1 to 32 do
if IsPortAvailable(i) then
ComboBox1.Items.Add ( 'COM ' + IntToStr (i));
if ComboBox1.Items.Count > 0 then
ComboBox1.ItemIndex := 0;
Edit1.Text := '';
Edit2.Text := '';
with ApdDataPacket1 do begin
// 終端文字をセット
EndCond := [AdPacket.ecString];
EndString := #13;
// 開始文字を無視
StartCond := AdPacket.scAnyData;
end;
end;
// 1秒周期
procedure TForm2.Timer1Timer(Sender: TObject);
begin
if ApdComPort1.Open then begin
buf := '';
// 送信
// 型番を取得
//ApdComPort1.Output := 'G0'+#13;
// 温度、湿度を取得
//ApdComPort1.Output := 'S0'+#13;
ApdComPort1.PutString('S0'+#13);
end;
end;
end.
■ REX-BT60 (RS232C-Bluetooth 変換アダプタ) を使って Android 端末に計測データを表示してみました。
・Parani-SD1000-00 でも使用可能。(アマゾンへのリンク)(マイクロテクニカへのリンク)(マイクロテクニカ説明書)
・露点温度計算
・音声読み上げ
30 秒に 1 回、計測値を読みあげます。結構便利です。
・トレンドグラフ表示
計測値が安定しているかの確認用で、最新 12 分間のみの表示です。
CSV ファイルに保存する機能を追加予定です。

返信文字列数が少ないので、Bluetooth LE でも使えるかもしれません。であれば、iOS 端末でも使えますね。
■ソースコード
コード
unit Unit2;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
System.Bluetooth, FMX.ScrollBox, FMX.Memo, FMX.Controls.Presentation,
FMX.StdCtrls, System.Bluetooth.Components, FMX.Edit, FMX.Objects,
UIConsts,
Math, FMX.Colors,
// for TTS
Androidapi.JNI.TTS,AndroidAPI.JNIBridge;
type
TBtThread = class(TThread)
private
{ Private 宣言 }
procedure BtOpen;
protected
procedure Execute; override;
public
constructor Create; virtual;
end;
type
TForm2 = class(TForm)
Bluetooth1: TBluetooth;
Timer1: TTimer;
Label1: TLabel;
Label2: TLabel;
PaintBox1: TPaintBox;
Label3: TLabel;
Label4: TLabel;
Panel1: TPanel;
Rectangle1: TRectangle;
Rectangle2: TRectangle;
Rectangle3: TRectangle;
Rectangle5: TRectangle;
Rectangle6: TRectangle;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
Switch1: TSwitch;
Label9: TLabel;
Switch2: TSwitch;
Label10: TLabel;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
procedure FormDestroy(Sender: TObject);
// TTS
type
TttsOnInitListener = class(TJavaLocal, JTextToSpeech_OnInitListener)
private
[weak] FParent : TForm2;
public
constructor Create(AParent : TForm2);
procedure onInit(status: Integer); cdecl;
end;
private
{ private 宣言 }
ttsListener : TttsOnInitListener;
tts : JTextToSpeech;
procedure SpeakOut(const s :string);
procedure InitTTS;
public
{ public 宣言 }
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
end;
type
TRecData = record
Temp : double;
Humi : double;
Dp : double;
RecTime : TDateTime;
end;
const
RECDATA_MAX = 720;
var
GThdMode : integer;
GCmdMode : integer;
GSocket:TBluetoothSocket;
ThBt : TBtThread;
OpenNGcnt : integer;
OpenMsecCnt : integer;
Counter : integer;
BtDeviceHead : string;
const
// SPP(Serial Port Profile) による通信のUUID
ServiceUUID = '{00001101-0000-1000-8000-00805F9B34FB}';
BTDeviceHead1 = 'RN42-';
BTDeviceHead2 = 'SD1000v2';
thdTHSTART = 1000;
thdTHTERM = 2000;
cmdSCCREATE = 200;
cmdSCCONNECT = 201;
cmdSCNG = 202;
var
Form2: TForm2;
ASocket : TBluetoothSocket;
FlagBTConnect : boolean;
RecDataAry : array [0..RECDATA_MAX-1] of TRecData;
DispIndex : integer;
implementation
{$R *.fmx}
uses Androidapi.JNI.JavaTypes, FMX.Helpers.Android
{$IF CompilerVersion >= 27.0}
, Androidapi.Helpers
{$ENDIF}
;
function CalcPws(Td : double):double;
// uses ... Math;
var
S, Pws, T : double;
begin
// 絶対温度 [K]
T := Td + 273.15;
// 飽和水蒸気圧 [hPa]
// Vaisala --------------------------------------------------------------
S := T - (
-0.12743214E-7 * Power(T, 3) +
0.13746454E-4 * Power(T, 2) +
-0.46094296E-2 * Power(T, 1) +
0.49313580 * Power(T, 0)
);
Pws := Exp(
-0.14452093E-7 * Power(S, 3) +
0.41764768E-4 * Power(S, 2) +
-0.48640239E-1 * Power(S, 1) +
0.13914993E01 * Power(S, 0) +
-0.58002206E04 * Power(S, -1)+
6.5459673 * Ln(S)
) / 100;
result := Pws;
end;
function CalcDewPoint(Td, Hu : double): double;
var
Pw, Pws, Tdp : double;
begin
Pws := CalcPws(td);
// 水蒸気圧 [hPa]
Pw := Pws * Hu / 100;
// 露点温度 [℃DP]
Tdp := 237.30 / (7.5000 / Log10(Pw / 6.1078) - 1);
result := Tdp;
end;
// -----------------------------------------------------------------------------
// Bluetooth を Open し、接続する
procedure TBtThread.BtOpen;
var
ABluetoothManager : TBluetoothManager;
APairedDevices : TBluetoothDeviceList;
ADevice : TBluetoothDevice;
idx, i : integer;
begin
GThdMODE := thdTHSTART;
try
try
ABluetoothManager := TBluetoothManager.Current;
if ABluetoothManager.ConnectionState = TBluetoothConnectionState.Connected then begin
// PC名
Synchronize(procedure() begin
Form2.Label1.Text :=
'[' + ABluetoothManager.CurrentAdapter.AdapterName + ']'
end);
// 過去にペアリングされたデバイスの一覧から、REX-BT60 を探す
APairedDevices := ABluetoothManager.GetPairedDevices;
if APairedDevices.Count > 0 then begin
idx := -1;
for i := 0 to APairedDevices.Count -1 do begin
// 'RN42-****' が、REX-BT60
if (Pos(BTDeviceHead, APairedDevices[i].DeviceName) = 1) then begin
Synchronize(procedure() begin
Form2.Label1.Text := Form2.Label1.Text + ' - ' +
'[' + APairedDevices[i].DeviceName + ']';
end);
idx := i;
break;
end;
end;
if idx >= 0 then begin
ADevice := APairedDevices[idx];
if ADevice <> nil then begin
GSocket := ADevice.CreateClientSocket(StringToGUID(ServiceUUID), False);
if GSocket <> nil then begin
GCMDMODE := cmdSCCREATE;
// 接続
GSocket.Connect;
if GSocket.Connected then begin
GCMDMODE := cmdSCCONNECT;
end;
end;
end;
end;
end;
end;
except
on E : Exception do begin
GCMDMODE := cmdSCNG;
end;
end;
finally
// 明示的にスレッドを終了(破棄される)
// スレッド実行中にアプリを終了した時エラーになるため
Terminate;
WaitFor;
FreeAndNil(ThBt);
GThdMODE := thdTHTERM;
end;
end;
constructor TBtThread.Create;
begin
// スレッドを生成、直ちに実行
inherited Create(False);
// スレッド終了時、スレッドオブジェクトを破棄
FreeOnTerminate := True;
end;
procedure TBtThread.Execute;
begin
BtOpen;
end;
// -----------------------------------------------------------------------------
procedure TForm2.InitTTS;
begin
tts := TJTextToSpeech.JavaClass.init(TAndroidHelper.Context, ttsListener);
end;
procedure TForm2.SpeakOut(const s : string);
var
text : JString;
begin
text := StringToJString(s);
tts.speak(text, TJTextToSpeech.JavaClass.QUEUE_FLUSH, nil);
end;
{ TForm1.TttsOnInitListener }
constructor TForm2.TttsOnInitListener.Create(AParent: TForm2);
begin
inherited Create;
FParent := AParent
end;
procedure TForm2.TttsOnInitListener.onInit(status: Integer);
var
Result : Integer;
begin
if (status = TJTextToSpeech.JavaClass.SUCCESS) then
begin
//result := FParent.tts.setLanguage(TJLocale.JavaClass.US);
result := FParent.tts.setLanguage(TJLocale.JavaClass.JAPAN);
if (result = TJTextToSpeech.JavaClass.LANG_MISSING_DATA) or
(result = TJTextToSpeech.JavaClass.LANG_NOT_SUPPORTED) then
ShowMessage('This Language is not supported')
else
begin
//FParent.Button1.Enabled := true; // SayMe
//FParent.button2.Enabled := false; // Init TTS
end;
end
else
ShowMessage('Initilization Failed!');
end;
// -----------------------------------------------------------------------------
function ASocketReceiveData(ASocket: TBluetoothSocket; term: Char; ATimeout: Cardinal): string;
var
AData : TBytes;
ReadData : TBytes;
i : integer;
res : string;
Ticks : Cardinal;
idx : integer;
loop : boolean;
cnt : integer;
begin
res := '';
cnt := 0;
SetLength(ReadData, 1024);
idx := 0;
Ticks := TThread.GetTickCount;
loop := True;
while loop and (cnt < 500) do begin
Sleep(1);
AData := ASocket.ReceiveData;
if Length(AData) > 0 then begin
for i := 0 to Length(AData) - 1 do begin
ReadData[idx] := AData[i];
Inc(idx);
// CR であれば、抜ける
if (AData[i] = Ord(term)) or (idx >= 1024) then begin
loop := False;
break;
end;
end;
end;
Inc(cnt);
if loop then
loop := TThread.GetTickCount - Ticks < ATimeout;
end;
SetLength(ReadData, idx);
res := TEncoding.ANSI.GetString(ReadData);
result := Trim(res);
end;
// -----------------------------------------------------------------------------
constructor TForm2.Create(AOwner: TComponent);
begin
inherited;
ttsListener := TttsOnInitListener.Create(self);
end;
destructor TForm2.Destroy;
begin
if Assigned(tts) then begin
tts.stop;
tts.shutdown;
tts := nil;
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
var
i : integer;
begin
Timer1.Interval := 10;
ThBt := TBtThread.Create;
Label1.Text := '';
Label2.Text := '';
Label3.Text := '';
Label5.Text := '';
for i := 0 to RECDATA_MAX -1 do begin
RecDataAry[i].Temp := -99;
RecDataAry[i].Humi := -99;
RecDataAry[i].Dp := -99;
RecDataAry[i].RecTime := 0;
end;
DispIndex := -1;
BtDeviceHead := BTDeviceHead1;
// TTS
InitTTS;
end;
procedure TForm2.FormDestroy(Sender: TObject);
begin
// ソケット破棄
if GSocket <> nil then begin
if GSocket.Connected then
GSocket.Close;
FreeAndNil(GSocket);
end;
end;
procedure TForm2.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var
xsc , ysc, ybase : double;
i : integer;
stX, stY, edX, edY : single;
aLeft, aTop, aRight, aBottom : single;
aStep : integer;
pbox : TPaintBox;
begin
pBox := Sender as TPaintBox;
with Canvas do begin
BeginScene;
xsc := pbox.Width / RECDATA_MAX;
ysc := pbox.Height/ 100;
ybase := 0.0;
aLeft := 0;
aTop := 0;
aRight := aLeft + pbox.Width;
aBottom := aTop + pbox.Height;
aStep := RECDATA_MAX div 6;
Fill.Kind := TBrushKind.Solid ;
Fill.Color := TAlphaColors.Black;//claBlack;
FillRect(RectF(aLeft, aTop, aRight + 1, aBottom), 0, 0, AllCorners, 1.0);
Stroke.Color := claBlue; // 線色
Stroke.Dash := TStrokeDash.Dash; // 線種
Stroke.Kind := TBrushKind.Solid;
Stroke.Thickness := 1 ; // 線幅
// 横目盛り
for i := 1 to 9 do begin
//if i * 10 = 50 then
// Stroke.Color := claRed
//else
// Stroke.Color := claBlue;
// 横線
DrawLine(
PointF(aLeft + 1, aBottom - i * 10 * ysc),
PointF(aRight, aBottom - i * 10 * ysc),
1.0);
Fill.Color := claWhite;
Font.Size := 10;
// 左側の目盛り
FillText(
RectF(aLeft, aBottom - i * 10 * ysc - 6,
aLeft + 20, aBottom - i * 10 * ysc - 6 + 16),
IntToStr(i*10),
True, 1.0, [], TTextAlign.Leading, TTextAlign.Leading);
// 右側の目盛り
FillText(
RectF(aRight - 20, aBottom - i * 10 * ysc - 6,
aRight, aBottom - i * 10 * ysc - 6 + 16),
IntToStr(i*5),
True, 1.0, [], TTextAlign.Trailing, TTextAlign.Leading);
end;
Fill.Color := claWhite;
FillText(RectF(aLeft + 1, aTop, aLeft + 40, aTop + 16),
'[%RH]',
True, 1.0, [], TTextAlign.Leading, TTextAlign.Leading);
FillText(RectF(aRight - 20, aTop, aRight, aTop + 16),
'[℃]',
True, 1.0, [], TTextAlign.Trailing, TTextAlign.Leading);
// 縦目盛り
for i := 1 to 5 do begin
DrawLine(
PointF(aLeft + i * aStep * xsc, aBottom),
PointF(aLeft + i * aStep * xsc, aTop),
0.75);
end;
// 時刻
FillText(
RectF(aLeft, aBottom - 16, aLeft + 40, aBottom),
FormatDateTime('hh:mm', RecDataAry[0].RecTime),
True, 1.0, [], TTextAlign.Leading, TTextAlign.Leading);
for i := 1 to 6 do begin
if RecDataAry[i * aStep-1].RecTime > 0 then begin
FillText(
RectF(aLeft + i * aStep * xsc, aBottom - 16,
aLeft + i * aStep * xsc + 40, aBottom),
FormatDateTime('hh:mm', RecDataAry[i * aStep - 1].RecTime),
True, 1.0, [], TTextAlign.Leading, TTextAlign.Leading);
end;
end;
// 現在の値
FillText(
RectF(aLeft + 40, aTop + 1,
aLeft + 40 + 400, aTop + 17),
FormatDateTime('[ yyyy/mm/dd hh:mm:ss ] ', Now) +
Format('%.1f %%RH: %.1f ℃: %.1f ℃DP',
[RecDataAry[DispIndex].Humi, RecDataAry[DispIndex].Temp, RecDataAry[DispIndex].Dp]),
True, 1.0, [], TTextAlign.Leading, TTextAlign.Leading);
// 計測データ
Stroke.Dash := TStrokeDash.Solid;
Stroke.Thickness := 1 ; // 線幅
// 相対湿度
Stroke.Color := claYellow;
stX := 0; stY := 0; edX := 0; edY := 0;
for i := 0 to RECDATA_MAX - 2 do begin
if RecDataAry[i].Humi >= 0 then begin
stX := aLeft + i * xsc;
stY := aBottom - (RecDataAry[i].Humi + ybase) * ysc;
end;
if RecDataAry[i+1].Humi >= 0 then begin
edX := aLeft + (i + 1) * xsc;
edY := aBottom - (RecDataAry[i + 1].Humi + ybase) * ysc;
end;
if (stX > 0) and (stY > 0) and (edX > 0) and (edY > 0) then
DrawLine(PointF(stX + 1, stY), PointF(edX + 1, edY), 1.0);
end;
// 温度
ysc := pbox.Height / 50;
Stroke.Color := claLime;
stX := 0; stY := 0; edX := 0; edY := 0;
for i := 0 to RECDATA_MAX - 2 do begin
if RecDataAry[i].Temp >= 0 then begin
stX := aLeft + i * xsc;
stY := aBottom - (RecDataAry[i].Temp + ybase) * ysc;
end;
if RecDataAry[i+1].Temp >= 0 then begin
edX := aLeft + (i + 1) * xsc;
edY := aBottom - (RecDataAry[i + 1].Temp + ybase) * ysc;
end;
if (stX > 0) and (stY > 0) and (edX > 0) and (edY > 0) then
DrawLine(PointF(stX + 1, stY), PointF(edX + 1, edY), 1.0);
end;
// 露点温度
if Switch1.IsChecked then begin
Stroke.Color := claAqua;
stX := 0; stY := 0; edX := 0; edY := 0;
for i := 0 to RECDATA_MAX - 2 do begin
if RecDataAry[i].Dp >= 0 then begin
stX := aLeft + i * xsc;
stY := aBottom - (RecDataAry[i].Dp + ybase) * ysc;
end;
if RecDataAry[i+1].Dp >= 0 then begin
edX := aLeft + (i + 1) * xsc;
edY := aBottom - (RecDataAry[i + 1].Dp + ybase) * ysc;
end;
if (stX > 0) and (stY > 0) and (edX > 0) and (edY > 0) then
DrawLine(PointF(stX + 1, stY), PointF(edX + 1, edY), 1.0);
end;
end;
EndScene;
end;
end;
procedure TForm2.Timer1Timer(Sender: TObject);
var
res : string;
T, H, Tdp : double;
i : integer;
TxData : TBytes;
begin
if not ((GCMDMODE = cmdSCCONNECT) and GSocket.Connected) then begin
Inc(OpenMsecCnt);
Label4.Text := IntToStr(OpenMsecCnt * 10) + 'msec';
if GCMDMODE = cmdSCNG then begin
Inc(OpenNgCnt);
if OpenNgCnt > 4 then begin
Timer1.Enabled := False;
ShowMessage('接続できません.');
end
else begin
// 再接続
// ターゲットを変えてみる
if BtDeviceHead = BTDeviceHead1 then
BtDeviceHead := BTDeviceHead2
else
BtDeviceHead := BTDeviceHead1;
Sleep(500);
OpenMsecCnt := 0;
GCMDMODE := 0;
GTHDMODE := 0;
ThBt := TBtThread.Create;
end;
end;
end;
if (GCMDMODE = cmdSCCONNECT) and GSocket.Connected then begin
Timer1.Interval := 500;
try
// 送信
TxData := TEncoding.ANSI.GetBytes('S0' + #13);
GSocket.SendData(TxData);
// 受信
res := ASocketReceiveData(GSocket, #13, 500);
T := StrToFloatDef(res.Substring(0, 6), -20);
H := StrToFloatDef(res.Substring(11), 0);
Label2.Text := Format('%.1f', [T]);
Label3.Text := Format('%.1f', [H]);
if (T > -20) and (H > 0) then begin
Tdp := CalcDewPoint(T,H);
Label5.Text := Format('%.1f', [Tdp]);
end
else begin
Tdp := 0;
Label5.Text := '';
end;
Inc(DispIndex);
if DispIndex >= RECDATA_MAX - 1 then begin
DispIndex := RECDATA_MAX - 121;
for i := 0 to RECDATA_MAX - 121 do
RecDataAry[i] := RecDataAry[i + 121];
for i := RECDATA_MAX - 120 to RECDATA_MAX - 1 do begin
RecDataAry[i].Temp := -99;
RecDataAry[i].Humi := -99;
RecDataAry[i].Dp := -99;
RecDataAry[i].RecTime := 0;
end;
end;
RecDataAry[DispIndex].Humi := H;
RecDataAry[DispIndex].Temp := T;
RecDataAry[DispIndex].Dp := Tdp;
RecDataAry[DispIndex].RecTime := Now;
// 描画
PaintBox1.Repaint;
// テキストスピーチ
Inc(Counter);
if Switch2.IsChecked then begin
if Counter = 10 then
SpeakOut('温度:' + Label2.Text)
else if Counter = 20 then
SpeakOut('湿度:' + Label3.Text)
else if Counter = 30 then
SpeakOut('露点温度:' + Label5.Text);
end;
if Counter >= 30 then Counter := 0;
except
;
end;
end;
end;
end.