ステッピングモーターの制御

  ステッピングモーター、あるいは、サーボモーターの制御は、メカコントロールで必ずといって必要になるものです。
制御方法としては、シーケンサー、ステッピングモーターコントローラー、PCIボードモーターコントローラ等を利用して、モーター制御用のクロック信号を作り出し、そのクロック信号によりステッピングモーター、あるいは、サーボーモーターのドライバーでモーターの巻き線に電流を流し、モーターの回転子を回転させる方法があります。
 プログラムを組む上では、モーターの回転子を一回転させるのに、何パルス必要なのか、移動させるものがある場合は、単位移動距離の移動に何パルス必要かがわかれば、モーターを回転させるための仕組みはあまり知る必要は有りませんが、モーターで、何かを移動させる場合、必ず負荷が存在し、負荷には、摩擦負荷と、加減速による慣性負荷が存在するので、モーターの出力に対して、負荷が越えないようにする必要があります。
  負荷として、摩擦による負荷の発生率が高い場合、摩擦負荷の変動に注意を払う必要があります。特に粘性係数を持つ負荷の場合は、速度によって負荷が大きく変動するので注意しましょう。
 慣性モーメントは、計算により求める事が出来るので、メカ設計時に計算をしておきます。
 メカの設計を行う場合、摩擦負荷の予測は可なり難しく、摩擦負荷を伴う場合は、安全率を高くしてモーターの選択を行う必要があります。
モーターが正常に回転しない場合、ソフトの問題なのか、負荷に対してモーターの出力が足りないのか判別が難しくなる場合があります、コストを安くするために、特にステッピングモーターのドライバーをクロックで直接モーターの電流を制御するタイプは、衝撃荷重や、共振により脱調し、回転不良が発生する確率が高くなるので、荷重に対して安全率を高く設定する必要があります。
 現在は、ステッピングモーターでも、各相に対する流す電流を制御し、磁極が増えたのかのように見せかけて駆動する、マイクロステップ、パルスエンコーダーを持ち、回転を検出して、脱調しないようにしたものがありますが、高価です、又、回転パルスを検出しながら回転させるため、与えたクロックに対して、リアルタイムに動作するのではなくて、数パルスから数十パルス以上遅れて動作するのが普通です。(”パルス溜まり” と呼ばれることもあります)
 サーボモーターのドライバーも、ステッピングモーターの様に、クロックを与えることにより、クロックに同期して回転を行うドライバーが一般的になっていますので、同じモーターコントローラーで、どちらでも制御をする事が出来ます。
モータードライバーも、内部にCPUを持ち入力されたクロックにより、モーターの電流をどのように切替えるかを演算し、コントロールするタイプが一般的になっています、特にサーボモーターは、入力されたクロックよりも数倍、あるいは十倍以上の精度のパルスエンコーダーを内蔵しているので、ギヤ比として、入力クロック数と、パルスエンコーダーの比を演算し、モーターのエンコーダークロック数を決めて回転制御を行います。
又、サーボモーターの場合は、静止させる場合、少しでもずれたら位置を戻そうとすると、メカの弾性係数、制御の演算遅れ等により発信する場合があるので、ある程度の誤差は許容するようにします。
 脱調レスステッピングモーター、或いは、サーボーモーターのドライバーには、パルス溜まりが発生し、制御遅れが発生するので、位置制御をする場合は注意が必要です、目標位置に達したかを出力する信号を持っているものであれば、必ずその信号を確認する必要があります。

 モーターの立ち上げ時の立ち上げカーブとして、直線的に立ち上げるか、加速度を変更する時に、徐々に変更する方式があります。
立上げカーブ
徐々に変更すると、立ち上げ立ち下げカーブが S 字型になります。
加速度を急激に変更すると、その時に振動が発生したり、脱調現象が発生したりするので、滑らかに変更する為です。
滑らかに変更するためには、浮動小数点の計算、関数計算が必要なため、安価なシーケンサーには用意されていない場合があります。

コントローラーの基準クロック周波数の影響
 コントローラーのモータークロックを発生するための基準クロック周波数が仕様として記載されていないものが多く、問題があります。
モーター用のクロックは、基準クロックを分周して作り出す為、モータークロックの周波数が高くなると、目的の周波数に対して、発生できる周波数の誤差が大きくなるます。
必要な周波数を発生させるのに、基準クロックを必要な周波数で割った値が整数とならない場合は、必ず誤差が発生します。
基準クロックが1MHzとして、必要な周波数が1KHz近辺とすると、最大0.1%の誤差となり、10KHz近辺だと1%(100Hz)の誤差となります。
ステッピングモーターは、高速時には、トルクが減少するので、立上げ途中の周波数に計算誤差が大きくなるのは、致命的な問題となります。

ステッピングモーターの連続運転
 ステッピングモーターを高速で連続運転すると、鉄損が増大し、発熱が非常に大きくなります。
最近は、サーボモーターの様に回転を検出し、トルクを電流によりコントロールして発熱を抑えたものもあります。
目的にあった駆動回路の選択が必要です。

モーターの回転条件設定
 1.
初期速度
 2.立上がり加速度
 3.立下り加速度
 4.目標速度
 5.加減速カーブ
6.ゲイン)
7.微積分定数)
8.ギヤ比)
括弧内は、ドライバーでの設定、それ以外は、シーケンサー、コントローラーでの設定となります。


オリエンタルモーター EMP402
(株)メレック MPL28 CB23/USB
(株)コスモテックス USPG-48(F)
    について



オリエンタルモーターのストアードプログラム型コントローラ EMP402の使用例

 このコントローラーは、32種類の動作プログラムを1000ステップまで入力が可能です、又ダイレクトにコマンドの実行も可能です。
プログラムは、Windows標準のハイパーターミナルとなっていますが、WINXP以降はハイパーターミナルはありません、インターネットで検索しインストールする必要があります。
Tera Term が推奨です、使用例も検索できるので参考にして下さい。

Windows XPがある場合は、XPから下記四個のファィルを
   1) C:¥Program Files¥Windows NT¥HYPERTRM.EXE
   2) C:¥Windows¥Help¥HYPERTRM.CHM
   3) C:¥Windows¥Help¥HYPERTRM.HLP
   4) C:¥Windows¥System32¥hypertrm.dll
 新しいフォルダーをWIN7、8.1 に作成しその中に全てコピーします。
 HYPERTRM.EXEの プログラムのショートカットを作りますすす
 HYPERTRM.EXEを起動すると、規定のプログラムにするかどうかダイアログが出ますが、どちらを選んでも構いません。
 その後名前を付けるダイアログが出ますがアイコンが無いので、とにかく名前だけ付けて起動します。
 その後は、XPの時と同じ操作です。
*HYPERTRMを起動すると、プログラムメニューに、新しく アクセサリ¥通信¥ハイパーターミナルという名前のホルダーが作成され、その中に設定ファイルが保存されますが、XPの様に起動アイコンは作成されないので、そこからは起動できません。
ファイルの保存を選択し、別のホルダーへ保存すると、ハイパーターミナルのホルダーは空のホルダーになります。
前の条件でHYPERTRMを起動したい場合は、起動後に名前とアイコン選択のダイアログが表示されますが、CANCELを選択し、ファイルを開くで、前に保存した設定ファイル(.ht)を選択して開きます。
XPのシステムから、抜き出してWIN7、8.1等で使用するのは、著作権の問題があると思います、あくまでも自己責任でお願いします。
ハイパーターミナルの製作は、Hilgraeveとなっており、WIN7、8.1用は有料となっています。

此処での使用例は、ストアードプログラムは全く使用せず、全てパソコンからのコマンドで実行する場合です。
Delphiで動作させるのに、ハイパーターミナルは必要ありませんが、EMP402の条件設定に使用します。
本ホームページでダウンロード出来るRS232C通信プログラムでも、条件設定、プログラムの書き込み、ダイレクトモードでの動作は可能です。

 EMP402は、32種類のプログラムを組むことが出来ますが、単純な移動を繰り返すのには良いのですが、パソコンで細かい動作をさせるのにはあまり向いていません。
しかし、オリエンタルの電動スライダーを動作させるのに、接続ケーブル類が充実しているので、配線の手間を可なり省くことが出来ます。
パソコンで、細かい制御をするのには、多少コマンドが不足しているので、INポートを利用して、不足分を補います。
使用説明書は、オリエンタルモーターのホームページからダウンロードして下さい。(ユーザー登録が必要です)

 次の図はEMP402に二種類の電動スライダーを接続した場合の接続例です。
スライダーの駆動には、ステッピングモーターが使用されています。
オリエンタルモーターの接続例に対して、出力READY、E-STOP、ALMを、IN1、IN2、IN3にそれぞれ接続しています、これは通信で、動作完了、緊急停止、アラームを検出する為です。
二つのスライダーに対し、一つの状態出力しか無い為、マルチに動作させるのには向いていません。
本例の場合は、逆に同時に動作させると問題が発生するので、マルチに動作しないほうが良い場合の使用例です。
二軸の補間移動、直線の二軸補間はありますが、プログラムモードでしか使用出来ませんので、細かい動作は出来ません、円弧の補間動作が必要な場合は、他社のコントローラーが必要です。
EMP400-1EMP400-2EMP400-3EMP400-4EMP400-5

COMポートの設定
 
 通信コマンドにより動作する場合は、普通は通信エラーチェックの為チェックサムコード、ブロックチェックキャラクタ等で通信エラーを確認するのですが、ハイパーターミナルの仕様となっているのでエコーバックにより確認をします。
更に最後に送られてくる文字コードが ">" greater-than sign #62 となっているので、これを受信割り込みに設定します。

XZ軸コントロールコマンド送信処理
 XZControl; (モーターコントロール XZ)のルーチンをタイマーで一定間隔で呼び出すことにより、処理を行います。
STOPコマンド以外は、フラグをたて、そのフラグにより XZControl ルーチンで処理されます。
スライダーの移動処理コマンドがが無い場合は、ポートの入力状態を常時チェックします。
コマンドを送信した場合の受信確認エラーチェックは、エコーバックで確認していますが、送信したコマンドの内容全てではなく、コマンド文字だけでコマンドに続くデーターの確認はしていませんが、実使用で問題が出た事は有りません。
又、エコーバック受信確認後、次のコマンド送信の間に、必ず一定間隔以上のあき時間を設けています。これは、受信確認と、送信用タイマーのタイミングによっては、コントローラーの実行遅れにより次のコマンドが正しく実行されなくなるのを防止するためです。(受信処理後タイマーの呼び出しを1回パスする)
EMP402には、位置情報だけを取得するコマンドがありません、全体状態を読み出すコマンドがあるので、それを利用して位置情報を取得しますが、通信データー量が多いため、読み出すのに時間が掛かります。

次のプログラム例は、全てではなく、通信部分だけを取り出しています。
移動の制御は別のルーチンで行いますが、同じタイマーで呼び出すことにより、順次実行されます。

 {
***************************************************************************************
オリエンタル 402 コントローラー設定値
Z軸
  ID1 = 06103100001000 (ID1,06103100001000)
  ACTL1 = 0,0,0,1,1
X軸
  ID2 = 05103100001000 (ID2,05103100001000)
  ACTL2 = 0,0,0,1,1
***************************************************************************************
}




var
// ------------- XZ 電動スライダー --------------- 
  XZTimeOutCount  : Cardinal;       // 送信エコータイムアウトカウンター
  XZTimeOutFL     : Boolean;        // タイムアウトFlag
  XZReset         : Boolean;        // リセット送信済みフラグ
  XZReady         : Boolean;        // XZ軸レディフラグ
  XZALM           : Boolean;        // XZ軸アラーム
  XALM            : Boolean;        // X軸アラーム
  ZALM            : Boolean;        // Z軸アラーム
  XZEstop         : Boolean;        // 緊急停止
  XHomeReady      : Boolean;        // X軸ホーム完了
  ZHomeReady      : Boolean;        // Z軸ホーム完了
  XFreeFl         : Boolean;        // X軸フリーにしたフラグ
  XPLM            : Boolean;        // X軸+リミット
  XMLM            : Boolean;        // X軸-リミット
  ZPLM            : Boolean;        // Z軸+リミット
  ZMLM            : Boolean;        // Z軸-リミット
  XVPosition      : Double;         // Xデーターセット
  ZVPosition      : Double;         // Zデーターセット
  XVSpeed         : Cardinal;       // X軸速度
  ZVSpeed         : Cardinal;       // Z軸速度
  OutXZSTR        : String;         // OutPortString
  XPosition       : Double;         // X軸位置データー確認用
  ZPosition       : Double;         // Z軸位置データー確認用
  XZCOMMOPENFL    : Boolean;        // 通信ポートオープンフラグ
  XZSendF         : DWord;          // 送信フラグ
  ZXCOTWait       : Boolean;        // True でone wait;
  ZVSSpeed        : integer;        // Z軸起動速度
  ZTSpeed         : Double;         // Z軸加速度
  ZRAMPTime       : Double;         // Z軸ランプタイム 0.1 刻み

      //   $8000 $4000 $2000 $1000 $800  $400 $200 $100 $80  $40     $20  $10  $8  $4   $2    $1
      // Bit15   14    13    12     11    10,  9,   8,   7,   6        5,  4,   3,  2,   1,    0,
      // Ranp    T     R   XHomerz X=0Z=1 Out VS    D  SendF ResetHome V   ABS  H,- D,+  MHome In

const

  ZLowConst       = 1000;            // Z軸低速
  ZXHighConst     = 10000;           // Z軸高速
  ZVMeasureConst  = 3000;            // Z軸測定時速度
  ZVHiDownConst   = 4000;            // Z軸高速低下速度
  ZVSLowSpeed     = 20;              // Z軸起動速度
  ZVSBase         = 600;             // Z軸初期速度
  ZTLowSpeedConst = 200;             // Z軸測定時加速度 時間長
  ZTbase          = 50;              // Z軸加速度初期値 時間単
  ArMax           = 50000;           // Ar軸最高速度
  ZLanpLongConst  = 200;             // Lamp時間長
  ZLanpShort      = 50;              // Lamp時間短

  XLowConst       = 1000;            // X軸低速
  XVSSPEED        = 500;             // X軸起動速度

  ShortWait       = 10;              // STOP送信待ち合わせ時間

// ****************************** ディレー タイマー *****************************************

procedure TOrientalF.Delay(dtime: Cardinal);  // 遅延タイマー
var
  starttime: Cardinal;
  endtime: Cardinal;
  BreakTime: Cardinal;
begin
  BreakTime := 0;                              // BreakTime初期化
  starttime := TimeGetTime;
  while BreakTime < dtime do                  // 設定時間以下ならループする
    begin
      Application.ProcessMessages;
      EndTime := TimeGetTime;
      if EndTime >= StartTime then             // スタート時間と取得時間により経過時間計算法選択
          BreakTime := EndTime - StartTime     // ブレーク時間計算
        else
          BreakTime := not StartTime + EndTime + 1;    // スタート時間より取得時間が小さい場合
   end;                                                // タイマーカウンターが一周している
end;


// ********************** IOF.LoopTimer ***************************
// タイマーにより16㍉秒~20㍉秒程度の間隔で実行する。
procedure TOrientalF.Controltimersub; 	//タイマーサブルーチン
begin
  XZControl; 				// モーターコントロール XZ
 *********;				// モーターコントロール以外も同じタイマー呼び出し動作の制御を行います。
      |
 *********;
end;


//----------------------- 電動スライダーコントローラ 通信処理 ------


// RS232C Commポートオープン
function TOrientalF.XZSLDCOMMOPEN:Boolean;
begin
  Result := True;
  try
    COMM4.Port := 4;                   	// ポート番号 4
    COMM4.BaudRated := User_BaudRate;  	// ユーザーボーレート
    COMM4.BaudRate := 9600;            	// 9600 ボー
    COMM4.FlowControls := [];          	// フローコントロール無し

    COMM4.EventMask := [evRxflag];     	// 受信割り込みフラグ使用
    COMM4.RxflagReceive := eventOn;    	// 割り込み使用
    COMM4.EventFlag := UserIn;         	// ユーザー指定フラグ使用
    COMM4.EventFlagin := #62; 	  	// フラグ文字 '>'


//    COMM4.EventMask := [evRxchar];
//    COMM4.RxflagReceive := eventOff;
    COMM4.ByteSize := cbs8; 		// データー 8 ビット
    COMM4.StopBits := csb1; 		// ストップビット 1 ビット
    COMM4.ParityBits := cpbNone; 		// パリティ無し
    COMM4.Open;
  except
    Application.MessageBox('電動スライダー通信ポート(COMM4) オープンエラーです。','確認',MB_OK);
    Result := False;
  end;
end;

procedure TOrientalF.XZSLDCommClose; 	// Comm4 ポートクローズ
begin
  COMM4.Close; 				// Comm4 close
  XZCOMMOPENFL := False; 			// ポートオープンフラグリセット
end;

// ===================== XZ軸コントロールコマンド送信処理 ====================
procedure TOrientalF.XZControl; 		// モーターコントロール XZ
label
  Axis2,Common;
const
  AllFlag = $02 + $04 + $08 + $10 + $20 + $100 + $200 + $800 +$1000 + $2000 + $4000 + $8000; // 全コマンド IN OUT RESET 除く
var
  TempStr : string;
begin
  if not XZCOMMOPENFL then exit; 		// 通信ポートがOPENされていなければ終了
  if XZTimeOutCount < MTimeOutP1 then inc(XZTimeOutCount) 	// タイムアウトカウンターインクリメント
			     else exit;
  if XZTimeOutCount = PreTimeout then
	XZSendF := XZSendF and (MAXDWORD - $81); 		// PreTimeoutになったら一度送信フラグ解除し通信再開ここみる
  if (XZTimeOutCount > MTimeOut) or XZEstop or XALM or ZALM then 	// タイムアウトになったら
    begin
       XZTimeOutFL := True; 		// タイムアウトフラグセット
       XZReady := False; 			// レディフラグリセット
       XZReset := False; 			// XZリセット済みフラグリセット
       exit; 				// 此処まで
    end;
  if ZXCOTWait then 			// One wait Trueだったら一回パスする
    begin
      ZXCOTWait := False;
      exit;
    end;
  if XZSendF and $80 > 0 then exit; 	// 未受信なら此処まで
  if XZSendF and $40 > 0 then 		// リセット送信
    begin
      XZSendF := XZSendF or $1000; 		// X軸ホーム予約 送信フラグセット
      XZSendF := XZSendF or $80; 		// 送信フラグセット
      Comm4.SendString('RESET' + #13#10); 	// リセット実行送信
      XHomeReady := False; 			// Xホームフラグリセット
      ZHomeReady := False; 			// Zホームフラグリセット
      XZReset := False; 			// リセットフラグリセット
      if not MXZResetFL then MXZResetIn := 3; 	// MXZResetIn 0 以外順次中フラグ
      exit; 				// 此処まで
    end;
  if not XZReSet then exit; 		// リセットされていなかったら此処まで
  if XZSendF and AllFlag = 0 then goto Common; 	// コマンドフラグ無かったらI/0 Commomへ

  if XZSendF and $800 = 0 then goto Axis2; 	// Axis1 Z軸でなかったら Axis2 X軸へ

// --------------- Z軸コントロール -------------------------
  if XZSendF and $02 = $02 then 		// MHome1 送信
    begin
      XZSendF := XZSendF or $80; 		// 送信済みフラグセット
      Comm4.SendString('MHOME1' + #13#10); 	// MHOME1 ホーム位置初期化送信
      if not MXZResetFL then MXZResetIn := 7; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $08 = $08 then 		// Z H1,- 送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString('H1,-' + #13#10);
      if not MXZResetFL then MXZResetIn := 5; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $04 = $04 then 		// D1,DATA 送信
    begin
      XZSendF := XZSendF or $80;
      TempStr := floatTostr(SimpleRoundTo(ZVPosition, -2)); 	// 小数点以下2桁に丸める
      TempStr := Copy(TempStr,1,8);
      Comm4.SendString(AnsiString('D1,+' + TempStr + #13#10));
      if MZMOVEFL then MZMOVEin := 2; 	// Z軸順次制御フラグ
      exit;
    end;
  if XZSendF and $10 = $10 then 		// ABS1, アブソリュート移動送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString('ABS1' + #13#10);
      if MZMOVEFL then MZMOVEin := 4; 	// Z軸順次制御フラグ
      exit;
    end;
  if XZSendF and $20 = $20 then 		// V1,移動速度送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString(('V1,' + intTostr(ZVSpeed) + #13#10)));
      exit;
    end;
  if XZSendF and $100 = $100 then 		// D1, 設定位置読み出し送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString('D1' + #13#10);
      if not MXZResetFL then MXZResetIn := 10; // MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $200 = $200 then 		// VS1, 起動速度送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString('VS1,' + intTostr(ZVSSpeed) +#13#10));
      exit;
    end;
  if XZSendF and $2000 = $2000 then 	// R1, データーリクエスト送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString('R1' + #13#10));
      exit;
    end;
  if XZSendF and $4000 = $4000 then 	// Z軸加速度送信
    begin
      XZSendF := XZSendF or $80;
      TempStr := floatTostr(SimpleRoundTo(ZTSpeed, -1)); // 小数点以下1桁に丸める
      TempStr := Copy(TempStr,1,6);
      Comm4.SendString(AnsiString('T1,' + TempStr + #13#10));
      exit;
    end;
  if XZSendF and $8000 = $8000 then 	// RAMP1送信
    begin
      XZSendF := XZSendF or $80;
      TempStr := floatTostr(SimpleRoundTo(ZRAMPTime, -1)); 	// 小数点以下1桁に丸める
      TempStr := Copy(TempStr,1,7);
      Comm4.SendString(AnsiString('RAMP1,1,' + TempStr + #13#10)); 	// Ramp
      exit;
    end;

// ---------------- X軸コントロール -----------------
Axis2:
  if XZSendF and $02 = $02 then 		// MHome2 送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString(('MHOME2' + #13#10)));
      if not MXZResetFL then MXZResetIn := 14; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $08 = $08 then 		// X H2,- 送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString('H2,-' + #13#10);
      if not MXZResetFL then MXZResetIn := 12; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $04 = $04 then 		// D2,DATA 送信
    begin
      XZSendF := XZSendF or $80;
      TempStr := floatTostr(SimpleRoundTo(XVPosition, -2)); 	// 小数点以下2桁に丸める
      TempStr := Copy(TempStr,1,8);
      Comm4.SendString(AnsiString('D2,+' + TempStr + #13#10));
      if MXMOVEFL then MXMOVEin := 2; 	// X軸順次制御フラグ
      exit;
    end;
  if XZSendF and $10 = $10 then 		// ABS2, アブソリュート移動送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString('ABS2' + #13#10));
      if MXMOVEFL then MXMOVEin := 4; 	// X軸順次制御フラグ
      exit;
    end;
  if XZSendF and $20 = $20 then 		// V2,送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString('V2,' + intTostr(XVSpeed) + #13#10));
      exit;
    end;
  if XZSendF and $100 = $100 then 		// D2, 送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString('D2' + #13#10));
      if not MXZResetFL then MXZResetIn := 17; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $200 = $200 then 		// VS2, 起動速度送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString('VS2,' + intTostr(XVSSpeed) + #13#10));
      exit;
    end;
  if XZSendF and $2000 = $2000 then 	// R2, 送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString('R2' + #13#10));
      exit;
    end;

// ---------------------------- 共通 IN OUT -------------------------------
Common:
// I/O out
  if XZSendF and $400 > 0 then 		// OUT 送信
    begin
      XZSendF := XZSendF or $80;
      Comm4.SendString(AnsiString('OUT,' + OutXZSTR + #13#10)); // OutXZSTR = 'XXXXXX' X='0' or X='1'
      exit;
    end;
// I/O in
  if XZSendF and (MAXDWORD - $1000 - $800) = 0 then 	// $1000 は X軸Home 予約
    begin
      XZSendF := XZSendF or $81;
      BufS := ''; 				// 受信バッファクリア
      Comm4.SendString(AnsiString('IN' + #13#10));
    end;
end;

// =============== 電動スライダーコントローラ 通信受信処理 ====================
procedure TOrientalF.Comm4CommReceive(Sender: TObject; Size: Cardinal);
label
  Axis2;
var
  Buf: Pansichar;
  I,Leng,ILeng: integer;
  checkStr: string;
  inBufstr: string;
const
  AllFlag = $02 + $04 + $08 + $10 + $20 + $40 + $100 + $200 + $2000 + $4000 + $8000 + $80; // 全コマンド IN OUT RESET 除く
begin
  XZTimeOutCount := 0; 			// タイムアウトタイマーリセット
  Buf := AllocMEM(Size + 1); 		// バッファメモリー取得
  Comm4.Read(Buf,Size); 			// データー読み込み
  inBufstr := string(Buf); 			// checkStrにコピー
  FreeMem(Buf,Size + 1); 			// バッファメモリー開放
  BufS := BufS + inBufstr; 			// 読み込み文字加算処理
  Leng := Length(BufS) - 1; 		// 文字長さ取得1小さくする
  inBufstr := ''; 				// 文字クリア
  checkStr := ''; 				// 文字クリア
  if Leng > 0 then 			// 受信文字があったら
    for I := Leng downto 1 do 		// '0>' 位置確認
      begin
        checkStr := copy(BufS,I,2); 		// 二文字取得
        if checkStr = '0>' then 		// '0>' だったら
          begin
            if I < Leng then 		// 二文字数以上小さい場合
              begin
                inBufstr := copy(BufS,1,I + 1); 	// バッファより先頭からI+1文字数コピー
                BufS := copy(BufS,I + 2,Leng - I); 	// バッファより残りの文字数コピー
              end
              else
              begin 			// 文字長さとIが等しい場合
                inBufstr := BufS; 		// バッファをコピー
                BufS := ''; 		// ブッファクリア
              end;
            Break; 			// for 終了
          end;
      end;
  if checkStr <> '0>' then exit; 		// '0>'がなかったら終了
  if OrientalF.Visible then 		// フォームが表示されていたら受信内容表示
    begin
      Comm4Memo.Clear; 			// Memo クリア
      Comm4Memo.Lines.Add(inBufstr); 	// inBufstr 表示
    end;
  if (Leng > 35) and (Leng < 300) then 	// 文字長さが 30~ 300 なら
    begin
      checkStr := copy(inBufstr,5,28); 	// 5番目から28文字取り出し
      if checkStr = ' * E-STOP switch active.' then 	// E-STOPなら
        begin
          XZEstop := True; 			// EStop フラグセット
          BufS := '';
          XZSendF := 0; 			// 送信フラグリセット
          ZXCOTWait := True; 		// True でone wait;
          exit;
        end;
      if checkStr = ' * S-STOP switch active.' then 	// S-STOPなら
        begin
          BufS := '';
          XZSendF := 0; 			// 送信フラグリセット
          ZXCOTWait := True; 		// True でone wait;
          exit;
        end;
      checkStr := copy(inBufstr,5,30);
      if checkStr = ' * CW limit switch active.' then 	// CW limit
        begin
          if XZSendF and $800 = $800 then ZPLM := True 	// Z軸 +リミットフラグセット
				 else XPLM := True; 	// X軸 +リミットフラグセット
          BufS := '';
          XZSendF := 0; 			// 送信フラグリセット
          ZXCOTWait := True;
          exit;
        end;
      if checkStr = ' * CCW limit switch active' then 	// CCW limit
        begin
          if XZSendF and $800 = $800 then ZMLM := True 	// Z軸 -リミットフラグセット
				 else XMLM := True; 	// X軸 -リミットフラグセット
          BufS := '';
          XZSendF := 0; 			// 送信フラグリセット
          ZXCOTWait := True;
          exit;
        end;
      if checkStr = ' * Driver alarm. ->axis1 ' then
        begin
          ZALM := True; 			// Z軸 アラームフラグセット
          XZSendF := 0; 			// 送信フラグリセット
          BufS := '';
          ZXCOTWait := True;
          exit;
        end;
      if checkStr = ' * Driver alarm. ->axis2 ' then
        begin
          XALM := True; 			// X軸 アラームフラグセット
          XZSendF := 0; 			// 送信フラグリセット
          BufS := '';
          ZXCOTWait := True;
          exit;
        end;
    end;
// ------ INポート処理 データーによりフラグセット ------
  if XZSendF and $81 = $81 then 		// IN
    begin
      checkStr := copy(inBufstr,1,2); 	// 先頭二文字
      if checkStr <> 'IN' then 		// 'IN'でないなら終了 
        begin
          BufS := ''; 			// バッファ文字クリア
          ZXCOTWait := True; 		// True でone wait;
          XZSendF := XZSendF and (MAXDWORD - $81); 	// フラグ解除
          exit;
        end;
      if inBufstr[22] = '1' then 		// Ready チェック IN1
        begin
          if XZSendF and $800 = $800 then
            begin 			// Z軸フラグだったら
              if not ZHomeReady then
                begin
                  XZSendF := XZSendF or $100; 		// D1,問い合わせフラグセット続いてXMOHOEを行う
                  if not MXZResetFL then MXZResetIn := 9; 	// MXZResetIn 0 以外順次中フラグ
                end;
            end
            else
            begin 			// X軸なら
              if not XHomeReady then
                begin
                  XZSendF := XZSendF or $100; // D2問い合わせ
                  if not MXZResetFL then MXZResetIn := 16; 	// MXZResetIn 0 以外順次中フラグ
                end;
            end;
          if (MZMOVEin = 5) then MZMOVEin := 6; 		// Z軸順次制御フラグ
          if (MXMOVEin = 5) then MXMOVEin := 6; 		// X軸順次制御フラグ
          XZReady := True; 			// XZ 402 レディフラグセット
        end
        else XZReady := False; 		// XZ 402 NOTレディフラグセット
      if inBufstr[21] = '0' then XZEstop := True 		// EStop IN2
		          else XZEstop := False;
      if inBufstr[20] = '0' then XZALM := True 		// ALM IN3
		          else XZALM := False;
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $81); 		// 'IN'フラグ解除
      exit;
    end;
  if XZSendF and $C0 = $C0 then 		// Reset
    begin
      checkStr := copy(inBufstr,1,5);
      if checkStr <> 'RESET' then exit; 	// 通信確認用
      XZReady := False; 			// XZ軸レディリセット
      XHomeReady := False; 			// X軸ホームセット済みフラグ
      ZHomeReady := False; 			// Z軸ホームセット済みフラグ
      XZReset := True; 			// リセットフラグセット
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $C0); 		// リセット送信フラグ解除
      XZSendF := XZSendF or ($800 + $08); 	// H1,-送信フラグセット
      if not MXZResetFL then MXZResetIn := 4; 		// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
// out
  if XZSendF and $480 = $480 then 		// Out
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'OUT' then exit; 	// 通信確認用
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $480);
      exit;
    end;
  if XZSendF and AllFlag = 0 then exit; 	// コマンドが無かったら終了
  if XZSendF and AllFlag = $80 then 	// S1 $80 はすべてに含まれる
    begin
      checkStr := copy(inBufstr,1,2);
      if checkStr = 'S1' then MZStopin := False;
      if checkStr = 'S2' then MXStopin := False;
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $80);
      exit;
    end;

  if XZSendF and $800 = 0 then goto Axis2; 	// Axis1 でなかったら Axis2

// ------------------------ Z軸モード --------------------------------
  if XZSendF and $82 = $82 then 		// Mhome1
    begin
      checkStr := copy(inBufstr,1,6);
      if checkStr <> 'MHOME1' then exit; 	// 通信確認用
      ZXCOTWait := True;                      // True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $82);
      if not MXZResetFL then MXZResetIn := 8; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $88 = $88 then 		// H1,-
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'H1,' then exit; 	// 通信確認用
      ZXCOTWait := True;                      // True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $88);
      XZSendF := XZSendF or $02; 		// Mhome1送信フラグセット
      if not MXZResetFL then MXZResetIn := 6; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $84 = $84 then 		// D1,+
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'D1,' then exit; 	// 通信確認用
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $84);
      XZSendF := XZSendF or $10; 		// ABS1送信送信フラグセット
      if MZMOVEFL then MZMOVEin := 3; 	// Z軸順次制御フラグ
      exit;
    end;
  if XZSendF and $90 = $90 then 		// ABS1
    begin
      checkStr := copy(inBufstr,1,4);
      if checkStr <> 'ABS1' then exit; 	// 通信確認用
      XZReady := False; 			// Reday = False
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $90);
      if MZMOVEFL then MZMOVEin := 5; 	// Z軸順次制御フラグ
      exit;
    end;
  if XZSendF and $A0 = $A0 then 		// V1,
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'V1,' then exit; 	// 通信確認用
      ZXCOTWait := True;                     // True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $A0);
      XZSendF := XZSendF or ($800 + $200); 	// Vs1 送信設定
      exit;
    end;
  if XZSendF and $280 = $280 then 		// VS1
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'VS1' then exit; 	// 通信確認用
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $280);
      MZSpeedFL := False; 			// Z速度設定完了フラグ
      MZSpeedin := False; 			// Z速度設定完了フラグ
      exit;
    end;
  if XZSendF and $180 = $180 then 		// Position D1
    begin
      checkStr := copy(inBufstr,1,2);
      if checkStr <> 'D1' then exit; 	// 通信確認用
      I := LastDelimiter(#13,inBufstr); 	// 最後の'CR' 位置検出
      inBufstr := Copy(inBufstr,15,I - 15); 	// 受信文字15文字目からI文字までコピー
      Val(inBufstr,ZPosition,Leng); 		// 数値変換
      ZXCOTWait := True;                     // True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $180);
      if XZSendF and $1000 = $1000 then 	// X軸リセットホーム指定だったら
        begin
          XZSendF := XZSendF and (MAXDWORD - $1000 - $800); 	// X軸リセットZ軸フラグ解除
          XZSendF := XZSendF or $08; 	// 'H2,-'送信フラグセット
        end; 				// 'H2,-'フラグをセットすると
      ZHomeReady := True; 			// Z軸 MHOME済みフラグ
      if not MXZResetFL then MXZResetIn := 11; 	// MXZResetIn 0 以外順次中フラグ
      exit; 				// 続いてXMHOMEを実行する
    end;
  if XZSendF and $2080 = $2080 then 	// 'R1' X軸状態問い合わせ
    begin
      checkStr := copy(inBufstr,1,2);
      if checkStr <> 'R1' then exit;
      Leng := length(inBufstr); 		// 文字長さ取得
      checkStr := copy(inBufstr,1,Leng - 4); 	// 最後の4文字を除き取得 '$0D0A'0>'
      ILeng := LastDelimiter(char(#10),checkStr); 	// 最後の$0Aの文字位置取得
      Leng := length(checkStr); 		// 文字長さ取得
      inBufstr := copy(checkStr,ILeng + 1,Leng - ILeng); 	// 最後の$0Aの次の文字から後の文字取得
      ILeng := LastDelimiter('=',inBufstr); 	// '=' の位置取得
      Leng := length(inBufstr); 		// 文字長さ取得
      checkStr := copy(inBufstr,ILeng + 1,Leng - ILeng);	 // '='の後ろの文字取得
      val(checkStr,ZPosition,Ileng);; 	// 文字を数値に変換Z軸現在位置取得データー
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $2080); 	// コマンドフラグ解除
      MZPosiGetFL := False; 		// Z軸位置取得フラグ
      MZPosiGetin := False; 		// Z軸位置取得フラグ
      exit;
    end;
  if XZSendF and $4080 = $4080 then 	// 'R1' X軸状態問い合わせ
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'T1,' then exit; 	// 通信確認用
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $4080);
      MZTSpeedin := False; 			// Z軸加速度中フラグ
      MZTSpeedFL := False; 			// Z軸加速度設定フラグ
      exit;
    end;
  if XZSendF and $8080 = $8080 then 	// RAMP1
    begin
      checkStr := copy(inBufstr,1,5);
      if checkStr <> 'RAMP1' then exit; 	// 通信確認用
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $8080);
      MZRAMPin := False; 			// Z軸加速度中フラグ
      MZRAMPFL := False; 			// Z軸加速度設定フラグ
      exit;
    end;

  if XZSendF and $800 = $800 then exit; 	// AXis1 ここまで

// ------------- X 軸モード 処理  -------------------------------
Axis2:
  if XZSendF and $88 = $88 then 		// H2,-
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'H2,' then exit;
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $88);
      XZSendF := XZSendF or $02; 		// Mhome2送信フラグセット
      if not MXZResetFL then MXZResetIn := 13; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $82 = $82 then 		// Mhome2
    begin
      checkStr := copy(inBufstr,1,6);
      if checkStr <> 'MHOME2' then exit;
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $82);
      if not MXZResetFL then MXZResetIn := 15; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $84 = $84 then 		// D2,+
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'D2,' then exit;
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $84);
      XZSendF := XZSendF or $10; 		// ABS2送信フラグセット
      if MXMOVEFL then MXMOVEin := 3; 	// X軸順次制御フラグ
      exit;
    end;
  if XZSendF and $90 = $90 then 		// ABS2
    begin
      checkStr := copy(inBufstr,1,4);
      if checkStr <> 'ABS2' then exit;
      XZReady := False; 			// Reday = False
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $90);
      if MXMOVEFL then MXMOVEin := 5; 	// X軸順次制御フラグ
      exit;
   end;
  if XZSendF and $A0 = $A0 then 		// V2,
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'V2,' then exit;
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $A0);
      XZSendF := XZSendF or $200;
      exit;
    end;
  if XZSendF and $280 = $280 then 		// VS2
    begin
      checkStr := copy(inBufstr,1,3);
      if checkStr <> 'VS2' then exit;
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $280);
      MXSpeedFL := False; 			// X速度設定完了フラグ
      MXSpeedin := False; 			// X速度設定完了フラグ
      exit;
   end;
  if XZSendF and $180 = $180 then 		// Position D2
    begin
      checkStr := copy(inBufstr,1,2);
      if checkStr <> 'D2' then exit;
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $180);
      I := LastDelimiter(#13,inBufstr); 	// 改行文字位置取得
      inBufstr := Copy(inBufstr,15,I - 15); 	// 受信文字15文字目からI文字までコピー
      Val(inBufstr,XPosition,Leng); 		// 数値変換
      XHomeReady := True; 			// X軸 MHOME済みフラグ
      if not MXZResetFL then MXZResetIn := 18; 	// MXZResetIn 0 以外順次中フラグ
      exit;
    end;
  if XZSendF and $2080 = $2080 then 	// R2
    begin
      checkStr := copy(inBufstr,1,2);
      if checkStr <> 'R2' then exit;
      Leng := length(inBufstr); 		// 文字長さ取得
      checkStr := copy(inBufstr,1,Leng - 4); 	// 最後の4文字を除き取得 '$0D0A'0>'
      ILeng := LastDelimiter(char(#10),checkStr); 	// 最後の$0Aの文字位置取得
      Leng := length(checkStr); 		// 文字長さ取得
      inBufstr := copy(checkStr,ILeng + 1,Leng - ILeng); 	// 最後の$0Aの次の文字から後の文字取得
      ILeng := LastDelimiter('=',inBufstr); 	// '=' の位置取得
      Leng := length(inBufstr); 		// 文字長さ取得
      checkStr := copy(inBufstr,ILeng + 1,Leng - ILeng); 	// '='の後ろの文字取得
      val(checkStr,XPosition,Ileng);; 	// 文字を数値に変換X軸現在位置取得データー
      ZXCOTWait := True; 			// True でone wait;
      XZSendF := XZSendF and (MAXDWORD - $2080);
      MXPosiGetFL := False; 		// X位置取得フラグ解除
      MXPosiGetin := False; 		// X位置取得中フラグ解除
      exit;
    end;
end;

//============================= X軸Z軸移動処理 ======================

procedure TOrientalF.ZMHome; 		// Z軸ホームへ戻し
begin
  MZMHOMEIn := True; 			// MHome 送信中フラグセット
  ZHomeReady := False; 			// ホームセットフラグリセット
  XZTimeOutCount := 0; 			// タイムアウトカウンタークリア
  ZPLM := False; 				// Z軸+リミットフラグリセット
  ZMLM := False; 				// Z軸-リミットフラグリセット
  while XZSendF and (MAXDWORD - $800) > 0 do Application.ProcessMessages; 	// 前のコマンド実行待ち
  XZSendF := $800 + $08; 			// ZMHome 送信フラグセット
end;

procedure TOrientalF.XMHome; 		// X軸ホームへ戻し
begin
  MXMHOMEIn := True; 			// MHome 送信中フラグセット
  XHomeReady := False; 			// ホームセットフラグリセット
  XZTimeOutCount := 0; 			// タイムアウトカウンタークリア
  XPLM := False; 				// X軸+リミットフラグリセット
  XMLM := False; 				// X軸-リミットフラグリセット
  while XZSendF and (MAXDWORD - $800) > 0 do Application.ProcessMessages; 	// 前のコマンド実行待ち
  XZSendF := $08; 				// XMHome 送信フラグセット
end;

procedure TOrientalF.ResetHome; 		// XZ軸軸ホーム戻し
begin
  XPLM := False; 				// X軸+リミットフラグリセット
  XMLM := False; 				// X軸-リミットフラグリセット
  ZPLM := False; 				// Z軸+リミットフラグリセット
  ZMLM := False; 				// Z軸-リミットフラグリセット
  XZReset := False; 			// リセット送信済みフラグ
  ZHomeReady := False; 			// リセット済みフラグリセット
  XHomeReady := False; 			// リセット済みフラグリセット
  XZSendF := $80; 				// リセットフラグセット
  XZTimeOutCount := 0; 			// タイムアウトカウンタークリア
  XZTimeOutFL := False; 			// タイムアウトフラグリセット
  if not XZCOMMOPENFL then XZCOMMOPENFL := XZSLDCOMMOPEN; 	// スライダー通信ポートオープンフラグ
  if not XZCOMMOPENFL then 		// 通信オープンできなかったら
    begin
      MainF.EndBtn.Enabled := True; 		// 終了ボタン表示
      exit;
    end;
  ZXCOTWait := False; 			// 送信1ウェイト
  if IOF.Oriental402EstpSet then 		// USB IO により、ESTOP 解除出来たら
    begin
      MZMHOMEin := True; 			// Zホーム実行中フラグセット
      MXMHOMEin := True; 			// Xホーム実行中フラグセット
      XZSendF := $800 + $40; 		// ResetToHomeフラグセット
      if not MXZResetFL then MXZResetIn := 2; 	// MXZResetIn 0 以外順次中フラグ
    end
    else 				// EStop 解除できない場合
    begin
      Errorstr := 'モーターの駆動ロック解除できませんでした。' + #13#10 +
    	         'USBの接続、配線確認後再起動して下さい。';
      application.MessageBox(Pchar(Errorstr),'注意');
    end;
end;

procedure TOrientalF.ZMoveTo; 		// Z軸移動
begin
  if MZMOVEFL then MZMOVEin := 1; 		// Z軸順次制御フラグ
  while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  XZSendF := XZSendF or ($800 + $04); 	// 指定位置移動フラグセット
end;

procedure TOrientalF.ZSpeedSet; 		// Z軸速度指定
begin
  MZSpeedin := True; 			// Z速度設定中フラグ
  while (XZSendF and (MAXDWORD - $800) > 0) do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  XZSendF := XZSendF or ($800 + $20); 	// 速度設定フラグセット
end;

procedure TOrientalF.ZMoveStop; 		// Z軸移動停止
begin
  if MZStopin then exit; 			// 既に停止モードなら終了
  MZStopin := True;
  IOF.OutBitNoOnNonErr(XZSstopbit); 		// XZモーター SStop ON IOによる停止
  while (XZSendF and (MAXDWORD - $800) > 0) do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then
        begin
          IOF.OutBitNoOff(XZSstopbit); 	// XZモーター SStop Off
          exit; 				// EStop なら 抜ける
        end;
    end;
  XZSendF := XZSendF or ($800 + $80); 	// 送信フラグセット
  MainF.Delay(ShortWait); 			// 遅延タイマー10mmsec 通常
  IOF.OutBitNoOffNonErr(XZSstopbit); 	// XZモーター SStop Off
  Comm4.SendString('S1' + #13#10); 		// 停止フラグ'S1'送信
end; 					// 停止コマンドは移動中いつでも受け付ける

procedure TOrientalF.ZTpeedSet; 		// Z軸加速度指定
begin
  if MZTSpeedin then exit;
  MZTSpeedin := True; 			// コマンド送信中ラグセット
  while (XZSendF and (MAXDWORD - $800) > 0) do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  XZSendF := XZSendF or ($800 + $4000); 	// 加速度設定フラグセット
end;

procedure TOrientalF.XSpeedSet; 		// X軸速度指定
begin
  MXSpeedin := True; 			// X速度設定中フラグ
  while (XZSendF and (MAXDWORD - $800) > 0) do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  XZSendF := XZSendF and (MAXDWORD - $800); 	// X軸フラグ消去
  XZSendF := XZSendF or $20; 		// 速度設定フラグセット
end;

procedure TOrientalF.XMoveTo; 		// X軸移動
begin
  if MXMOVEFL then MXMOVEin := 1; 		// X軸順次制御フラグ
  while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  XZSendF := XZSendF and (MAXDWORD - $800); 	// X軸指定フラグセット
  XZSendF := XZSendF or $04; 		// 指定位置移動フラグセット
end;

procedure TOrientalF.XMoveStop; 		// X軸移動停止
begin
  if MXStopin then exit; 			// 既に停止モードにら終了
  MXStopin := True;
  IOF.OutBitNoOnNonErr(XZSstopbit); 		// XZモーター SStop ON IOによる停止
  while (XZSendF and (MAXDWORD - $800) > 0) do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then
        begin
          IOF.OutBitNoOffNonErr(XZSstopbit); 	// XZモーター SStop Off
          exit; 				// EStop なら 抜ける
        end;
    end;
  XZSendF := XZSendF and (MAXDWORD - $800); 	// X軸指定フラグセット
  XZSendF := XZSendF or $80; 		// 送信フラグセット
  Delay(ShortWait); 			// 遅延タイマー10mmsec 通常
  IOF.OutBitNoOffNonErr(XZSstopbit); 	// XZモーター SStop Off
  Comm4.SendString('S2' + #13#10); 		// 停止コード送信
end;

procedure TOrientalF.ZR1send; 		// R1送信Position取得
begin
  MZPosiGetin := True; 			// Z軸位置取得フラグ
  while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  XZSendF := XZSendF or $2800; 		// Z軸R1 送信フラグセット
end;

procedure TOrientalF.XR2send; 		// X軸R2送信Position取得
begin
  MXPosiGetin := True; 			// X軸位置取得フラグ
  while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  XZSendF := XZSendF and (MAXDWORD - $800); 	// X軸指定フラグセット
  XZSendF := XZSendF or $2000; 		// R2 送信フラグセット
end;

procedure TOrientalF.ZRAMPSet; 		// Z軸Rampset;
begin
  MZRampin := True; 			// Z軸Rampフラグ
  while (XZSendF and (MAXDWORD - $800) > 0) do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  XZSendF := XZSendF or $8800; 		// ZRamp 送信フラグセット
end;


//------------------------ XZ OUTData Make -------------------------------

procedure TOrientalF.XZOutDataMake(PortNo:integer;OnOffFl:boolean); 	// Outdata作成 OnOffFl True = 0n False = Off
begin
  if (PortNo < 1) or (PortNo > 6) then exit;
  if OnOffFl then OutXZSTR[7-PortNo] := '1' 		// OutXZSTR : OutPortString
             else OutXZSTR[7-PortNo] := '0';
end;

procedure TOrientalF.XZportOut; 		// Portout
begin
  while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  XZSendF := XZSendF or $400; 		// Portoutフラグセット
end;

//------------------------ XZアラームクリア ------------------------------
procedure TOrientalF.XZAlmClear; 		// XZアラームクリア
begin
  if XFreeFl then exit; 			// フリーだったら実行しない
  while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  OutXZSTR[6] := '1'; 			// ポートon設定
  OutXZSTR[5] := '1'; 			// ポートon設定
  XZSendF := XZSendF or $400; 		// Portoutフラグセット
  while (XZSendF and (MAXDWORD - $800) > 0) or not XZReady do 	// 前のコマンド実行待ち
    begin
      Application.ProcessMessages;
      if XZEStop then exit; 		// EStop なら 抜ける
    end;
  OutXZSTR[6] := '0'; 			// ポートoff設定
  OutXZSTR[5] := '0'; 			// ポートoff設定
  XZSendF := XZSendF or $400; 		// Portoutフラグセット
end;

// -----------------------XZ軸 ボタンクリック処理 --------------------------
procedure TOrientalF.ResetBtnClick(Sender: TObject);
begin
  MXZResetFL := False; 			// XZ軸軸ホーム戻し
end;

procedure TOrientalF.XMHOMEBtnClick(Sender: TObject);
begin
  application.MessageBox('位置データーを0(ゼロ)として戻して下さい','注意',0);
// if MXZResetFL then MXMHOMEFL := False; 	// Mhome済み
end;

procedure TOrientalF.ZMHomeBTnClick(Sender: TObject);
begin
  if MXZResetFL then MZMHOMEFL := False; 	// Mhome済み
end;

procedure TOrientalF.XMoveToBtnClick(Sender: TObject);
begin
  MXMOVEFL := True; 			// X軸移動
end;

procedure TOrientalF.ZMovetoBtnClick(Sender: TObject);
begin
  MZMOVEFL := True; 			// Z軸移動
end;

procedure TOrientalF.ZSpeedClick(Sender: TObject);
var
  check: integer;
  inspeed: Cardinal;
begin
  val(ZSpeedEdit.Text,inspeed,Check);
  if Check <> 0 then exit;
  ZVSpeed := inspeed; 			// 速度セット
  MZSpeedFL := True; 			// 速度設定フラグ
end;

procedure TOrientalF.XSpeedClick(Sender: TObject);
var
  check: integer;
  inspeed: Cardinal;
begin
  val(XSpeedEdit.Text,inspeed,Check);
  if Check <> 0 then exit;
  XVSpeed := inspeed; 			// 速度セット
  MXSpeedFL := True; 			// 速度設定フラグ
end;

procedure TOrientalF.XstopBtnClick(Sender: TObject);
begin
  if not MXStopin then XMoveStop; 		// X軸移動停止 フラグ使用しない
end;

procedure TOrientalF.ZStopBtnClick(Sender: TObject);
begin
  if not MZStopin then ZMoveStop; 		// Z軸移動停止 フラグ使用しない
end;

procedure TOrientalF.XFreeTgrBtnClick(Sender: TObject);
begin
  if OutXZSTR[4] = '0' then
    begin
      XZOutDataMake(3,True);
      XFreeTgrBtn.Caption := 'Free Off';
      XFreeFl := True; 			// X軸フリーにしたフラグ
    end
    else
    begin
      XZOutDataMake(3,False);
      XFreeTgrBtn.Caption := 'Free On';
      XFreeFl := False; 			// X軸フリー解除したフラグ
    end;
  XZportOut;
end;

procedure TOrientalF.ZFreeTgrBtnClick(Sender: TObject);
begin
  Application.MessageBox('Z軸をフリーにしてはいけません。','禁止事項');
end;

procedure TOrientalF.XR2btnClick(Sender: TObject);
begin
  MZPosiGetFL := True; 			// X軸R2送信Position取得
end;

procedure TOrientalF.ZR1BtnClick(Sender: TObject);
begin
  MZPosiGetFL := True; 			// R1送信Position取得
end;

procedure TOrientalF.AlmClearBtnClick(Sender: TObject);
begin
  XZAlmClear;
end;

procedure TOrientalF.ZPosisetBtnClick(Sender: TObject);
var
  check :integer;
begin
  val(ZpositionEdit.Text,ZVPosition,Check); 	// 送信用位置データー変換
  ZpositionCheck;
  ZpositionEdit.Text := FloatTostr(ZVPosition);
end;

procedure TOrientalF.XPosisetBtnClick(Sender: TObject);
var
  check :integer;
begin
  val(XpositionEdit.Text,XVPosition,Check); 	// 送信用位置データー変換
  XpositionCheck;
  XpositionEdit.Text:= FloatTostr(XVPosition);
end;

 

 (株)メレック MPL28 CB23/USB

これは、USBをRS485に変換して複数のユニットの制御が可能にしたものです。(ステッピングモーターコントローラー、IOユニット)
最初のバージョンには、Delphi用のサンプルプログラムが添付されてきたのですが、新しいバージョンには、Dlephi用のものは添付されてこないようです。
C#,VC.NET用のヘッダファイル、或いはVB用のDLL関数呼び出し定義ファイルがダウンロード出来れば、Delphi用に変換可能なのですが、製品にCDとして添付されてくるだけで、公開されていません。
メーカーの方針のようなので、ソフトの此処での公開は控えさせて頂きます。
最初のバージョンに付いてきたサンプルソフトの起動画面を下図に示します。

MPL28

Delphiは、最近少し盛り返してきましたが、仕様の変更が結構有った事、サンプルプログラムの少なさ、マイクロソフトのツールの無料公開等で、若い年代層のユーザー数が減少した為に、メーカー側で、Delphi用のサンプルソフトを用意するところが少なくなりました。

 (株)コスモテックス USPG-48(F)

これは、USB通信四軸ステッピングモーターコントローラーです。(直線、円弧補間可能)
ここの会社のホームページからは、ユーザー登録さえ行えば、マニュアル、ドライバー等必要なものは全てダウンロードできます。
必要であれば、メーカーホームページよりダウンロードして下さい。
 ここの会社にも Delphi用のサンプルプログラムはありません。
Delphi用に変換したプログラムリストを紹介します。
WinXp(32bit)用のものを変換したので、最近は、64ビットバージョンも出ており、多少違うところがあるかもしれません。

実行画面
USPG-48

サンプルプログラムは、ホームポジションセンサーを一個だけ取り付けて動作させた場合の例です。

unit USPGTEST;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, CTD20DLL, ExtCtrls, IniFileS;

type
  TUSPG48TESTF = class(TForm)
    Edit1: TEdit;
    DllVerGetBtn: TButton;
    DrvVerGetBtn: TButton;
    AxisIniBtn: TButton;
    Edit2: TEdit;
    Timer1: TTimer;
    OriginBtn: TButton;
    CwIndexBtn: TButton;
    CCwIndexBtn: TButton;
    ZeroRtnBtn: TButton;
    SlowStopBtn: TButton;
    InternalCouterBtn: TButton;
    SModesetbtn: TButton;
    DMODbtn: TButton;
    UDESmodebtn: TButton;
    HiSpeedBtn: TButton;
    LowSpeedBtn: TButton;
    CwScanBtn: TButton;
    CCwScanBtn: TButton;
    RangeReadbtn: TButton;
    Ready1Edit: TEdit;
    OpenBtn: TButton;
    AxisNoEdit: TEdit;
    ObjectspeedBtn: TButton;
    Ready2Edit: TEdit;
    Ready3Edit: TEdit;
    Ready4Edit: TEdit;
    IndexEdit: TEdit;
    IndexLabel: TLabel;
    AbsLabel: TLabel;
    AbsEdit: TEdit;
    AbsBtn: TButton;
    LowSpeedEdit: TEdit;
    LowSpeedLabel: TLabel;
    HiSpeedEdit: TEdit;
    HiSpeedLabel: TLabel;
    RiseEdit: TEdit;
    RiseLabel: TLabel;
    DownEdit: TEdit;
    DownLabel: TLabel;
    SRatioEdit: TEdit;
    SRaitLabel: TLabel;
    AxisLabel: TLabel;
    MinimumEdit: TEdit;
    MinimumLabel: TLabel;
    MinimumBtn: TButton;
    procedure DllVerGetBtnClick(Sender: TObject);
    procedure DrvVerGetBtnClick(Sender: TObject);
    procedure AxisIniBtnClick(Sender: TObject);
    procedure OriginBtnClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure CwIndexBtnClick(Sender: TObject);
    procedure CCwIndexBtnClick(Sender: TObject);
    procedure ZeroRtnBtnClick(Sender: TObject);
    procedure SlowStopBtnClick(Sender: TObject);
    procedure InternalCouterBtnClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure SModesetbtnClick(Sender: TObject);
    procedure DMODbtnClick(Sender: TObject);
    procedure UDESmodebtnClick(Sender: TObject);
    procedure HiSpeedBtnClick(Sender: TObject);
    procedure LowSpeedBtnClick(Sender: TObject);
    procedure CwScanBtnClick(Sender: TObject);
    procedure CCwScanBtnClick(Sender: TObject);
    procedure RangeReadbtnClick(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure OpenBtnClick(Sender: TObject);
    procedure ObjectspeedBtnClick(Sender: TObject);
    procedure AbsBtnClick(Sender: TObject);
    procedure MinimumBtnClick(Sender: TObject);
  private
{ Private 宣言 }
    function InitAxis(wBsn, wAxis: Word): LongBool; 	// 軸初期化
    function LeftSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double; sUpTime, sDownTime: Word; SRate: Double): Word; 	// 残パルス指定速度設定
    function StraightSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double; sUpDownTime: Word): Word; 			// 直線加速指定速度設定
    procedure BtnFalseSet;
    procedure DeviceOpen;
    function MinimumPulses(var UpTime, DownTime, dHighSpeed: double; dLowSpeed, Funit: Double): Cardinal;
    function NESModeset: boolean;

  public
{ Public 宣言 }
    procedure Orgmove(wAxis: Word); 	// 原点復帰
    function SpeedDataInput: Boolean; 	// 速度データー入力
  end;

var
  USPG48TESTF : TUSPG48TESTF;
  Ack : LongBool;
  STATE : integer;
  STATE_SUB : integer;
  wBsn : Word;
  wAxis : Word;
  chk : Smallint;
  SLD_P_DATA : DWord;
  Err : Dword;
  RANGE_DATA : Word;
  Bdata : byte; 				// ドライブステータス
  ReadyF : array[1..4] of Boolean; 		// 軸ReadyF
  LowSpeed : Double;
  HiSpeed : Double;
  RiseTime : Word;
  DownTime : Word;
  SRate : Double;
  SHModeF : Boolean; 			// S時非対称モードフラグ

const
  CRatebase = 4.096E6;
  clockbase = 8.191E6; 			// 基本は8.192E6 計算上 8.191E6に設定


implementation

{$R *.dfm}
var
  check : integer;
  IndexData : Cardinal;

function TUSPG48TESTF.SpeedDataInput: Boolean; 	// 速度データー入力
begin
  Result := False;
  val(LowSpeedEdit.Text, LowSpeed, check);
  if (check <> 0) or (LowSpeed < 0) then
    begin
      Application.MessageBox('起動速度に誤りがあります。','注意',MB_OK);
      exit;
    end;
  val(HiSpeedEdit.Text, HiSpeed, check);
  if (check <> 0) or (HiSpeed <= 0) then
    begin
      Application.MessageBox('指定速度に誤りがあります。','注意',MB_OK);
      exit;
    end;
  if HiSpeed < LowSpeed then
    begin
      Application.MessageBox('指定速度より起動速度が大きいです。','注意',MB_OK);
      exit;
    end;
  val(RiseEdit.Text, RiseTime, check);
  if check <> 0 then
    begin
      Application.MessageBox('起動時間に誤りがあります。','注意',MB_OK);
      exit;
   end;
  val(DownEdit.Text, DownTime, check);
  if check <> 0 then
    begin
      Application.MessageBox('停止時間に誤りがあります。','注意',MB_OK);
      exit;
    end;
  val(SRatioEdit.Text, SRate, check);
  if (check <> 0) or (SRate < 0) then
    begin
      Application.MessageBox('Sカーブ比率に誤りがあります。','注意',MB_OK);
      exit;
    end;
  Result := True;
end;

// ------------------ S 字 非対称時 指定パルス数による 立ち上げたち下げ時間補正
function TUSPG48TESTF.MinimumPulses(var UpTime, DownTime, dHighSpeed: double; dLowSpeed, Funit: Double): Cardinal;
var
  DownTimePulses,UpTimePulses : Cardinal;
  DT : double;
  SUpPulse: double;
  Nuptime, Ndowntime: double;
begin
  DownTimePulses := Round((DownTime) * (dHighSpeed + dLowSpeed - Funit) / 2);
  UpTimePulses := Round((UpTime) * (dHighSpeed + dLowSpeed - Funit) / 2);
  Result := DownTimePulses + UpTimePulses;
  if indexData >= Result then exit;
  SUpPulse := indexData * (UpTimePulses / (UpTimePulses + DownTimePulses));
  DT := (dHighSpeed - dLowSpeed) / UpTime;
  Nuptime := sqrt(sqr(2 * dLowSpeed - Funit) - 4 * DT * (-2 * SUppulse));
  Nuptime := (-(2 * dLowSpeed - Funit) + Nuptime) / 2 / DT;
  Ndowntime := Nuptime / UpTime * DownTime;
  UpTime := Nuptime;
  DownTime := Ndowntime;
  dHighSpeed := Nuptime * DT + dLowSpeed;
// Result := indexData;
  Edit1.Text := floatTostr(Nuptime);
  Edit2.Text := floatTostr(Ndowntime);
end;

function TUSPG48TESTF.LeftSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double; sUpTime, sDownTime: Word; SRate: Double): Word; // 残パルス指定速度設定
var
  SS_SPEED_DATA : Word;
  OB_SPEED_DATA : Word;
  RATE_1_DATA : Word;
  RATE_2_DATA : Word;
  SW1_DATA : Word;
  SW2_DATA : Word;
  Funit : double;
  sr : double;
  UpTime, DownTime : double;
  Utsw,Utud : double;
  Dtsw,Dtud : double;

begin
  Result := 0;

//*---------------------------------------------------------------
// データ設定
//

  sr := SRate / 100; 			// パーセント -> 係数
  UpTime := sUpTime * 0.001; 		// Up mmsec -> sec
  DownTime := sDownTime * 0.001; 		// down mmsec -> sec

//  Rang 固定 8.191E6 ÷ 最高周波数(81920 PPS)

// RANGE DATA
  RANGE_DATA := round(int(clockbase / dHighSpeed));

  Funit := 1000 / RANGE_DATA; 		// 周波数設定単位

//-------------------  速度調整 -------------------------------------------

  MinimumEdit.Text := intTostr(MinimumPulses(UpTime, DownTime, dHighSpeed, dLowSpeed, Funit));

//
// START/STOP SPEED DATA 開始停止周波数設定単位
  SS_SPEED_DATA := Round(Int(dLowSpeed / Funit));

// OBJECT SPEED DATA 目的周波数設定単位
  OB_SPEED_DATA := Round(Int(dHighSpeed / Funit));
// RATE-1 DATA 加速時間設定単位

  Utsw := UpTime * sr / 2; 			// Up Sカーブ部時間 
  Utud := UpTime * (1 - sr); 		// Up 直線部時間

  Dtsw := DownTime * sr / 2; 		// down Sカーブ部時間 
  Dtud := DownTime * (1 - sr); 		// down 直線部時間

  RATE_1_DATA := Round(Int((Utsw + Utud) / (OB_SPEED_DATA - SS_SPEED_DATA) * CRatebase));

// RATE-2 DATA 減速時間設定単位
  RATE_2_DATA := Round(Int((Dtsw + Dtud) / (OB_SPEED_DATA - SS_SPEED_DATA) * CRatebase));

// 残パルス数
  SLD_P_DATA := Round(Int((DownTime) * (dHighSpeed + dLowSpeed - Funit) / 2));

//SW1_DATA
  SW1_DATA := Round(Int(CRatebase * Utsw / 2 / RATE_1_DATA)); 	// S時加速区間スピードデーター
  if SW1_DATA < 1 then SW1_DATA := 1; 			// SW1_DATA が 0 ではいけない

//SW2_DATA
  SW2_DATA := Round(Int(CRatebase * Dtsw / 2 / RATE_2_DATA)); 	// S時減速区間スピードデーター
  if SW2_DATA < 1 then SW2_DATA := 1; 			// SW2_DATA が 0 ではいけない

// RATE-3 DATA デフォルト値 8191(1FFFh)
// RATE CHANGE POINT 1-2 デフォルト値 8191(1FFFh)
// RATE CHANGE POINT 2-3 デフォルト値 8191(1FFFh)
//

//*---------------------------------------------------------------
// MODE1 SET
//
// 減速開始ポイント検出方式 残パルス数指定
// パルス出力方式 2パルス方式
// DIR 出力端子 CWパルス アクティブ Hi
// PULSE 出力端子 CCWパルス アクティブ Hi
//--------------------------------------------------------------*/
// if False = CTDMode1Write(wBsn, wAxis, $C0) then Exit;
  if False = CTDMode1Write(wBsn, wAxis, $E0) then Exit;

//*---------------------------------------------------------------

  if False = CTDCommandWrite(wBsn, wAxis, CTD_US_S_CURVE_ACCELERATE_MODE_SET) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RANGE_WRITE, RANGE_DATA) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_START_STOP_SPEED_DATA_WRITE, SS_SPEED_DATA) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_OBJECT_SPEED_DATA_WRITE, OB_SPEED_DATA) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RATE1_DATA_WRITE, RATE_1_DATA) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RATE2_DATA_WRITE, RATE_2_DATA) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_SW1_DATA_WRITE, SW1_DATA) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_SW2_DATA_WRITE, SW2_DATA) then Exit;
  if False = CTDDataFullWrite(wBsn, wAxis, CTD_SLOW_DOWN_REAR_PULSE_WRITE, SLD_P_DATA) then Exit;

  Result := 1;
end;

function TUSPG48TESTF.StraightSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double;sUpDownTime: Word): Word; // 直線加速指定速度設定
var
  SS_SPEED_DATA : Word;
  OB_SPEED_DATA : Word;
  RATE_1_DATA : Word;
  Funit : double;
  UpDownTime :double;
begin
  Result := 0;
//*---------------------------------------------------------------
// MODE1 SET
//
// 減速開始ポイント検出方式 自動
// パルス出力方式 2パルス方式
// DIR 出力端子 CWパルス アクティブ Hi
// PULSE 出力端子 CCWパルス アクティブ Hi
//--------------------------------------------------------------*/
// if False = CTDMode1Write(wBsn, wAxis, $40) then Exit; 	// $40 $60 は、回転方向
  if False = CTDMode1Write(wBsn, wAxis, $60) then Exit; 	// CCWPuls CWPuls 切り替え
//*---------------------------------------------------------------
// データ設定
//
  UpDownTime := sUpDownTime * 0.001; 		// Up mmsec -> sec

// RANGE DATA
  RANGE_DATA := round(int(clockbase / dHighSpeed)); 	// Rang 固定 8.191E6 ÷ 最高周波数(dHighSpeed)

// Funit 出力周波数設定単位
  Funit := 1000 / RANGE_DATA; 			// Funit = 1000÷RANGE

// START/STOP SPEED DATA 開始停止設定単位 SS_SPEED_DATA = dLowSpeed ÷ Funit
  SS_SPEED_DATA := Round(Int(dLowSpeed / Funit));

// OBJECT SPEED DATA 目的周波数設定単位 OB_SPEED_DATA = dHighSpeed ÷ Funit;
  OB_SPEED_DATA := Round(Int(dHighSpeed / Funit));

// RATE-1 DATA 加減時間設定単位
// RATE_1_DATA = UpDownTime ÷ (OB_SPEED_DATA - SS_SPEED_DATA) * CRatebase
  RATE_1_DATA := Round(Int((UpDownTime) / (OB_SPEED_DATA - SS_SPEED_DATA) * CRatebase));

// RATE-2 DATA デフォルト値 8191(1FFFh)
// RATE-3 DATA デフォルト値 8191(1FFFh)
// RATE CHANGE POINT 1-2 デフォルト値 8191(1FFFh)
// RATE CHANGE POINT 2-3 デフォルト値 8191(1FFFh)
//
//--------------------------------------------------------------*/
  if False = CTDCommandWrite(wBsn, wAxis, CTD_STRAIGHT_ACCELERATE_MODE_SET) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RANGE_WRITE, RANGE_DATA) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_START_STOP_SPEED_DATA_WRITE, SS_SPEED_DATA) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_OBJECT_SPEED_DATA_WRITE, OB_SPEED_DATA) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RATE1_DATA_WRITE, RATE_1_DATA) then Exit;
// 残パルス数を 0 にしないと、減速後 残パルス数移動する
  if False = CTDDataFullWrite(wBsn, wAxis, CTD_SLOW_DOWN_REAR_PULSE_WRITE, 0) then Exit;

  Result := 1;
end;

function TUSPG48TESTF.InitAxis(wBsn, wAxis: Word): LongBool; 	// 軸初期化
begin
// 返り値 False 既設定
  Result := False;

//*---------------------------------------------------------------
// MODE1 SET
//
// 減速開始ポイント検出方式 自動
// パルス出力方式 2パルス方式
// DIR 出力端子 CWパルス アクティブ Hi
// PULSE 出力端子 CCWパルス アクティブ Hi
//--------------------------------------------------------------*/
// if False = CTDMode1Write(wBsn, wAxis, $40) then Exit;
  if False = CTDMode1Write(wBsn, wAxis, $60) then Exit;
// 減速開始ポイント検出方式 残パルス数
// if False = CTDMode1Write(wBsn, wAxis, $C0) then Exit;

//*---------------------------------------------------------------
// MODE2 SET
//
// EXTERNAL COUNTER 入力仕様 None
// DEND 入力信号アクティブレベル High
// DERR 入力信号アクティブレベル High
// -SLM 入力信号アクティブレベル High
// +SLM 入力信号アクティブレベル High
// -ELM 入力信号アクティブレベル High
// +ELM 入力信号アクティブレベル High
//--------------------------------------------------------------*/
  if False = CTDMode2Write(wBsn, wAxis, $3F) then Exit;

//*---------------------------------------------------------------
// モード設定
//
// STRAIGHT ACCELERATE MODE
// INPOSITION WAIT MODE RESET
// ALARM STOP ENABLE MODE SET
//--------------------------------------------------------------*/
  if False = CTDCommandWrite(wBsn, wAxis, CTD_STRAIGHT_ACCELERATE_MODE_SET) then Exit;
  if False = CTDCommandWrite(wBsn, wAxis, CTD_INPOSITION_WAIT_MODE_RESET) then Exit;
  if False = CTDCommandWrite(wBsn, wAxis, CTD_ALARM_STOP_ENABLE_MODE_SET) then Exit;

//*---------------------------------------------------------------
// データ設定
// RANGE DATA 100 8.191E6 ÷ 最高周波数(PPS)
// Funit 10 出力周波数設定単位 1000÷100=10PPS
// START/STOP SPEED DATA 50 開始停止周波数 50× 10PPS=500PPS
// OBJECT SPEED DATA 400 目的周波数 400× 10PPS=4000PPS
// RATE-1 DATA 2048 加速時間設定単位 2048÷(4.096×10^6)= 0.5mSec
// 加速減時間 (400-50)×0.5mSec = 0.175Sec
// RATE-2 DATA デフォルト値 8191(1FFFh)
// RATE-3 DATA デフォルト値 8191(1FFFh)
// RATE CHANGE POINT 1-2 デフォルト値 8191(1FFFh)
// RATE CHANGE POINT 2-3 デフォルト値 8191(1FFFh)
//
// この設定により RATE-1 DATA による直線加減速となります
//--------------------------------------------------------------*/
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RANGE_WRITE, 100) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_START_STOP_SPEED_DATA_WRITE, 50) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_OBJECT_SPEED_DATA_WRITE, 200) then Exit;
  if False = CTDDataHalfWrite(wBsn, wAxis, CTD_RATE1_DATA_WRITE, 2048) then Exit;
// 残パルス数を 0 にしないと、減速後 残パルス数移動する
  if False = CTDDataFullWrite(wBsn, wAxis, CTD_SLOW_DOWN_REAR_PULSE_WRITE, 0) then Exit;
//*---------------------------------------------------------------
// アドレス設定
//
// INTERNAL COUNTER 及び EXTERNAL COUNTER に 0h を書き込みます
//--------------------------------------------------------------*/
  if False = CTDDataFullWrite(wBsn, wAxis, CTD_INTERNAL_COUNTER_WRITE, 0) then Exit;
  if False = CTDDataFullWrite(wBsn, wAxis, CTD_EXTERNAL_COUNTER_WRITE, 0) then Exit;
// 返り値 True設定
  Result := True;
end;

procedure TUSPG48TESTF.Orgmove(wAxis: Word); 	//原点復帰
label
  Rewhile;
var
  b : byte;
begin
  OriginBtn.Enabled := False;
// 原点復帰開始イベントで STATE = 11 を設定する。
// STATE の初期値は0 から3 と11 以外とする。
// STATE := 10;
  while (STATE <> 10) or (STATE_SUB <> 10) do 	// 原点復帰したらループを抜ける
    begin
      case STATE of
        0:begin 	// STATE=0 原点復帰開始 ステート
            Ack := CTDGetMechanicalSignal(wBsn,wAxis, b); 	// メカ二ルシグナル読み込み
            if b and $A = 0 then 				// -ELM or .SLM がOFF の時。
                						// 開始位置-リミットにない。ORG↑-シグナルサーチ1 開始
                STATE := 1 					// 開始位置-リミットにない
              else 					// 開始位置-リミット。 ORG↓+シグナルサーチ1 開始
                STATE := 2; 				// 開始位置-リミット
        	   goto Rewhile;
          end;
        1:begin 	// STATE=1・・・開始位置-リミットにない ステート
            case STATE_SUB of 				// STATE_DUB はSTATE 内の内部STATE
              0:begin
                  // Ack := CTDMode1Write(wBsn, wAxis, $4C); 	// IN0-n(ORG-n)立ち上がりエッジ
                  Ack := CTDMode1Write(wBsn, wAxis, $6C); 	// IN0-n(ORG-n)立ち上がりエッジ
                  Ack := CTDCommandWrite(wBsn, wAxis, $25); 	// -SignalSearchDrive-1
                  ReadyF[wAxis] := False; 			// ReadyF 解除
                  STATE_SUB := 1; 				// STATE=1 のSTATE_SUB=0 のDrive 終了待ちSTATE へ移行
                  goto Rewhile;
                end;
              2:begin
                  Ack := CTDGetMechanicalSignal(wBsn,wAxis, b); // メカニカルシグナル読み込み
                  if b and $A = 0 then 			// -ELM or .SLM がOFF の時、開始位置 ORG-n より+側にある。
                      					// 開始位置 ORG-n より+側にある。ORG↓+シグナルサーチ2 開始
                      STATE_SUB := 3 			// STATE=1 のSTATE_SUB=2 のDrive 終了待ちSTATE へ移行
                    else
                    begin
                      STATE := 2; 				// 開始位置がORG-n より-側にある STATE=2 はSTATE=1 からの派生STATE。
                      STATE_SUB := 0; 			// STATE=2 の内部STATE を初期化。(STATE_SUB)
                    end;
                  goto Rewhile;
                end;
            end;
            goto Rewhile;
          end;
        2:begin 	// STATE=2 ・・STATE=1 からの派生STATE。 開始位置がORG-n より-側にある ステート
            case STATE_SUB of 				// STATE=3 ・・開始位置-リミットにある ステート
              0:begin 	// 開始位置 ORG-n より-側にある。ORG↓+シグナルサーチ1 開始
                  // Ack := CTDMode1Write(wBsn, wAxis, $44); 	// IN0-n(ORG-n)立下りエッジ
                  Ack := CTDMode1Write(wBsn, wAxis, $64); 	// IN0-n(ORG-n)立下りエッジ
                  Ack := CTDCommandWrite(wBsn, wAxis, $24); 	// +SignalSearchDrive-1
                  ReadyF[wAxis] := False; 			// ReadyF 解除
                  STATE_SUB := 1; 				// STATE=2,3 のSTATE_SUB=0 のDrive 終了待ちSTATE へ移行
                  goto Rewhile;
                end;
              2:begin 	// ORG↑-シグナルサーチ2 開始
                  // Ack := CTDMode1Write(wBsn, wAxis, $4C); 	// IN0-n(ORG-n)立上がりエッジ
                  Ack := CTDMode1Write(wBsn, wAxis, $6C); 	// IN0-n(ORG-n)立上がりエッジ
                  Ack := CTDCommandWrite(wBsn, wAxis, $27); 	// -SignalSearchDrive-2
                  ReadyF[wAxis] := False; 			// ReadyF 解除
                  STATE_SUB := 3; 				// STATE=2,3 のSTATE_SUB=2 のDrive 終了待ちSTATE へ移行
                  goto Rewhile;
                end;
              4:begin 	// ORG↓+シグナルサーチ2 開始
                  // Ack := CTDMode1Write(wBsn, wAxis, $44); 	// IN0-n(ORG-n)立下りエッジ
                  Ack := CTDMode1Write(wBsn, wAxis, $64); 	// IN0-n(ORG-n)立下りエッジ
                  Ack := CTDCommandWrite(wBsn, wAxis, $26); 	// +SignalSearchDrive-2
                  ReadyF[wAxis] := False; 			// ReadyF 解除
                  STATE_SUB := 5; 				// STATE=2,3 のSTATE_SUB=4 のDrive 終了待ちSTATE へ移行
                  goto Rewhile;
                end;
              6:begin 	// カウンタークリア
                  Ack := CTDDataFullWrite(wBsn,wAxis,CTD_INTERNAL_COUNTER_WRITE,0);
                  Ack := CTDDataFullWrite(wBsn,wAxis,CTD_EXTERNAL_COUNTER_WRITE,0);
                  // "原点復帰終了";
                  STATE_SUB := 10;
                  STATE := 10;
                  goto Rewhile;
                end;
            end;
            goto Rewhile;
          end;
       11:begin 	// 開始 ステート
            STATE := 0;
            STATE_SUB := 0;
          end;
      end;
Rewhile:
      application.ProcessMessages;
      if ReadyF[wAxis] then 				// Ready
        case STATE of
          1,2:begin 	// STATE=1・・・開始位置-リミットにない ステート
              case STATE_SUB of
                1: STATE_SUB := 2; 				// ドライブ終了 STATE=1,2,3 のSTATE_SUB=2 へ移行
                3: begin STATE_SUB := 4; STATE := 2; end; 	// ドライブ終了 STATE= 2,3 のSTATE_SUB=4 へ移行
                5: STATE_SUB := 6; 				// ドライブ終了 STATE= 2,3 のSTATE_SUB=6 へ移行
              end;
            end;
        end;
    end;
  OriginBtn.Enabled := True;
end;

procedure TUSPG48TESTF.DllVerGetBtnClick(Sender: TObject);
begin
  Edit2.Text := '';
  Ack := CTDGetLibVersion(Versionchar);
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
    end;
  Edit1.Text := string(Versionchar);
end;

procedure TUSPG48TESTF.DrvVerGetBtnClick(Sender: TObject);
begin
  Edit2.Text := '';
  Ack := CTDGetDrvVersion(Versionchar);
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
    end;
  Edit1.Text := String(Versionchar);
end;

procedure TUSPG48TESTF.AxisIniBtnClick(Sender: TObject);
var
  inAxis,check: integer;
begin
  Edit1.Text := '';
  Edit2.Text := '';
  val(AxisNoEdit.Text, inAxis, check);
  if check <> 0 then
    begin
      application.MessageBox('数値以外が入力されています。','注意',MB_OK);
      exit;
    end;
  case inAxis of
      1 : wAxis := CTD_AXIS_1; // 第一軸
      2 : wAxis := CTD_AXIS_2; // 第二軸
      3 : wAxis := CTD_AXIS_3; // 第三軸
      4 : wAxis := CTD_AXIS_4; // 第四軸
     else
       begin
         application.MessageBox('軸Noの範囲は1~4です。','注意',MB_OK);
         exit;
       end;
    end;
  Ack:= InitAxis(wBsn,wAxis); // 軸初期化
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  Chk:= CTDSpeedWrite(wBsn,wAxis,100); 	// 速度100%
  OriginBtn.Enabled := True;
  CwIndexBtn.Enabled := True;
  CCwIndexBtn.Enabled := True;
  ZeroRtnBtn.Enabled := True;
  SlowStopBtn.Enabled := True;
  InternalCouterBtn.Enabled := True;
  SModesetbtn.Enabled := True;
  DMODbtn.Enabled := True;
  UDESmodebtn.Enabled := True;
  CwScanBtn.Enabled := True;
  CCwScanBtn.Enabled := True;
  RangeReadbtn.Enabled := True;
  AbsBtn.Enabled := True;
  ObjectspeedBtn.Enabled := True;

  AxisIniBtn.Enabled := False;
  Edit2.Text := 'Open 成功';
end;

procedure TUSPG48TESTF.OriginBtnClick(Sender: TObject); 	// 原点復帰
begin
  Edit2.Text := '';
  STATE := 11;
  Ack:= InitAxis(wBsn, wAxis); 		// wAxis軸初期化
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  Orgmove(wAxis); 				// 原点復帰
end;

procedure TUSPG48TESTF.CwIndexBtnClick(Sender: TObject);
begin
  val(IndexEdit.Text,indexData,check);
  if check <> 0 then exit;
  if SHModeF then
  if not NESModeset then exit;
  CTDDataFullWrite(wBsn, wAxis, CTD_PLUS_PRESET_PULSE_DRIVE, indexData);
end;

procedure TUSPG48TESTF.CCwIndexBtnClick(Sender: TObject);
begin
  val(IndexEdit.Text,indexData,check);
  if check <> 0 then exit;
  if SHModeF then
    if not NESModeset then exit;
  CTDDataFullWrite(wBsn, wAxis, CTD_MINUS_PRESET_PULSE_DRIVE, indexData);
end;


procedure TUSPG48TESTF.ZeroRtnBtnClick(Sender: TObject); 	// ゼロ位置移動
var
  ITCounter: DWord;
begin
  Edit2.Text := '';
  Ack := CTDDataFUllRead(wBsn, wAxis, CTD_INTERNAL_COUNTER_READ,ITCounter);
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  if integer(ITCounter) > 0 then
      Ack := CTDDataFullWrite(wBsn, wAxis, CTD_MINUS_PRESET_PULSE_DRIVE, ITCounter)
    else
    begin
      ITCounter := 0 - integer(ITCounter);
      Ack := CTDDataFullWrite(wBsn, wAxis, CTD_PLUS_PRESET_PULSE_DRIVE, ITCounter)
    end;
  if not ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
end;

procedure TUSPG48TESTF.SlowStopBtnClick(Sender: TObject);
begin
  Edit2.Text := '';
  Ack := CTDCommandWrite(wBsn, wAxis, CTD_SLOW_DOWN_STOP);
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
    end;
end;

procedure TUSPG48TESTF.InternalCouterBtnClick(Sender: TObject);
var
  EXTCounter: Dword;
begin
  Edit1.Text := '';
  Edit2.Text := '';
// Ack := CTDGetExternalCounter(wBsn, wAxis, EXTCounter);
  Ack := CTDGetInternalCounter(wBsn, wAxis, EXTCounter);
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  Edit1.Text := intTostr(integer(EXTCounter));
end;

procedure TUSPG48TESTF.DeviceOpen;
begin
  wBsn := CTD_USPG48_ID or 0; 	// USPG48_ID + USB ADDr
  chk := CTDCreate(wBsn);
  if chk < 0 then
    begin
      Err := CTDGetLastError(wBsn);
      Edit1.Text := CTDGetErrorStr(Err);
      AxisIniBtn.Enabled := False;
    end
    else
    begin
      OpenBtn.Enabled := False;
      Edit2.Text := '軸初期化してください。';
    end;
end;

procedure TUSPG48TESTF.BtnFalseSet;
begin
  OriginBtn.Enabled := False;
  CwIndexBtn.Enabled := False;
  CCwIndexBtn.Enabled := False;
  ZeroRtnBtn.Enabled := False;
  SlowStopBtn.Enabled := False;
  InternalCouterBtn.Enabled := False;

  SModesetbtn.Enabled := False;
  DMODbtn.Enabled := False;
  UDESmodebtn.Enabled := False;
  CwScanBtn.Enabled := False;
  CCwScanBtn.Enabled := False;
  RangeReadbtn.Enabled := False;
  AbsBtn.Enabled := False;
  ObjectspeedBtn.Enabled := False;

  LowSpeedBtn.Enabled := False;
  HiSpeedBtn.Enabled := False;
end;

procedure TUSPG48TESTF.FormCreate(Sender: TObject);
var
  Ini: TIniFile;
begin
  Edit1.Text := '';
  Edit2.Text := '';
  Ready1Edit.Text := '';
  Ready2Edit.Text := '';
  Ready3Edit.Text := '';
  Ready4Edit.Text := '';
  AxisNoEdit.Text := '1';
  BtnFalseSet;
  DeviceOpen;

  Ini :=TIniFile.Create(ChangeFileExt(Application.ExeName,'.INI' ));
  try
    Top := Ini.ReadInteger('Form','Top',100 );
    Left := Ini.ReadInteger('Form','Left',100 );
    LowSpeedEdit.Text := Ini.ReadString('CtdSpeed','LowSpeed','200');
    HiSpeedEdit.Text := Ini.ReadString('CtdSpeed','HiSpeed','6000');
    RiseEdit.Text := Ini.ReadString('CtdSpeed','RiseTime','200');
    DownEdit.Text := Ini.ReadString('CtdSpeed','DownTime','500');
    SRatioEdit.Text := Ini.ReadString('CtdSpeed','SRatio%','100');
    AxisNoEdit.Text := Ini.ReadString('AxisNo','Axis','1');
    AbsEdit.Text := Ini.ReadString('AbsPulses','AbsNo','0');
    IndexEdit.Text := Ini.ReadString('IndexPulses','Index','1000');

    if Ini.ReadBool('Form', 'InitMax', false) then
        WindowState := wsMaximized
      else
        WindowState := wsNormal;
  finally
    Ini.Free;
  end;
end;

procedure TUSPG48TESTF.FormClose(Sender: TObject; var Action: TCloseAction);
var
  Ini: TIniFile;
begin
  CTDClose(wBsn);

  Ini :=TIniFile.Create(ChangeFileExt(Application.ExeName,'.INI' ));
  try
    Ini.WriteInteger('Form','Top',Top);
    Ini.WriteInteger('Form','Left',Left);
    Ini.WriteString('CtdSpeed','LowSpeed',LowSpeedEdit.Text);
    Ini.WriteString('CtdSpeed','HiSpeed',HiSpeedEdit.Text);
    Ini.WriteString('CtdSpeed','RiseTime',RiseEdit.Text);
    Ini.WriteString('CtdSpeed','DownTime',DownEdit.Text);
    Ini.WriteString('CtdSpeed','SRatio%',SRatioEdit.Text);
    Ini.WriteString('AxisNo','Axis',AxisNoEdit.Text);
    Ini.WriteString('AbsPulses','AbsNo',AbsEdit.Text);
    Ini.WriteString('IndexPulses','Index',IndexEdit.Text);

    Ini.WriteBool('Form', 'InitMax', WindowState = wsMaximized);
  finally
    Ini.Free;
  end;
end;

function TUSPG48TESTF.NESModeset: boolean;
var
  b : byte;
begin
  Result := False;
  Ack := CTDGetDriveStatus(wBsn, wAxis, b); 	//ドライブステータス 読み込み
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  if (b and $01 = $01) then
    begin
      Edit2.Text := 'Busy';
      exit; 				// Busy だったら終了
    end;
  val(IndexEdit.Text, indexData, check);
  if check <> 0 then exit;
  chk := LeftSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime, DownTime, SRate);
// S 残パルス指定速度設定 起動速度pps, 目標速度pps, 起動時間msec, 減速時間mse S時間%
  if chk = 0 then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  Result := true;
end;

procedure TUSPG48TESTF.SModesetbtnClick(Sender: TObject);
begin
  Edit2.Text := '';
  if not SpeedDataInput then exit;
  Chk:= CTDSpeedWrite(wBsn, wAxis, 100); 	// 速度100% CTDSpeedParameterWriteの時のみ有効
  if chk = 0 then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end
    else
    begin
      SHModeF := True;
      LowSpeedBtn.Enabled := False;
      HiSpeedBtn.Enabled := False;
    end;
  val(IndexEdit.Text, indexData, check);
  if check <> 0 then exit;
  LeftSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime, DownTime, SRate); 	// 残パルス指定速度設定
end;

procedure TUSPG48TESTF.DMODbtnClick(Sender: TObject); 	// UpDown時間等しい直線加速設定
begin
  if not SpeedDataInput then exit;
  Chk:= CTDSpeedWrite(wBsn, wAxis, 100); 	// 速度100% CTDSpeedParameterWriteの時のみ有効
  if chk = 0 then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  Edit2.Text := '';
  chk := StraightSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime); 	// 直線起動設定 起動速度pps 目標速度pps 起動減速時間msec
  if chk = 0 then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  SHModeF := False;
  LowSpeedBtn.Enabled := False;
  HiSpeedBtn.Enabled := False;
end;

procedure TUSPG48TESTF.UDESmodebtnClick(Sender: TObject); 	// UpDown時間等しいS時モード設定
begin
  if not SpeedDataInput then exit;
  Edit2.Text := '';
  Chk:= CTDSpeedWrite(wBsn, wAxis, 100); 	// 速度100% CTDSpeedParameterWriteの時のみ有効
  if chk = 0 then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
// if False = CTDMode1Write(wBsn, wAxis, $40) then Exit; 	// CTDSpeedParameterWrite 使用時は
  if False = CTDMode1Write(wBsn, wAxis, $60) then Exit; 	// 減速自動計算モードに切り替え
  if False = CTDDataFullWrite(wBsn, wAxis, CTD_SLOW_DOWN_REAR_PULSE_WRITE, 0) then 	// 残パル数0に設定
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      Exit;
    end;
  chk := CTDSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime, SRate); 	// 起動速度pps 目標速度pps 起動減速時間msec S時間 %
  if chk = 0 then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  SHModeF := False;
  LowSpeedBtn.Enabled := True;
  HiSpeedBtn.Enabled := True;
end;

procedure TUSPG48TESTF.HiSpeedBtnClick(Sender: TObject);
begin
  Chk:= CTDSpeedWrite(wBsn, wAxis, 100); 	// 速度100% CTDSpeedParameterWriteの時のみ有効
  if chk = 0 then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
    end;
end;

procedure TUSPG48TESTF.LowSpeedBtnClick(Sender: TObject);
begin
  Chk:= CTDSpeedWrite(wBsn, wAxis, 50); 	// 速度50% CTDSpeedParameterWriteの時のみ有効
  if chk = 0 then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
    end;
end;

procedure TUSPG48TESTF.CwScanBtnClick(Sender: TObject);
begin
  Ack := CTDCommandWrite(wBsn, wAxis, CTD_PLUS_CONTINUOUS_DRIVE);
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
    end;
end;

procedure TUSPG48TESTF.CCwScanBtnClick(Sender: TObject);
begin
  Ack := CTDCommandWrite(wBsn, wAxis, CTD_MINUS_CONTINUOUS_DRIVE);
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
    end;
end;

procedure TUSPG48TESTF.RangeReadbtnClick(Sender: TObject); 	// Range 読み出し
begin
  if False = CTDDataHalfRead(wBsn, wAxis, CTD_RANGE_READ, RANGE_DATA) then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      Exit;
    end;
  Edit2.Text := intTostr(RANGE_DATA);
end;

procedure TUSPG48TESTF.Timer1Timer(Sender: TObject);
var
  Loopd: word; 				// Axis
begin
  for Loopd := 0 to 3 do
    begin
      if not CTDGetDriveStatus(wBsn, Loopd, Bdata) then
        begin
          Err := CTDGetLastError(wBsn);
          if Err = CTD_ERR_USB_REMOVE then
            begin
              Timer1.Enabled := False;
              Edit2.Text := 'デバイスが取り外されました。';
              CTDClose(wBsn);
              BtnFalseSet;
            end;
          if Err = CTD_ERR_TRANS then
            begin
              Timer1.Enabled := False;
              Edit2.Text := '通信エラーです。';
              CTDClose(wBsn);
              BtnFalseSet;
            end;
          exit; 				//ドライブステータス 読み込み
        end;
      if Bdata and $01 = 0 then
        begin 				// Drive 終了
          ReadyF[Loopd] := True;
          case Loopd of
             0: Ready1Edit.Text := 'Reay';
             1: Ready2Edit.Text := 'Reay';
             2: Ready3Edit.Text := 'Reay';
             3: Ready4Edit.Text := 'Reay';
          end;
        end
        else
        begin
          ReadyF[Loopd] := False;
          case Loopd of
             0: Ready1Edit.Text := 'Not Reay';
             1: Ready2Edit.Text := 'Not Reay';
             2: Ready3Edit.Text := 'Not Reay';
             3: Ready4Edit.Text := 'Not Reay';
          end;
        end;
    end;
end;

procedure TUSPG48TESTF.OpenBtnClick(Sender: TObject);
begin
  DeviceOpen;
end;

procedure TUSPG48TESTF.ObjectspeedBtnClick(Sender: TObject); // 速度データー読み出し
var
  SPEeD_DATA :word;
  LSPeD_Data :word;
begin
  if False = CTDDataHalfRead(wBsn, wAxis, CTD_OBJECT_SPEED_DATA_READ, SPEeD_DATA) then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      Exit;
    end;
  if False = CTDDataHalfRead(wBsn, wAxis, CTD_START_STOP_SPEED_DATA_READ, LSPeD_Data) then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      Exit;
    end;
  Edit1.Text := intTostr(SPEeD_DATA);
  Edit2.Text := intTostr(LSPeD_Data);
end;

procedure TUSPG48TESTF.AbsBtnClick(Sender: TObject); // 指定位置移動
var
  ITCounter : Dword;
  AbsData : integer;
begin
  val(AbsEdit.Text, absData, check);
  if check <> 0 then exit;
  Ack := CTDDataFUllRead(wBsn, wAxis, CTD_INTERNAL_COUNTER_READ,ITCounter); // 現在位置取得
  if not Ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
  ITCounter := integer(ITCounter) - AbsData; 	// 移動量計算
  if integer(ITCounter) > 0 then
      Ack := CTDDataFullWrite(wBsn, wAxis, CTD_MINUS_PRESET_PULSE_DRIVE, ITCounter)
    else
    begin
      ITCounter := 0 - integer(ITCounter);
      Ack := CTDDataFullWrite(wBsn, wAxis, CTD_PLUS_PRESET_PULSE_DRIVE, ITCounter)
    end;
  if not ack then
    begin
      Err := CTDGetLastError(wBsn);
      Edit2.Text := CTDGetErrorStr(Err);
      exit;
    end;
end;

procedure TUSPG48TESTF.MinimumBtnClick(Sender: TObject);
begin
  val(IndexEdit. Text,indexData, check);
  if check <> 0 then exit;
  if not SpeedDataInput then exit;
  LeftSpeedParameterWrite(wBsn, wAxis, LowSpeed, HiSpeed, RiseTime, DownTime, SRate); // 残パルス指定速度設定
end;

initialization

  RANGE_DATA := 100;
end.
unit CTD20DLL;

interface

uses Types;




//-----------------------------------------------------------------
// Error code
//-----------------------------------------------------------------
const
  CTD_SUCCESS 		= 0; 		// 異状なし(正常終了)
  CTD_ERR_NO_DEVICE 	= 2; 		// 使用可能なデバイスがありません
  CTD_ERR_IN_USE 		= 3; 		// 指定のデバイスは使用中です
  CTD_ERR_INVALID_BSN 	= 4; 		// 無効なボードセレクトナンバーです
// デバイスがバス上にないか
// 使用宣言されていません
  CTD_ERR_INVALID_PORT 	= 6; 		// 不正なポートを要求した
  CTD_ERR_PARAMETER 	= 7; 		// 引数の値が範囲外です
  CTD_ERR_INVALID_AXIS 	= 50; 		// 無効な制御軸を要求した
  CTD_ERR_TRANS 		= 60; 		// 送信時の通信エラーです
  CTD_ERR_RECEIVE 		= 61; 		// 受信時の通信エラーです
  CTD_ERR_USB_REMOVE 	= 62; 		// デバイスが取り外されました
  CTD_ERR_WRAPDLL 		= $FFFFFFFF; 	// ラッパー関数内エラー DWord - 1
//-----------------------------------------------------------------
// Axis
//-----------------------------------------------------------------
  CTD_AXIS_1 = 0;
  CTD_AXIS_2 = 1;
  CTD_AXIS_3 = 2;
  CTD_AXIS_4 = 3;
//-----------------------------------------------------------------
// I/O Map
//-----------------------------------------------------------------
  CTD_PORT_DATA1 			= 0;
  CTD_PORT_DATA2 			= 1;
  CTD_PORT_DATA3 			= 2;
  CTD_PORT_DATA4 			= 3;
  CTD_PORT_COMMAND 		= 4;
  CTD_PORT_MODE1 			= 5;
  CTD_PORT_MODE2 			= 6;
  CTD_PORT_UNIVERSAL_SIGNAL 	= 7;
  CTD_PORT_DRIVE_STATUS 		= 4;
  CTD_PORT_END_STATUS 		= 5;
  CTD_PORT_MECHANICAL_SIGNAL 	= 6;
//-----------------------------------------------------------------
// command
//-----------------------------------------------------------------
  CTD_RANGE_WRITE 				= $00;
  CTD_RANGE_READ 				= $01;
  CTD_START_STOP_SPEED_DATA_WRITE 		= $02;
  CTD_START_STOP_SPEED_DATA_READ 		= $03;
  CTD_OBJECT_SPEED_DATA_WRITE 		= $04;
  CTD_OBJECT_SPEED_DATA_READ 		= $05;
  CTD_RATE1_DATA_WRITE 			= $06;
  CTD_RATE1_DATA_READ 			= $07;
  CTD_RATE2_DATA_WRITE 			= $08;
  CTD_RATE2_DATA_READ 			= $09;
  CTD_RATE3_DATA_WRITE 			= $0A;
  CTD_RATE3_DATA_READ 			= $0B;
  CTD_RATE_CHANGE_POINT_1_2_WRITE 		= $0C;
  CTD_RATE_CHANGE_POINT_1_2_READ 		= $0D;
  CTD_RATE_CHANGE_POINT_2_3_WRITE 		= $0E;
  CTD_RATE_CHANGE_POINT_2_3_READ 		= $0F;
  CTD_SLOW_DOWN_REAR_PULSE_WRITE 		= $10;
  CTD_SLOW_DOWN_REAR_PULSE_READ 		= $11;
  CTD_NOW_SPEED_DATA_READ 			= $12;
  CTD_DRIVE_PULSE_COUNTER_READ 		= $13;
  CTD_PRESET_PULSE_DATA_OVERRIDE 		= $14;
  CTD_PRESET_PULSE_DATA_READ 		= $15;
  CTD_DEVIATION_DATA_READ 			= $16;
  CTD_INPOSITION_WAIT_MODE1_SET 		= $17;
  CTD_INPOSITION_WAIT_MODE2_SET 		= $18;
  CTD_INPOSITION_WAIT_MODE_RESET 		= $19;
  CTD_ALARM_STOP_ENABLE_MODE_SET 		= $1A;
  CTD_ALARM_STOP_ENABLE_MODE_RESET 		= $1B;
  CTD_SLOW_DOWN_STOP 			= $1E;
  CTD_EMERGENCY_STOP 			= $1F;
  CTD_PLUS_PRESET_PULSE_DRIVE 		= $20;
  CTD_MINUS_PRESET_PULSE_DRIVE 		= $21;
  CTD_PLUS_CONTINUOUS_DRIVE 		= $22;
  CTD_MINUS_CONTINUOUS_DRIVE 		= $23;
  CTD_PLUS_SIGNAL_SEARCH1_DRIVE 		= $24;
  CTD_MINUS_SIGNAL_SEARCH1_DRIVE 		= $25;
  CTD_PLUS_SIGNAL_SEARCH2_DRIVE 		= $26;
  CTD_MINUS_SIGNAL_SEARCH2_DRIVE 		= $27;
  CTD_INTERNAL_COUNTER_WRITE 		= $28;
  CTD_INTERNAL_COUNTER_READ 		= $29;
  CTD_INTERNAL_COMPARATE_DATA_WRITE 		= $2A;
  CTD_INTERNAL_COMPARATE_DATA_READ 		= $2B;
  CTD_EXTERNAL_COUNTER_WRITE 		= $2C;
  CTD_EXTERNAL_COUNTER_READ 		= $2D;
  CTD_EXTERNAL_COMPARATE_DATA_WRITE 		= $2E;
  CTD_EXTERNAL_COMPARATE_DATA_READ 		= $2F;
  CTD_INTERNAL_PRE_SCALE_DATA_WRITE 		= $30;
  CTD_INTERNAL_PRE_SCALE_DATA_READ 		= $31;
  CTD_EXTERNAL_PRE_SCALE_DATA_WRITE 		= $32;
  CTD_EXTERNAL_PRE_SCALE_DATA_READ 		= $33;
  CTD_CLEAR_SIGNAL_SELECT 			= $34;
  CTD_ONE_TIME_CLEAR_REQUEST 		= $35;
  CTD_FULL_TIME_CLEAR_REQUEST 		= $36;
  CTD_CLEAR_REQUEST_RESET 			= $37;
  CTD_REVERSE_COUNT_MODE_SET 		= $38;
  CTD_REVERSE_COUNT_MODE_RESET 		= $39;
  CTD_NO_OPERATION 			= $3A;
  CTD_STRAIGHT_ACCELERATE_MODE_SET 		= $84;
  CTD_US_STRAIGHT_ACCELERATE_MODE_SET 	= $85;
  CTD_S_CURVE_ACCELERATE_MODE_SET 		= $86;
  CTD_US_S_CURVE_ACCELERATE_MODE_SET 	= $87;
  CTD_SW1_DATA_WRITE 			= $88;
  CTD_SW1_DATA_READ 			= $89;
  CTD_SW2_DATA_WRITE 			= $8A;
  CTD_SW2_DATA_READ 			= $8B;
  CTD_SLOW_DOWN_LIMIT_ENABLE_MODE_SET 	= $8C;
  CTD_SLOW_DOWN_LIMIT_ENABLE_MODE_RESET 	= $8D;
  CTD_EMERGENCY_LIMIT_ENABLE_MODE_SET 	= $8E;
  CTD_EMERGENCY_LIMIT_ENABLE_MODE_RESET 	= $8F;
  CTD_INITIAL_CLEAR 			= $90;

  CTD_USPG48_ID : Word = $0000; 	// 上位バイトが機種ID

//-----------------------------------------------------------------
// Misc
//-----------------------------------------------------------------
  CTD_MAX_SLOTS = 16;
//-----------------------------------------------------------------
// Additional 定数
//-----------------------------------------------------------------
  FCLK = 32768000; 		// 32.768MHz

//-----------------------------------------------------------------
// 補間パラメーター
//-----------------------------------------------------------------

type
  CTIPDRIVEPARAMETER = record
  bIpAxis 	: array[0..3] of Byte; 		// 補間軸
  bIpKind 	: array[0..0] of Byte; 		// 補間種類
  bMovekind 	: array[0..0] of Byte; 		// 0=相対座標 1=絶対座標
  lObjPoint 	: array[0..1] of Longint; 		// 目標位置 [0]=X軸 [1]=Y軸
  lCenterPoint	: array[0..1] of Longint; 		// 中心位置 [0]=X軸 [1]=Y軸
  lN2Data1 	: array[0..0] of Longint; 		//
  lN2Data2 	: array[0..0] of Longint; 		//
  lN2Data3 	: array[0..0] of Longint; 		//
  bIpconsin 	: array[0..0] of Byte; 		// 1=連続補間 0=補間
  bEndkind 	: array[0..0] of Byte; 		// 0=減速停止 1=急停止
  bDrawIn 	: array[0..0] of Byte; 		// 引き込み制御 0=無効 1=有効
end;

//--------------------------------------------------------------------
// バージョン読み出し用
//--------------------------------------------------------------------
  Verchar = array[0..32] of Ansichar; 		// バージョン読み出し用文字配列型
var
  Versionchar: verchar;

//-----------------------------------------------------------------
// API Functions
//-----------------------------------------------------------------
  function CTDCreate(wBsn: Word): Smallint; stdcall external 'CTD20.Dll';
  function CTDClose(wBsn: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDWrite(wBsn: Word; var str: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDReadData(wBsn: Word; var str: Byte; Status, kind, cmd, asxis: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDRead(wBsn: Word; var str: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDwrData(wBsn: Word; var str: Byte): LongBool; stdcall external 'CTD20.Dll';

//----------ダイレクト制御専用 関数----------------------------------------------------
  function CTDGetLibVersion(var pbLibVersion: verchar): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetDrvVersion(var pbDrvVersion: verchar): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetRomVersion(wBsn: Word; var pbRomVersion: verchar): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetLastError(wBsn: Word): DWord; stdcall external 'CTD20.Dll';
  function CTDDeviceStatus(wBsn: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDInPort(wBsn, wAxis, wPort: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDOutPort(wBsn, wAxis, wPort: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetDriveStatus(wBsn, wAxis: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetEndStatus(wBsn, wAxis: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetMechanicalSignal(wBsn, wAxis: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetUniversalSignal(wBsn, wAxis: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetInternalCounter(wBsn, wAxis: Word; var pdwData: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetExternalCounter(wBsn, wAxis: Word; var pdwData: Dword): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetNowSpeedData(wBsn, wAxis: Word; var pwData: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetDrivePulseCounter(wBsn, wAxis: Word; var pdwData: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDMode1Write(wBsn, wAxis: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDMode2Write(wBsn, wAxis: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDUniversalSignalWrite(wBsn, wAxis: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDDataHalfRead(wBsn, wAxis: Word; bCmd: Byte; var pwData: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDDataFullRead(wBsn, wAxis: Word; bCmd: Byte; var pdwData: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDCommandWrite(wBsn, wAxis: Word; bdata: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDDataHalfWrite(wBsn, wAxis: Word; bdata: Byte; wdata: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDDataFullWrite(wBsn, wAxis: Word; bdata: Byte; dwdata: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDLineFallOut(wBsn, wAxis, wdata: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDStartSignalWrite(wBsn: Word; dwdata: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetAxisStatus(wBsn: Word; var pbData: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetAxisAllPort(wBsn, wAxis: Word; var pdwData: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDSetIpParameter(wBsn: Word; var pDriveParameter: CTIPDRIVEPARAMETER; wIndex: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDIpExe(wBsn, wcmd: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDIpExeSub(wBsn, wcmd: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDIpReset(wBsn: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDIpSpeedPush(wBsn: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDIpSpeedPop(wBsn: Word): LongBool; stdcall external 'CTD20.Dll';
  function CTDIpStraight(wBsn: Word; var blpAxis: Ansichar; l0bjx,l0bjy: integer; var IN2, integer; bDrawin, bspd:Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDIpStraightE(wBsn: Word; var blpAxis: Ansichar; l0bjx,l0bjy: integer; var IN2, integer; bDrawin, bspd:Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetIpPulse(wBsn, wAxis: Word; var pdwDara: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDSetIpPulse(wBsn, wAxis: Word; dwDara: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetIpIoRead(wBsn, wAxis: Word; var pdwDara: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDSetIpIoWrite(wBsn, wAxis: Word; dwDara: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetIoRead(wBsn, wAxis: Word; var pdwDara: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDSetIoWrite(wBsn, wAxis: Word;var pdwDara: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDGetIpStepNo(wBsn, wAxis: Word;var pdwStepNo: DWord): LongBool; stdcall external 'CTD20.Dll';
  function CTDlpParaSet(bMoveKind, blpconsin, bDrawln: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDlpAxisSet(blpAxis1, blpAxis2, blpAxis3, blpAxis4: Byte): LongBool; stdcall external 'CTD20.Dll';
  function CTDlpDataSet(wBsn: Word; blpkind: Byte; l0bjx, l0BJy, lCenterX, lCenterY, lN2D2, lN2D3,lN2D4: integer; wStepNo: Word): LongBool; stdcall external 'CTD20.Dll';

  function CTDSpeedParameterWrite(wBsn, wAxis: Word; dLowSpeed, dHighSpeed: Double; sAccTime: Word; dSRate: Double): Word; stdcall external 'CTD20.Dll';
  function CTDSpeedParameterRead(wBsn, wAxis: Word; var pdLowSpeed, pdHighSpeed: Double; var psAccTime: Word; var pdSRate: Double): WordBool; stdcall external 'CTD20.Dll';
  function CTDSpeedWrite(wBsn, wAxis: Word; dObjSpeed: Double): Word; stdcall external 'CTD20.Dll';
  function CTDSpeedRead(wBsn, wAxis: Word; var pdObjSpeed: Double): LongBool; stdcall external 'CTD20.Dll';

//----------------- エラー内容取得用 -----------------------------------------------
  function CTDGetErrorStr(ErrorCoad: Dword): string;

implementation

function CTDGetErrorStr(ErrorCoad: Dword): string;
begin
  case ErrorCoad of
    CTD_SUCCESS 		: Result := '異状なし(正常終了)。';
    CTD_ERR_NO_DEVICE 	: Result := '使用可能なデバイスがありません。';
    CTD_ERR_IN_USE 	: Result := '指定のデバイスは使用中です。';
    CTD_ERR_INVALID_BSN 	: Result := '無効なボードセレクトナンバーです' + #13#10 +
				   'デバイスがバス上にないか' + #13#10 +
				   '使用宣言されていません。';
    CTD_ERR_INVALID_PORT 	: Result := '不正なポートを要求した。';
    CTD_ERR_PARAMETER 	: Result := '引数の値が範囲外です。';
    CTD_ERR_INVALID_AXIS 	: Result := '無効な制御軸を要求した。';
    CTD_ERR_TRANS 		: Result 	:= '送信時の通信エラーです。';
    CTD_ERR_RECEIVE 	: Result := '受信時の通信エラーです。';
    CTD_ERR_USB_REMOVE 	: Result := 'デバイスが取り外されました。';
    CTD_ERR_WRAPDLL 	: Result := 'ラッパー関数内エラー。;'
    else 		  Result := 'その他のエラー';
  end;
end;

end.


最初に戻る