azbil SDC/R を Android スマホで動作チェック (2019/03/20)
azbil 調節計 SDC/R 35 シリーズの現場チェックを Android スマホで行います。
SDC のローダーコネクタに Bluetooth アダプターを接続し、Bluetooth 経由で Android と CPL 通信をしています。
・PV、SP、OUT、MFB の表示のほか、設定変更、手動出力が行えます。
・PV、MFB の値を音声合成で読み上げます。
■Bluetooth アダプタ
・自作の場合
マイクロテクニカの「Bluetooth - シリアルモジュール RBT-001」 + 「電圧レベル変換アダプタ 80FG990」 (合計¥4,630)を使います。
レベル確保のため、SDC へはバッファ IC 74HC4050 を通して接続ます。接続図はこちらです。
SDC への接続は、富士パーツ商会の3.5mm -> 2.5mm 変換プラグ AD-SPS-06 または、AD-SPS-12 を使っています。(ゴムキャップ切れなし)
RBT-001 のツールで、通信設定を 19200BPS、Even に変更。 No events reported, no UART break
に変更します。
接続先の名前は、「EasyBT」です。

↑+5V は USB 給電です。
※スイッチサイエンスでも同様のものが販売されています。
「Bluetooth モジュール RBT-001」+「RBT-001用シリアルレベルコンバータ Rev.3」 (合計¥7,044.)
・市販品の場合
ラトックシステムの「RS232C-Bluetooth 変換アダプタ REX-BT60」と azbil 純正のローダーケーブル (RS232C)
を使います。
REX-BT60 のツールで、通信設定を 19200BPS、8Bits、OneStopBit、Even にします。
Android アプリ 「BtSerialUtility」 で設定変更がうまくいかない場合は、Windows の「BtSerialUtility_com.exe」
を使います。
接続先の名前は、「RN42-」 または、「RNBT-」 で始まります。
REX-BT60 とローダーケーブル (RS232C) を直結するだけでつながります。
REX-BT60 の電源ケーブルは、USB 給電タイプのものを使うとモバイルバッテリーで使用できます。
■著作権、免責事項
・本ツールの著作権は、作者 f.izawa が所有し、これを主張します。
・本ツールをインストール、使用したことによる事故損害等の一切について、作者はその責を負いません。
■作者連絡先
・e-mail : f.izawa@dream.com (@を小文字に変えて下さい)
・URL : http://www.izawa-web.com/
■ダウンロード
・andC35.apk (apk 本体のみ)
起動前にペアリングしておいてください。
初回起動時は、エラーになります。一覧から接続先を指定し、「保存」ボタンをタップし、終了して下さい。
接続できない場合は、一度終了し再度起動してみて下さい。
unit Unit4;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
System.Bluetooth, System.Bluetooth.Components, FMX.ScrollBox, FMX.Memo,
FMX.Controls.Presentation, FMX.StdCtrls, FMX.Layouts, FMX.Edit, System.Rtti,
FMX.Grid.Style, FMX.Grid,{ Math,} FMX.Objects, System.UIConsts, FMX.ListBox,
System.IOUtils, System.IniFiles,
// for TTS
Androidapi.JNI.TTS,AndroidAPI.JNIBridge,
AndroidApi.JNI.Media;
type
TBtThread = class(TThread)
private
{ Private 宣言 }
procedure BtOpen;
protected
procedure Execute; override;
public
constructor Create; virtual;
end;
type
TForm4 = class(TForm)
Timer1: TTimer;
ScaledLayout1: TScaledLayout;
MOUT: TButton;
Rectangle1: TRectangle;
Label4: TLabel;
Rectangle2: TRectangle;
Label5: TLabel;
Rectangle3: TRectangle;
Label3: TLabel;
Rectangle4: TRectangle;
Label1: TLabel;
Rectangle5: TRectangle;
Label2: TLabel;
Label7: TLabel;
Rectangle9: TRectangle;
ComboBox3: TComboBox;
Button2: TButton;
Switch1: TSwitch;
Rectangle6: TRectangle;
Label8: TLabel;
Rectangle7: TRectangle;
Label9: TLabel;
Rectangle8: TRectangle;
Label6: TLabel;
Rectangle10: TRectangle;
Label10: TLabel;
Rectangle11: TRectangle;
Label12: TLabel;
SP: TButton;
Label14: TLabel;
Label15: TLabel;
Label16: TLabel;
Label17: TLabel;
Label11: TLabel;
Rectangle12: TRectangle;
Label19: TLabel;
Button1: TButton;
Rectangle13: TRectangle;
Label18: TLabel;
Rectangle14: TRectangle;
Label13: TLabel;
Rectangle15: TRectangle;
Label20: TLabel;
Label21: TLabel;
Rectangle16: TRectangle;
Rectangle17: TRectangle;
Rectangle18: TRectangle;
Rectangle19: TRectangle;
Rectangle20: TRectangle;
Rectangle21: TRectangle;
Rectangle22: TRectangle;
Label22: TLabel;
Label23: TLabel;
Label24: TLabel;
Label25: TLabel;
Label26: TLabel;
Label27: TLabel;
Label28: TLabel;
Switch2: TSwitch;
Label29: TLabel;
Label30: TLabel;
procedure MOUTClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Rectangle7Click(Sender: TObject);
procedure SPClick(Sender: TObject);
procedure Rectangle14Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
// TTS
type
TttsOnInitListener = class(TJavaLocal, JTextToSpeech_OnInitListener)
private
[weak] FParent : TForm4;
public
constructor Create(AParent : TForm4);
procedure onInit(status: Integer); cdecl;
end;
private
{ private 宣言 }
ttsListener : TttsOnInitListener;
tts : JTextToSpeech;
procedure SpeakOut(const s :string);
procedure InitTTS;
public
{ public 宣言 }
decScale : Double;
decPt : integer;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
end;
var
Form4: TForm4;
ADevice : TBluetoothDevice;
ASocket : TBluetoothSocket;
GThdMode : integer;
GCmdMode : integer;
ThBt : TBtThread;
OpenNGcnt : integer;
OpenMsecCnt : integer;
Counter : integer;
TTScnt : integer;
BtDeviceHead : string;
// uses ... Androidapi.JNIBridge, AndroidApi.JNI.Media;
ToneGenerator: JToneGenerator;
const
// SPP(Serial Port Profile) による通信のUUID
ServiceUUID = '{00001101-0000-1000-8000-00805F9B34FB}';
thdTHSTART = 1000;
thdTHTERM = 2000;
cmdSCCREATE = 200;
cmdSCCONNECT = 201;
cmdSCNG = 202;
STX = #$02;
ETX = #$03;
CRLF = #$0D#$0A;
implementation
uses Androidapi.JNI.JavaTypes, FMX.Helpers.Android
{$IF CompilerVersion >= 27.0}
, Androidapi.Helpers
{$ENDIF}
;
{$R *.fmx}
// n の k 乗 (Math ユニット不要)
function IntPower(n, k : integer):integer;
var
i : integer;
begin
result := 1;
for i := 1 to k do result := result * n;
end;
// CPL 通信の文字列を作成
function MakeCPLCommandStr(const cmd : string): string;
var
i : integer;
s : string;
sum : integer;
chksum : string;
AData : TBytes;
begin
s := '';
s := STX; // 電文先頭
s := s + '01'; // 機器アドレス
s := s + '00'; // サブアドレス(未使用)
s := s + 'X' ; // デバイス区別コード 'X' または、'x'
s := s + cmd ; // コマンド
s := s + ETX ; // アプリケーション層の終了位置
// チェックサムの作成
// STX ~ ETX までを1バイトずつ加算
sum := 0;
AData := TEncoding.ANSI.GetBytes(s);
for i := 0 to Length(AData) -1 do
sum := sum + Adata[i];
// 加算結果の下位1バイト
sum := sum and $000000FF;
// 2の補数
sum := (- sum and $000000FF);
// それを2バイトの ASCII コードに変換
chksum := IntToHex(sum, 2);
s := s + chksum; // チェックサム
s := s + CRLF; // 電文の最後
result := s;
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
// 過去にペアリングされたデバイスの一覧から、ターゲット を探す
APairedDevices := ABluetoothManager.GetPairedDevices;
if APairedDevices.Count > 0 then begin
idx := -1;
for i := 0 to APairedDevices.Count -1 do begin
Synchronize(procedure() begin
with Form4.ComboBox3 do begin
BeginUpdate;
Items.Add(APairedDevices[i].DeviceName );
EndUpdate;
end;
end);
if (BTDeviceHead = APairedDevices[i].DeviceName) then begin
Synchronize(procedure() begin
with Form4.ComboBox3 do begin
ItemIndex := i;
end;
end);
idx := i;
//break; // リストアップを続ける
end;
end;
if idx >= 0 then begin
ADevice := APairedDevices[idx];
if ADevice <> nil then begin
ASocket := ADevice.CreateClientSocket(StringToGUID(ServiceUUID), False);
if ASocket <> nil then begin
GCMDMODE := cmdSCCREATE;
// 接続
ASocket.Connect;
if ASocket.Connected then GCMDMODE := cmdSCCONNECT;
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 TForm4.InitTTS;
begin
tts := TJTextToSpeech.JavaClass.init(TAndroidHelper.Context, ttsListener);
end;
procedure TForm4.SpeakOut(const s : string);
var
text : JString;
begin
text := StringToJString(s);
tts.speak(text, TJTextToSpeech.JavaClass.QUEUE_FLUSH, nil);
end;
{ TForm4.TttsOnInitListener }
constructor TForm4.TttsOnInitListener.Create(AParent: TForm4);
begin
inherited Create;
FParent := AParent
end;
procedure TForm4.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');
end
else
ShowMessage('Initilization Failed!');
end;
constructor TForm4.Create(AOwner: TComponent);
begin
inherited;
ttsListener := TttsOnInitListener.Create(self);
end;
destructor TForm4.Destroy;
begin
if Assigned(tts) then begin
tts.stop;
tts.shutdown;
tts := nil;
end;
end;
// -----------------------------------------------------------------------------
function ASocketReceiveData(ASocket: TBluetoothSocket; ATimeout: Cardinal): string;
// SDC からの応答
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);
// 終端まで読む
if (AData[i] = $0A) {or (AData[i] = $03)} 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;
procedure TForm4.SPClick(Sender: TObject);
// SP 変更
var
AData : TBytes;
res, cmd, s : string;
ATimeout: Cardinal;
d : double;
begin
if (ASocket <> nil) and ASocket.Connected then begin
Timer1.Enabled := False;
ATimeout := 250;
d := StrToFloatDef(Label8.Text, 0);
cmd := 'WD238E' + IntToHex(Trunc(d * IntPower(10, decPt)), 4);
s := MakeCPLCommandStr(cmd);
AData := TEncoding.ANSI.GetBytes(s);
// 送信
ASocket.SendData(AData);
// 受信
res := ASocketReceiveData(ASocket, ATimeout);
if Copy(res, 6, 2) = '00' then
ToneGenerator.startTone(TJToneGenerator.JavaClass.TONE_PROP_ACK)
else
ToneGenerator.startTone(TJToneGenerator.JavaClass.TONE_PROP_NACK);
Timer1.Enabled := True;
end;
end;
procedure TForm4.Button1Click(Sender: TObject);
// Auto / Manual 反転
var
AData : TBytes;
res, cmd, s : string;
ATimeout: Cardinal;
begin
if (ASocket <> nil) and ASocket.Connected then begin
Timer1.Enabled := False;
ATimeout := 250;
if Pos('AUTO', Label5.Text) > 0 then begin
cmd := 'WU00'+ '3904' + '0001' + '3902' + IntToHex(Trunc(StrToFloatDef(Label19.Text, 0) * 10), 4);
end
else cmd := 'WD3904' + '0000';
s := MakeCPLCommandStr(cmd);
AData := TEncoding.ANSI.GetBytes(s);
// 送信
ASocket.SendData(AData);
// 受信
res := ASocketReceiveData(ASocket, ATimeout);
if Copy(res, 6, 2) = '00' then
ToneGenerator.startTone(TJToneGenerator.JavaClass.TONE_PROP_ACK)
else
ToneGenerator.startTone(TJToneGenerator.JavaClass.TONE_PROP_NACK);
Timer1.Enabled := True;
end;
end;
procedure TForm4.Button2Click(Sender: TObject);
// 接続先保存
var
IniFile: TMemIniFile;
begin
IniFile := TMemIniFile.Create(System.IOUtils.TPath.Combine(
System.IOUtils.TPath.GetDocumentsPath, 'azbilSDC.ini'), TEncoding.UTF8);
with IniFile do begin
try
with ComboBox3 do begin
if ItemIndex >= 0 then begin
WriteString('Target', 'DeviceName', Items[ItemIndex]);
ShowMessage('接続先: ' + Items[ItemIndex] + 'を保存しました.' + #13#10 +
'次回起動時から有効になります.' + #13#10 + 'このアプリを再起動して下さい.');
end
else
ShowMessage('接続先が選択されていません.');
end;
IniFile.UpdateFile;
finally
Free;
end;
end;
end;
procedure TForm4.MOUTClick(Sender: TObject);
// Manual OUT
var
AData : TBytes;
res, cmd, s : string;
ATimeout: Cardinal;
d : double;
begin
if (ASocket <> nil) and ASocket.Connected then begin
Timer1.Enabled := False;
ATimeout := 250;
d := StrToFloatDef(Label19.Text, 0);
cmd := 'WD3902' + IntToHex(Trunc(d * 10), 4);
s := MakeCPLCommandStr(cmd);
AData := TEncoding.ANSI.GetBytes(s);
// 送信
ASocket.SendData(AData);
// 受信
res := ASocketReceiveData(ASocket, ATimeout);
if Copy(res, 6, 2) = '00' then
ToneGenerator.startTone(TJToneGenerator.JavaClass.TONE_PROP_ACK)
else
ToneGenerator.startTone(TJToneGenerator.JavaClass.TONE_PROP_NACK);
Timer1.Enabled := True;
end;
end;
procedure TForm4.FormCreate(Sender: TObject);
var
IniFile: TMemIniFile; // uses .... System.IniFiles;
begin
Label1.Text := '';
Label2.Text := '';
Label3.Text := '';
Label4.Text := '';
Label5.Text := '';
Label6.Text := '';
Label7.Text := '';
Label8.Text := '';
Label19.Text := '';
// 縦画面に固定
Application.FormFactor.Orientations :=
[TFormOrientation.Portrait, TFormOrientation.InvertedPortrait];
// use ..... System.IOUtils;
IniFile := TMemIniFile.Create(System.IOUtils.TPath.Combine(
System.IOUtils.TPath.GetDocumentsPath, 'azbilSDC.ini'), TEncoding.UTF8);
with IniFile do begin
try
BtDeviceHead := ReadString('Target', 'DeviceName', 'EasyBT');
finally
Free;
end;
end;
// TTS
InitTTS;
// ブザー
ToneGenerator := TJToneGenerator.JavaClass.init(
TJAudioManager.JavaClass.STREAM_ALARM,
TJToneGenerator.JavaClass.MAX_VOLUME);
// Bruetooth スレッド
Timer1.Interval := 10;
Timer1.Enabled := True;
ThBt := TBtThread.Create;
end;
procedure TForm4.FormDestroy(Sender: TObject);
begin
if ASocket <> nil then begin
ASocket.Close;
ASocket.Free;
ASocket := nil;
end;
end;
procedure TForm4.Rectangle14Click(Sender: TObject);
// Manual OUT UP / DOWN
var
mout : double;
d : double;
begin
mout := StrToFloatDef(Label19.Text, 0);
if Sender as TRectangle = Rectangle14 then
d := StrToFloatDef(Label13.Text, 0)
else
d := StrToFloatDef(Label20.Text, 0);
mout := mout + d;
if mout < 0 then mout := 0
else if mout > 100 then mout := 100;
Label19.Text := Format('%.1f', [mout]);
end;
procedure TForm4.Rectangle7Click(Sender: TObject);
// SP UP / DOWN
var
sp : double;
d : double;
fmt : string;
begin
fmt := '%.' + decPt.ToString + 'f';
sp := StrToFloatDef(Label8.Text, 25);
if Sender as TRectangle = Rectangle7 then
d := StrToFloatDef(Label9.Text, 0)
else if Sender as TRectangle = Rectangle10 then
d := StrToFloatDef(Label10.Text, 0)
else if Sender as TRectangle = Rectangle11 then
d := StrToFloatDef(Label12.Text, 0)
else
d := StrToFloatDef(Label18.Text, 0);
sp := sp + d;
Label8.Text := Format(fmt, [sp]);
end;
procedure TForm4.Timer1Timer(Sender: TObject);
var
ATimeout : Cardinal;
AData : TBytes;
i : integer;
s, cmd, rcv : string;
fmt : string;
Ticks : Cardinal;
sw : integer;
begin
if not ((GCMDMODE = cmdSCCONNECT) and ASocket.Connected) then begin
Inc(OpenMsecCnt);
Label7.Text := IntToStr(OpenMsecCnt * 10) + ' msec';
if GCMDMODE = cmdSCNG then begin
Inc(OpenNgCnt);
if OpenNgCnt > 4 then begin
Timer1.Enabled := False;
ShowMessage(BTDeviceHead + ' に、接続できません.');
end;
end;
if OpenMsecCnt > 100 then begin
Timer1.Enabled := False;
ShowMessage('接続先が無効です.');
end;
end;
if (GCMDMODE = cmdSCCONNECT) and ASocket.Connected then begin
Timer1.Interval := 250;
Timer1.Enabled := False;
Ticks := TThread.GetTickCount;
ATimeout := 250;
cmd := 'RU00' +'1454'+ '3814' + '3815' + '3816' + '3851' + '3811' + '3902';
s := MakeCPLCommandStr(cmd);
AData := TEncoding.ANSI.GetBytes(s);
// 送信
ASocket.SendData(AData);
// 受信
rcv := ASocketReceiveData(ASocket, ATimeout);
if (Copy(rcv, 6, 2) = '00') and (Length(Copy(rcv, 8)) >= 28) then begin
for i := 0 to 6 do begin
s := Copy(rcv, 8 + i * 4, 4);
if i = 0 then begin
decPt := StrToIntDef('$' + s, 0);
decScale := 1 / IntPower(10, decPt);
if decPt > 0 then begin
Label18.Text := '+0.5';
Label9.Text := '-0.5';
end
else begin
Label18.Text := '+1';
Label9.Text := '-1';
end;
end
else begin
fmt := '%.' + decPt.ToString + 'f ';
case i of
// PV
1: Label1.Text := Format(fmt, [StrToInt('$' + s) * decScale]);
// SP
2: begin
s := Format(fmt, [StrToInt('$' + s) * decScale]);
if (Label2.Text = '') and (Label8.Text = '') then Label8.Text := Trim(s);
Label2.Text := s;
end;
// OUT
3: Label3.Text := Format('%.1f ', [StrToInt('$' + s) * 0.1]);
// MFB
4: Label4.Text := Format('%.1f ', [StrToInt('$' + s) * 0.1]);
// Auto / Man
5: if StrToInt('$' + s) = 1 then begin
if Label5.Text <> 'MANUAL ' then begin
Label5.Text := 'MANUAL ';
Label5.TextSettings.FontColor := claRed;
Label6.TextSettings.FontColor := claRed;
Label3.TextSettings.FontColor := claRed;
end;
end
else begin
if Label5.Text <> 'AUTO ' then begin
Label5.Text := 'AUTO ';
Label5.TextSettings.FontColor := claSpringgreen;
Label6.TextSettings.FontColor := claSpringgreen;
Label3.TextSettings.FontColor := claSpringgreen;
end;
end;
// MAN Out
6: begin
s := Format('%.1f ', [StrToInt('$' + s) * 0.1]);
if Label19.Text = '' then Label19.Text := Trim(s);
Label6.Text := s;
end;
end;
end;
end;
end;
cmd := 'RD' +'23F4'+ '0002';
s := MakeCPLCommandStr(cmd);
AData := TEncoding.ANSI.GetBytes(s);
// 送信
ASocket.SendData(AData);
// 受信
rcv := ASocketReceiveData(ASocket, ATimeout);
if (Copy(rcv, 6, 2) = '00') and (Length(Copy(rcv, 8)) >= 8) then begin
for i := 0 to 1 do begin
sw := StrToIntDef('$' + Copy(rcv, 8 + i * 4, 4), 0);
if i = 0 then begin
// MANUAL mode
with Label22.TextSettings do begin
if sw and 1 = 1 then begin
if FontColor <> claSpringgreen then FontColor := claSpringgreen;
end
else begin
if FontColor <> claGray then FontColor := claGray;
end;
end;
// RSP mode
with Label23.TextSettings do begin
if sw and 4 = 4 then begin
if FontColor <> claSpringgreen then FontColor := claSpringgreen;
end
else begin
if FontColor <> claGray then FontColor := claGray;
end;
end;
end
else begin
// OUT 1
with Label27.TextSettings do begin
if sw and 1 = 1 then begin
if FontColor <> claSpringgreen then FontColor := claSpringgreen;
end
else begin
if FontColor <> claGray then FontColor := claGray;
end;
end;
// OUT 2
with Label28.TextSettings do begin
if sw and 2 = 2 then begin
if FontColor <> claSpringgreen then FontColor := claSpringgreen;
end
else begin
if FontColor <> claGray then FontColor := claGray;
end;
end;
// EV1
with Label24.TextSettings do begin
if sw and 4 = 4 then begin
if FontColor <> claRed then FontColor := claRed;
end
else begin
if FontColor <> claGray then FontColor := claGray;
end;
end;
// EV2
with Label25.TextSettings do begin
if sw and 8 = 8 then begin
if FontColor <> claRed then FontColor := claRed;
end
else begin
if FontColor <> claGray then FontColor := claGray;
end;
end;
// EV3
with Label26.TextSettings do begin
if sw and 16 = 16 then begin
if FontColor <> claRed then FontColor := claRed;
end
else begin
if FontColor <> claGray then FontColor := claGray;
end;
end;
end;
end;
end;
Label7.Text := IntToStr(TThread.GetTickCount - Ticks) + ' msec';
// テキストスピーチ
Inc(TTScnt);
if TTScnt > 10 then begin
TTScnt := 0;
s := '';
if Switch1.IsChecked then s := s + 'PV ' + Label1.Text + #13;
if Switch2.IsChecked then s := s + 'MFB ' + Label4.Text + ' ';
if s <> '' then SpeakOut(s);
end;
Timer1.Enabled := True;
end;
end;
end.