この記事で扱っていること
- デジタルタスクでカウンタもどきの操作をする方法
を紹介しています。
注意:すべてのエラーを確認しているわけではないので、記事の内容を実装する際には自己責任でお願いします。また、エラー配線は適当な部分があるので適宜修正してください。
LabVIEWで操作するDAQハードウェアには、エンコーダからの信号を入力してエッジを数えたり、信号のデューティー比や周波数を測定することができるカウンタ機能があります(ないものもあります)。
ただ、カウンタは一つのハードウェアに対して数に限りがあり、多くの信号を扱うことができません。
一方で、デジタルの入出力においては1つのポートに対しラインが複数(8つなど)あり、多くの信号を扱うことができます。
デジタルの入出力であってもソフトウェア的に処理することでカウンタのタスクと似たような機能を持たせることができるため、多くのデジタル信号を扱う際にカウンタタスクではなくデジタルタスクとしてエッジカウントやデューティー比および周波数測定を行えると便利だったりします。
本記事ではそのようなプログラムの構成例を紹介しています。
どんな結果になるか
フロントパネルには、デジタル入力用のデバイスを指定する部分とデジタル波形グラフ、そして各ラインで測定したカウント値を表示する数値配列の表示器があります。
実行すると、測定したラインでパルスが来ないと何も変わりませんが、パルス(エッジ)が来るとカウントが増えていきます。
あるいは、各ラインでのエッジカウント値をグラフではなく数値で表示することもできます。
こちらであっても、各ラインごとでエッジカウントしその値を表示させることができます。
ただし、測定されたカウント値は一度に大きく変わることがあります。それは、プログラムの仕組み上、エッジの数をまとめて数えるためです。この点についてはプログラムの構造として以下で紹介します。
プログラムの構造
プログラムの構造としては、各ラインを1チャンネルとしてそれぞれのチャンネルで得られた複数のデジタルデータ(をブール配列にしたもの)に対して「FALSEからTRUE」になったものをカウントしていくというやり方を採用しています。
上で紹介した、グラフ表示、数値配列で表示するどちらのプログラムも理屈は同じです。
まずはグラフ表示する方のプログラムから。
デジタルのタスクは「各ラインで1チャンネル」としています。こうすることで、DAQmx読み取りで「Nチャンネル」と指定して各ラインの値を独立して扱いやすくなります。
また、実際にエッジカウントをしていくWhileループの中では各ループごとにDAQmx読み取りで取得したデータの中しか調べないので、一度にDAQmx読み取りで取得するデータの数を指定しておきます。
例えば「20」としておくと、各ループごとに測定したデジタル値(FalseかTrueか)を20個取得し、その中で「False→True」になった部分があればエッジカウント値を1増やします。これら20個のデータ全てでエッジがあるかを調べてから、カウントした値を表示させます。
そのため、この「一度にDAQmx読み取りで取得するデータの数」が小さいほど、エッジカウント値を細かく知ることができる一方で、値が小さすぎるとバッファからのデータ読み取りが遅すぎてエラーが起こる可能性が出るので注意します。
そしてWhileループに入る前には、配列初期化で、ブールデータとカウント値を記録しておくためのシフトレジスタの初期値を定めています。
ブールデータをためておくのは、あるラインに注目したときに、前のループの最後のブール値を次のループの最初のブール値と比べる事でエッジがあるかどうかを確認するためです。
エッジカウントを行うWhileループの中では、まず外側のForループの自動指標付け有効にした入力トンネルで1ラインで読み取ったブールデータ配列とし、これに対して内側のForループでエッジを検出するためにこのブールデータ配列一つ一つを調べるようにしています。
内側のForループでエッジの数を数え終えたら、その値をWhileループの外側で用意しておいたカウント値を保持している二次元配列に渡します。
カウント値を数値配列で表示する方のブロックダイアグラムも紹介します。
やっていることは同じです。違いといえば、カウント値を保持しておく配列が二次元配列ではなく一次元配列になっていることくらいです。(もちろんこれに伴いForループの中の配列関数の使用法も若干変わりますが)
立下りエッジを検出する場合
上で紹介したプログラムは、エッジカウントとして、立ち上がりエッジを検出していました。もし立下りエッジを検出する場合には「TRUEからFALSE」を検出すればいいので、不等号を逆にすれば対応できます。
そもそも今回のプログラムのキモは、ブールには大小関係があり、FalseよりもTrueの方が「大きい」ということを利用しています。
立ち上がりエッジの場合には「False→True」となっているはずなので、あるタイミングで取られた、m個めのブール値と、(シフトレジスタで得られている)m-1個めのブール値の大小関係を比べ、「(m個めのブール値)> (m-1個めのブール値)」がTrueになっていればエッジがあったと判断できます。
ということは・・・立ち下がりエッジの場合には「True→False」を検出すればいいので、不等号の向きを反転させれば検出することができるようになります。
効率を求めて処理を分ける
上で紹介したプログラムは全ての処理(データ測定から解析まで)を一つのWhileループ内で行っています。
より効率のいいプログラムといえば・・・そう、キューを用いて生産者/消費者ループに分けるやり方ですね。
知っている人にとっては言われるまでもなく書き換えができるとは思いますが、一応プログラムの形の例を以下の図で紹介します。
本記事では、デジタルタスクによってエッジをカウントする方法を紹介してきました。本来はカウンタのタスクとしてエッジカウントができるので使用される場面は限られるかもしれませんが、搭載されたカウンタよりも多くのエッジを測る際の選択肢として参考になればうれしいです。
ここまで読んでいただきありがとうございました。
コメント