APIバッファーを使用するときは、値が保持されるタイミングに注意してコーディングを行う日y津陽があります。ここではよくある不具合についてご説明いたします。
GetOutBit関数が期待通りに動作しない
APIバッファーを使用したときWMX3ApiCLR.IoのGetOutBit関数は正常に動作しません。常に0を返します。Ioの0bit目をONにした状態で、APIバッファーの記録中はGetOutBit関数の値は期待値になりません。(値が0となっています)
解決方法 APIのIFブランチで状態判定を遅らせる必要があります
APIバッファー記録中はGetOutBit関数の代わりに、ApiBufferConditionのArg_IOOutputを使用し、if文と同等の動作を行います。(IFブランチ機能)
もう一つ注意があり、IFブランチの中に通常の変数を入れることができません。コンパイルエラーにはなりませんが、API記録中の状態が入るため期待通りの動きにはなりません。 そのため、変数値の遅延を行うためにユーザーメモリ機能を使用することになります。
IFブランチ機能とユーザーメモリを使用した、リアルタイム動作
APIバッファーを使用するときの動作が期待通りになる、サンプルを作成し検証しました。
このサンプルコードでは、デジタル出力の0bit目がONのとき、ユーザーメモリの0bit目をONします。
デジタル出力の0bit目がOFFのとき、ユーザーメモリの1bit目をONします。
ブレークポイントを使用したステップ実行では、Buffer.FlowIf(BuffCond);とBuffer.FlowElse();の両方を通ることが確認できます。両方のコードを通りますが、APIバッファの実行時にその時のI/Oの状態でどちらかが実行されるようになります。
検証を行ったコード
IFブランチの判定は、デジタル入力や、ユーザーメモリなど多数の種類が選択できます。※WMX3.6で検証したコード
private void APIバッファーでデジタル出力の状態でユーザーメモリを変更()
{
// APIバッファー作成
uint ApiChannelNo = 1;
var Buffer = new ApiBuffer(API);
Buffer.Clear(ApiChannelNo); // 以前動作させたバッファー内容のクリア
Buffer.CreateApiBuffer(ApiChannelNo);
// APIバッファー設定
var op = new ApiBufferOptions();
Buffer.GetOptions(ApiChannelNo, ref op); // 現在の設定の取得
op.AutoRewind = false; // true=最後の処理の後、バッファの最初のAPIから実行が継続
op.StopOnLastBlock = true; // true=最後の処理の後、APIバッファをStop状態にする
Buffer.SetOptions(ApiChannelNo, op); // 設定の書き込み
// APIバッファーへ記録開始
Buffer.StartRecordBufferChannel(ApiChannelNo);
// ↓ここからは記録のみで動作は行いません(遅延動作)
//APIのIFブランチを設定
var BuffCond = new ApiBufferCondition(); // ifの条件を設定する
BuffCond.BufferConditionType = ApiBufferConditionType.IOOutput; // デジタル出力の状態で判断(GetOutBitと同等の動き)
BuffCond.Arg_IOOutput.ByteAddress = 0; // 参照先の指定
BuffCond.Arg_IOOutput.BitAddress = 0; // 参照先の指定
BuffCond.Arg_IOOutput.Invert = 0; // 0=出力ビットが1のときにTRUEと評価
var usMemo = new WMX3ApiCLR.UserMemory(API); // WMX3Apiを代入するコンストラクタが必須です!
Buffer.FlowIf(BuffCond); // 遅延ifの開始
{ // ONの時
usMemo.SetMBit(0, 0, 1); // ユーザーメモリの0bit目をON
// [注意]この中に変数を入れてはいけません。(バッファー記録中の値になってしまいます)
//var BitDate = 1;
}
Buffer.FlowElse();
{
// OFFの時
usMemo.SetMBit(0, 1, 1); // ユーザーメモリの1bit目をON
}
Buffer.FlowEndIf(); // 遅延ifの終了
// APIバッファチャネルへのAPIの記録を終了
Buffer.EndRecordBufferChannel();
// APIバッファー処理開始(リアルタイム動作)
Buffer.Execute(ApiChannelNo); // ApiBuffer実行
ApiBufferStatus status = new ApiBufferStatus();
while (true) // API動作が終了するまで待機
{
Buffer.GetStatus(ApiChannelNo, ref status);
if (status.State == ApiBufferState.Stop) // 動作していない時
{
break; // API処理が完了した
}
}
}
【サンプル】APIバッファーを使用しないときの動作(Windowsスレッド)
通常の動作ではGetOutBit関数は期待通りに動作します。 APIバッファーが必要ない場面ではこちらを使用する方がスマートで良いです。
出力がONのときの状態を読むと、変数の値は1なので期待通り。
出力がONのときの状態を読むと、変数の値は0なので期待通り。
コメント