C++でNIのDAQmxを使用したプログラミングをした話
背景
ナショナルインスツルメンツの機器を使用して、trigger信号をうけて、アナログ信号を受信するアプリを作成した。その際に使用した基本の関数と、困ったことに関するメモです。
準備
NI-DAQmxをインストール
下記がNIのサイトです。そして当然ですが、NIの機器ないと、意味ないです。
基本コーディング
DAQmxをインストールすると、サンプルプログラムが一緒にインストールされる。ので、基本的に同様にすれば実装可能でした。正確にはC++用サンプルはないのですが、C用のものがあるのでそれが参考になります。
C++用に作るにあたり、一工夫必要になるのはcallback関数のところぐらいです。後はちょこちょこ困ったことをメモ。
問題1 callbackどうするんだっけ?
久しぶりのC++実装でcallbackでちょっと躓く(照)
デフォルトはDAQmxのサンプルコードにもあったこの関数↓だったのですが、
int32 CVICALLBACK MyClass::EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples)
C++で実装するときはラッパーが必要です。MyClassはクラス化したので、ついてるだけです。
int32 CVICALLBACK MyClass::EveryNCallbackWrapper(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void* callbackData)
{
MyClass* obj = static_cast<MyClass*>(callbackData);
return obj->EveryNCallback(taskHandle, everyNsamplesEventType, nSamples);
}
ちなみに呼び出し側は、
DAQmxRegisterEveryNSamplesEvent(this->task_handle, DAQmx_Val_Acquired_Into_Buffer, this->sample_num, 0, &this->EveryNCallbackWrapper, this);
というかんじで呼び出します。ラッパーにthisがわたされて、無事に色々できるようになります。
問題2 複数チャンネル使用時の指定
チャンネルが1つだと素直にいけたんですが、複数使用すると意外とわかりにくかった。アナログ受信しようとすると最低限使用するものの中で、サンプリング数の指定が必要なのは下記のあたりの関数だと思います。設定メモです。
- DAQmxCreateAIVoltageChan()で物理チャンネルを正確に指定
- DAQmxCfgSampClkTiming()で指定するサンプリング数は1ch分の数を指定
- DAQmxRegisterEveryNSamplesEvent()で指定するサンプリング数も1ch分の数を指定
- DAQmxSetBufInputBufSize() これを追加して、複数チャンネルxサンプリング数を指定
- DAQmxReadAnalogF64()で指定するサンプリング数は1ch分で、用意する配列は複数チャンネルxサンプリング数のものを用意
問題3 トリガーの設定
外部入力のアナログトリガーを使ったのですが、まずその関数が見つからない。デジタルはすぐ見つかったのに。
DAQmxCfgAnlgEdgeStartTrig()
でした。ここでまた躓いたのが、物理チャンネル。使用したNIの機器によるんだと思うのですが、APFI0
以外だと動作しませんでした。ai0でもよいって書いてあったので、それでやろうとして色々頑張ったのですが、できず。諦めました。APFI0のポートあるしね。
以下の3つが今回必要な関数でした
- DAQmxCfgAnlgEdgeStartTrig():triggerの設定
- DAQmxSetAnlgEdgeStartTrigHyst():ヒステリシスの設定
- DAQmxSetStartTrigRetriggerable():トリガー→サンプリング→トリガー→サンプリングを繰り返すなら、設定が必要。ちなみにこの場合、
DAQmxCfgSampClkTiming()
の引数で有限サンプリングを指定して、これを使用する。このへんがよくわからず試行錯誤しました。
やりたいことって一人ひとり違うので難しいものですよね。誰かの参考になるといいな。
Discussion