基於NI 採集卡,實現訊號實時顯示與儲存,以及濾波
阿新 • • 發佈:2020-12-23
最近一個需求,需要基於NI 採集卡,實現訊號實時顯示與儲存,以及濾波,在研究了NIDAQmx的API說明後,開始在C# 4.0和QT5下實現了相關的邏輯,現在免費分享QT的部分程式碼。如下:
QT5:
1.初始化介面
void NIDAQTest::InitUI() { int size = DAQmxGetSystemInfoAttribute(DAQmx_Sys_DevNames, NULL, 0); if (size > 0) { char *devNames = (char*)malloc(size); //get the device list DAQmxGetSystemInfoAttribute(DAQmx_Sys_DevNames, devNames, size); char* seg = ","; deviceName = strtok(devNames, seg);//only frist dev size = DAQmxGetDeviceAttribute(deviceName, DAQmx_Dev_ProductType, 0); char *dev1Type = (char*)malloc(size); DAQmxGetDeviceAttribute(deviceName, DAQmx_Dev_ProductType, dev1Type, size); ui.lblDeviceInfo->setText(QString("Name: %1 ( %2 ) ").arg(deviceName).arg(dev1Type)); size = DAQmxGetDevAIPhysicalChans(deviceName, NULL, 0); channelNames = (char*)malloc(size); DAQmxGetDevAIPhysicalChans(deviceName, channelNames, size); } else { ui.lblDeviceInfo->setText("No NI Device, please check."); ui.btnStart->setEnabled(false); } ui.cbxFilter->addItem("No filter"); ui.cbxFilter->addItem("Low pass filter"); ui.cbxFilter->addItem("High pass filter"); ui.cbxFilter->addItem("Band pass filter"); ui.cbxFilter->setCurrentIndex(1); ui.btnInputChannel->setVisible(false); ui.btnOutputChannel->setVisible(false); ui.chxTimes->setChecked(true); ui.txtRecordPath->setEnabled(false); ui.btnSave->setEnabled(false); //ui.btnStart->setEnabled(false); ui.btnHoldContinue->setEnabled(false); ui.btnStop->setEnabled(false); }
2.開始過程
void NIDAQTest::on_btnStart_clicked() { if (sizeof(deviceName) == 0) return; int32 error = 0; char errBuff[2048] = { '\0' }; rate = ui.txtRate->value(); sample = ui.txtSamples->value(); QString qChanNames = QString(channelNames); QStringList channs = qChanNames.split(","); error += DAQmxCreateTask("", &taskHandle); //error = DAQmxCreateAIVoltageChan(taskHandle, "Dev1/ai0", "", DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL); int maxCount = MAXCHANN_COUNT; int bSize = sample * maxCount; for (int i = 0; i < maxCount; i++) { error += DAQmxCreateAIVoltageChan(taskHandle, channs[i].toLatin1(), "", DAQmx_Val_Cfg_Default, -5.0, 5.0, DAQmx_Val_Volts, NULL); } error += DAQmxCfgSampClkTiming(taskHandle, "", rate, DAQmx_Val_Rising, DAQmx_Val_ContSamps, sample); error += DAQmxSetBufInputBufSize(taskHandle, bSize * 10); error += DAQmxRegisterEveryNSamplesEvent(taskHandle, DAQmx_Val_Acquired_Into_Buffer, sample, 0, EveryNCallback, NULL); error += DAQmxRegisterDoneEvent(taskHandle, 0, DoneCallback, NULL); error += DAQmxStartTask(taskHandle); if (error < 0) { DAQmxGetExtendedErrorInfo(errBuff, 2048); QMessageBox::information(this, "ERROR", QString("DAQmx Error: %1").arg(errBuff)); on_btnStop_clicked(); } else { deltaT = (double)(ui.txtSamples->value()) / (double)(ui.txtRate->value()); InitChartEx(); totalRead = 0; currentT = 0; isRecording = false; isHold = false; isRunning = true; receivedData = new float64[bSize]; ui.btnStart->setEnabled(false); ui.gpbParam->setEnabled(false); ui.btnHoldContinue->setEnabled(true); ui.btnStop->setEnabled(true); ui.btnSave->setEnabled(true); } }
3.獲取訊號過程,此過程最核心
int32 CVICALLBACK NIDAQTest::EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void * callbackData) { if (s_this->isHold || !(s_this->isRunning)) return 1; int32 error = 0; char errBuff[2048] = { '\0' }; int32 read = 0; int perFrame = 0; int frameCount = 0; int bufferSize = nSamples * MAXCHANN_COUNT;// buffer size = channel count * samples per channel //float64 *data = new float64[bufferSize]; while (true) { if (s_this->isHold || !(s_this->isRunning)) break; error = DAQmxReadAnalogF64(taskHandle, nSamples, 10.0, DAQmx_Val_GroupByChannel, s_this->receivedData, bufferSize, &read, NULL);//DAQmx_Val_GroupByScanNumber if (error < 0) break; perFrame += read; s_this->totalRead += read; if (perFrame == bufferSize) { frameCount++; perFrame = 0; //s_this->UpdateDisplayStyle(); QFuture<void> future = QtConcurrent::run([=] { s_this->UpdateDisplayStyle(); });//display while (!future.isFinished()) { QApplication::processEvents(QEventLoop::AllEvents, 100); } //recording data s_this->RecordToText(); //QFuture<void> recTh = QtConcurrent::run([=] { s_this->RecordToText(); });//recording data //if (recTh.isFinished()) //{ //} } bool res = QMetaObject::invokeMethod(s_this, [=] { s_this->ui.lblRunInfo1->setText(QString("Need gain %1, Acquired frames count %2, Total size %3").arg(bufferSize).arg(frameCount).arg(s_this->totalRead)); }, Qt::AutoConnection); } if (error < 0) { DAQmxGetExtendedErrorInfo(errBuff, 2048); QMetaObject::invokeMethod(s_this, [=] { QMessageBox::information(s_this, "ERROR", QString("DAQmx Error: %1").arg(errBuff)); s_this->on_btnStop_clicked(); }, Qt::QueuedConnection); return 0; } return 1; }
在實現過程中有些坑,比較QT自帶Chart重新整理問題,比如設定NIdata buffer的問題等,後續會貼出C#的。
實現過程中參考了https://wiki.freepascal.org/NI-DAQmx_and_NI-DAQmx_Base_examples
如需要原碼可聯絡