LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Using DAQmx to acquire analog data

Having some trouble learning to use DAQmx.  I have a 6229 card in a PXIe chassis to acquire and output analog and digital data.  Using the DAQmx simulator to develop the application.  The issue is I have one subroutine to initialize the task to read the analog channels, and another subroutine to actually get the data.  Problem is that the task handle reports back as invalid, even though I've printed it in both subroutines and it's the same (1841684368, which seems like a suspiciously large number).  I had broken the code into the separate initialization and reading tasks because I thought there would be significant overhead doing initialization, but I really only need to read the data every 10 seconds or so.
 
Here's the code for the task initialization:
int32 CreateDAQTaskAnalogRead(TaskHandle *taskOut1)
{
 int32 DAQmxError = DAQmxSuccess;
 char errBuff[2048]={'\0'};
 TaskHandle taskHandle;

 DAQmxErrChk(DAQmxCreateTask("DAQTaskAnalogRead", &taskHandle));
 DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "DAQBoard/ai0", "Voltage0",
  DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, "")); 
 DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "DAQBoard/ai1", "Voltage1",
  DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, "")); 
 DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "DAQBoard/ai2", "Voltage2",
  DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, "")); 
 DAQmxErrChk(DAQmxCfgSampClkTiming(taskHandle, "",
  1000, DAQmx_Val_Rising,
  DAQmx_Val_FiniteSamps, NUM_SAMPLES)); // NUM_SAMPLES samples at 1kHz rate
    *taskOut1 = taskHandle;
 printf ("taskHandle in CreateDAQTaskAnalogRead %d\r\n", taskHandle);
 
And here's the code for the analog reading routine:
int32 DAQAnalogRead(TaskHandle taskHandle, float64 * AvgAnalog)
{
 float64 AnalogArray[NUM_SAMPLES*NUM_AI_CHANNELS]; // AnalogArray is non-interleaved
 int32 DAQmxError = DAQmxSuccess;
 char errBuff[2048]={'\0'};
 int i,j;  // Counters to acquire analog data
 int32 Samples_Read = 0;
 double Mean_Input_Array [NUM_SAMPLES];
 double Mean_Result;
 
 printf ("taskHandle in DAQAnalogRead %d\r\n", taskHandle);
 printf ( "Hit any key to continue");
 getchar();

 DAQmxErrChk( DAQmxStartTask(taskHandle) );  // Starts the task ****Fails here****
 DAQmxReadAnalogF64 (taskHandle, DAQmx_Val_Auto, 10.0, DAQmx_Val_GroupByChannel,
  AnalogArray, NUM_SAMPLES*NUM_AI_CHANNELS,&Samples_Read, 0); // AnalogArray is non-interleaved
 DAQmxErrChk( DAQmxStopTask(taskHandle) );  // Stops the task
 
 // Average the samples for each channel.  Samples are non-interleaved
 for (i=0;i<NUM_AI_CHANNELS;i++) {
  for (j=0;j<NUM_SAMPLES;j++) {
   Mean_Input_Array [j] = AnalogArray[i*j];
   }
  Mean_Result = 0;
  Mean (Mean_Input_Array, NUM_SAMPLES, &Mean_Result);
  AvgAnalog[i] = Mean_Result;
  }
 
 
Also, is there a good source explaining the concepts behind the DAQmx CVI calls?  Seen that there's LabVIEW-related info on DAQmx, but haven't found much for CVI. 
0 Kudos
Message 1 of 5
(3,742 Views)
Hello Sandia.  It sounds like you have been able to recognize your 6229 and chassis in Measurement and Automation Explorer successfully.  Next, I would focus on making sure that the hardware is functioning properly by running one of our example programs in CVI.  Try this program that sounds fairly close to what you are trying to accomplish.  The PXI-6229 is specifically listed as a module that supports the operation of this CVI code.  The program is one of many programs that can be found in our Developer Zone.  I hope running this program and reviewing the code behind it helps you understand your application better!  If this program raises any further questions or comments, please feel free to post them here.  Have a great day and I look forward to hearing from you. 
 
Brian F
Applications Engineer
National Instruments
 
0 Kudos
Message 2 of 5
(3,726 Views)

In the ContAcq-IntClk.c program, initializing the DAQmx task and acquiring the data are accomplished in the same routine.  What I’d like to do (I think) is initialize the tasks in one call, then periodically acquire data in another subroutine call (StartTask thru StopTask).  On exiting the program, the ClearTask would run.

 

I modified my program to do the initialize, start, acquire, stop, and clear in one routine, and it works.  Is there a large overhead to initializing and clearing the DAQmx task each time I sample data?  It still bothers me that I can’t successfully pass the task handle to each routine in turn, but maybe that’s a problem for another day.

0 Kudos
Message 3 of 5
(3,722 Views)

While we are on the subject, how about clarifying how the channels are arranged when multiple channels are read?  The documentation says non-interleaved, which I've perhaps incorrectly interpreted as Chan1-samp1, Chan1-samp2, Chan1-samp3, ...  But the results seem to indicate differently: Chan1-samp1, Chan2-samp1, Chan3-samp1, ...

My code is listed below to read multiple samples of three channels and average each sample set into one value per channel.  I threw in a plot routine to look at the result.  I'm using the DAQmx simulator, so the data appear as a sine for all channels.  So I can't tell if I have it set up properly.  I get a faster sine wave plotted if I assume the second arrangement from above, which I think means the samples are interleaved.

 DAQmxErrChk(DAQmxCreateTask("DAQTaskAnalogRead", &taskHandle));

 DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "DAQBoard/ai0", "Voltage0",
 DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, "")); 

 DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "DAQBoard/ai1", "Voltage1",
 DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, "")); 

 DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "DAQBoard/ai2", "Voltage2",
 DAQmx_Val_RSE, 0, 5, DAQmx_Val_Volts, "")); 

 DAQmxErrChk(DAQmxCfgSampClkTiming(taskHandle, "",
  1000, DAQmx_Val_Rising, 
 DAQmx_Val_FiniteSamps, NUM_SAMPLES)); // NUM_SAMPLES samples at 1kHz rate

  *taskOut1 = taskHandle;
 
 DAQmxErrChk( DAQmxStartTask(taskHandle) );  // Starts the task
 DAQmxReadAnalogF64 (taskHandle, DAQmx_Val_Auto, 10.0, DAQmx_Val_GroupByChannel,
  AnalogArray, NUM_SAMPLES*NUM_AI_CHANNELS,&Samples_Read, 0); // AnalogArray is non-interleaved?
 DAQmxErrChk( DAQmxStopTask(taskHandle) );  // Stops the task

 // Average the samples for each channel.  Samples are non-interleaved
 for (i=0;i<NUM_AI_CHANNELS;i++) {
  for (j=0;j<NUM_SAMPLES;j++) {
//   Mean_Input_Array [j] = AnalogArray[i*NUM_SAMPLES + j]; // non-interleaved
   Mean_Input_Array [j] = AnalogArray[i + j*NUM_AI_CHANNELS]; // interleaved
   }
  Mean_Result = 0;
  Mean (Mean_Input_Array, NUM_SAMPLES, &Mean_Result);
  AvgAnalog[i] = Mean_Result;
  if (0 == i) { // Plot the result for channel 0 -- Sine?
   PlotStripChart (panelHandle, PANEL_PLOT, Mean_Input_Array, NUM_SAMPLES, 0, 0, VAL_DOUBLE);
   }
  }
 
Error:
 SetWaitCursor(0);
 if( DAQmxFailed(DAQmxError) )  DAQmxGetExtendedErrorInfo(errBuff,2048);
 if( taskHandle!=0 ) {
  /*********************************************/
  // DAQmx Stop Code
  /*********************************************/
  DAQmxStopTask(taskHandle);
  DAQmxClearTask(taskHandle);
 }
 if( DAQmxFailed(DAQmxError) )  MessagePopup("DAQmx Error",errBuff);
 return DAQmxError;
}

0 Kudos
Message 4 of 5
(3,715 Views)

Hello Sandia.  I am glad to hear that your application is functioning correctly!  In respect to your question about the overhead associated with configuring and clearing a task: Unless you are changing some part of the DAQmx task, there is no reason to clear and configure every time you wish to perform a DAQmx read.  All that is required is to configure the task at the beginning of the program and read from the task whenever you desire.  Basically, the configuration just tells the computer how to collect the data when it is told to collect the data.  If you continually want to acquire data in finite mode at a rate of 1 Hz across 3 channels (all constant desires), you don't need to clear and configure more than once in your program. 

As far as your question dealing with interleaved samples, interleaved samples prioritize samples before channels, such that the array lists the first sample from every channel in the task, then the second sample from every channel, up to the last sample from every channel.

Channel 0—Sample 1
Channel 1—Sample 1
Channel 2—Sample 1
Channel 0—Sample 2
Channel 1—Sample 2
Channel 2—Sample 2
...
Channel 0—Sample N
Channel 1—Sample N
Channel 2—Sample N

Non-interleaved samples prioritize channels before samples, such that the array lists all samples from the first channel in the task, then all samples from the second channel, up to all samples from the last channel.

Channel 0—Sample 1
Channel 0—Sample 2
...
Channel 0—Sample N
Channel 1—Sample 1
Channel 1—Sample 2
...
Channel 1—Sample N
Channel 2—Sample 1
Channel 2—Sample 2
...
Channel 2—Sample N
 
I hope this information is helpful!  If this generates any further questions or comments, I would be happy to answer them here.  Have a great day!
 
Brian F
Applications Engineer
National Instruments
0 Kudos
Message 5 of 5
(3,697 Views)