Using NI-DAQmx in Text Based Programming Environments


In general, data acquisition programming with DAQmx involves the following steps:

  • Create a Task and Virtual Channels
  • Configure the Timing Parameters
  • Start the Task
  • Perform a Read operation from the DAQ
  • Perform a Write operation to the DAQ
  • Stop and Clear the Task.

Data acquisition in text based-programming environment is very similar to the LabVIEW NI-DAQmx programming as the functions calls are the same as the NI-DAQmx VI's.


DAQmx Application Programming Interface (API)

DAQmx comes with APIs required for data acquisition programming. The DAQmx API is simply a set of libraries containing functions on how to perform all data acquisition operations. These APIs include support for LabWindows/CVI, C, C++, Visual Basic 6.0, VB.NET and C#.

The DAQmx APIs are installed along with the DAQmx driver and contain the following reference manuals:

  • NI-DAQmx C Reference Help
  • NI-DAQmx C API Visual Basic 6.0 Help
  • NI-DAQmx .NET Framework 1.1 Help (Visual Studio 2003)
  • NI-DAQmx .NET Framework 2.0 Help (Visual Studio 2005)
  • NI-DAQmx .NET Framework 3.5 Help (Visual Studio 2008)
  • NI-DAQmx .NET Framework 4.0 Help (Visual Studio 2010)

Each of these APIs contains detailed information on how to use the library of functions and classes to communicate with and control an NI data acquisition (DAQ) device.

DAQmx Common Functions

Create a Task and Virtual Channels

virtual channel is a collection of settings such as a name, a physical channel, input terminal connections, the type of measurement or generation, and can include scaling information.

task, an important concept for NI-DAQmx, is a collection of one or more virtual channels with timing, triggering, and other properties. Conceptually, a task represents a measurement or generation you want to perform. Tasks can be created for analog in and output, digital input and output and counter operations.

To create a task and an analog input channel in C, use the following function calls:

DAQmxCreateTask("", &taskHandle));

DAQmxCreateAIVoltageChan (taskHandle, "Dev1/ai0", "Voltage", DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL);

To create a task and an analog input channel in .NET, instantiate the Task object and create a Channel as shown below:

analogInTask = new Task();
AIChannel myChannel;
myChannel = analogInTask.AIChannels.CreateVoltageChannel(
    "dev1/ai0", //The physical name of the channel
    "myChannel", //The name to associate with this channel
    AITerminalConfiguration.Differential, //Differential wiring
    -10, //10v minimum
    10, //10v maximum
    AIVoltageUnits.Volts //Use volts

Configure the Timing Parameters

Most NI data acquisition devices use a sample clock to control the rate at which samples are acquired and generated. This sample clock sets the time interval between samples. Each tick of this clock initiates the acquisition or generation of one sample per channel.

In software, you can specify the interval (how fast the clock acquires or generates signals) by specifying the sample rate. You can also limit the sample rate by the signal conditioning you apply to the signals or the number of channels in your application.

To configure the timing parameters in C, call the DAQmxCfgSamp function as shown below:

DAQmxCfgSampClkTiming(taskHandle, "", 10000.0, DAQmx_Val_Rising,

DAQmx_Val_FiniteSamps, 1000);

To configure the timing parameters in .NET, use the Task.Timing property as shown below:


"/Dev1/PFI0", // external clock source line or use "" for internal clock

10000, // expected rate of external clock or actual rate of internal clock

SampleClockActiveEdge.Rising, // acquire on rising or falling edge of ticks

SampleQuantityMode.ContinuousSamples, // continuous or finite samples

1000 // number of finite samples to acquire or used for buffer size if continuous


When a device controlled by NI-DAQmx does something, it performs an action. Two very common actions are producing a sample and starting a waveform acquisition. Every NI-DAQmx action needs a stimulus or cause. When the stimulus occurs, the action is performed. Causes for actions are called triggers. Triggers are named after the actions they cause, such as a start trigger to start an acquisition.

The NI-DAQmx Trigger function configures a trigger to perform a specific action. The most commonly used actions are a start trigger and a reference trigger. A start trigger initiates an acquisition or generation. A reference trigger establishes the location, in a set of acquired samples, where pretrigger data ends and posttrigger data begins. Both of these triggers can be configured to occur on a digital edge, an analog edge, or when an analog signal enters or leaves a window.

To configure a start trigger on a rising digital signal coming in on PFI line 0 of the device, use the DAQmxCfgDigEdgeStartTrig function in C:

DAQmxCfgDigEdgeStartTrig (taskHandle, "PFI0", DAQmx_Val_Rising);

To configure a start trigger in .NET, use ConfigureDigitalEdgeTrigger in the Task.Triggers.StartTrigger collection as shown below:

DigitalEdgeStartTriggerEdge triggerEdge = DigitalEdgeStartTriggerEdge.Rising;

analogInTask.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("PFI0, triggerEdge);

Start the Task

The NI-DAQmx Start Task function explicitly transitions a task to the running state. In the running state, the task performs the specified acquisition or generation. A task will implicitly transition to the running state, or automatically start, if the NI-DAQmx Start Task function is not used when the NI-DAQmx Read function executes. This implicit transition also occurs if the NI-DAQmx Start Task function is not used and the NI-DAQmx Write function executes with its auto start input specified accordingly.

To start a task in C, use the DAQmxStartTask function:


To start a task in .NET, use the Task.Start function:


Read or Write Operation

NI-DAQmx provides multiple functions for reading and writing data. In many cases, you can use multiple options. The read and write functions have two major selection criteria: data format and data organization. Data format specifies the type of the data that is returned. Counter reads, for example, can return integers or floating-point formats. The second category, data organization, deals with the structure the data is returned in. Analog reads, for example, have a variety of array and scalar organizations.

Depending on the data operation, data may be acquired or generated. In acquisition mode, a read operation is required to read a specified number of samples from the buffer. In data generation mode, sample are been written out to the data acquisition board buffer.

To read data in C, use the DAQmxReadAnalog function call:

DAQmxReadAnalogF64(taskHandle, 1000, 10.0, DAQmx_Val_GroupByChannel, data, 1000, &read, NULL)'

To read data in .NET, create a ChannelReader object, bind it to Task.Stream and then call a read function as shown below:

//Create the reader and attach it to the stream
AnalogSingleChannelReader reader = new AnalogSingleChannelReader(analogInTask.Stream);
//Perform the read
double[] data = reader.ReadMultiSample(100);

For more information on reading and writing data in .NET, see the "Reading and Writing with the NI-DAQmx .NET Library" section of the NI-DAQmx .NET 2.0 Framework Help.

Stop and Clear Task

After completing a task, stop the task and de-allocate all reserved resources. The NI-DAQmx Clear Task function clears the specified task. If the task is currently running, the function first stops the task and then releases all of its resources. Once a task has been cleared, it cannot be used unless it is recreated. Thus, if a task will be used again, the NI-DAQmx Stop Task function should be used to stop the task, but not clear it.

To stop and clear a task in C use the following functions:



To stop and clear a task in .NET use the Task.Stop and Task.Dispose methods as shown below:




For a clear example of how this works, please see the Example Code locations, further down in this document.

DAQmx Programming in C

Here is an example of an analog input voltage operation to acquire a finite number of voltage samples from a transducer using an NI data acquisition board.


#include <stdio.h>
#include <NIDAQmx.h>
#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else

int main(void)
       int32       error=0;
       TaskHandle  taskHandle=0;
       int32       read;
       float64     data[1000];
       char        errBuff[2048]={'\0'};

// DAQmx analog voltage channel and timing parameters

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

DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "Dev1/ai0", "", DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL));

DAQmxErrChk(DAQmxCfgSampClkTiming(taskHandle, "", 10000.0, DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, 1000));

// DAQmx Start Code


// DAQmx Read Code

DAQmxErrChk(DAQmxReadAnalogF64(taskHandle, 1000, 10.0, DAQmx_Val_GroupByChannel, data, 1000, &read, NULL));

// Stop and clear task

       if( DAQmxFailed(error) )
       if( taskHandle!=0 )  {
       if( DAQmxFailed(error) )
              printf("DAQmx Error: %s\n",errBuff);
              return 0;


Note: It is important to include the NIDAQmx.h header file in the main.c program in order to have access to the DAQmx library. 

In this sample code, this function created a task:

int32 DAQmxCreateTask (const char taskName[], TaskHandle *taskHandle);

This assigned a name to the task with an output referencing the task created. This function then configured a virtual voltage channel:

int32 DAQmxCreateAIVoltageChan (TaskHandle taskHandle, const char physicalChannel[], const char nameToAssignToChannel[], int32 terminalConfig, float64 minVal, float64 maxVal, int32 units, const char customScaleName[]);

This function call specifies a reference to the task created, the physical channel names, the name to assign to the virtual channels, the input terminal configuration for the channel, the minimum and maximum value in unit that you expect to measure and the name of a custom scale to apply to the channel.

After configuring the virtual voltage channels, a sample clock setting function specified the sampling rate, sample mode, and number of samples to read:

int32 DAQmxCfgSampClkTiming (TaskHandle taskHandle, const char source[], float64 rate, int32 activeEdge, int32 sampleMode, uInt64 sampsPerChanToAcquire);

The sample mode can also be set to continuous using the DAQmx_Val_ContSamps constant. To actually start acquiring the voltage sample, the following function must be called with a reference to the task configured.

int32 DAQmxStartTask (TaskHandle taskHandle);

The DAQmxReadAnalogF64 reads multiple floating-point samples from a task that contains one or more analog input channels as shown in the function call.

int32 DAQmxReadAnalogF64 (TaskHandle taskHandle, int32 numSampsPerChan, float64 timeout, bool32 fillMode, float64 readArray[], uInt32 arraySizeInSamps, int32 *sampsPerChanRead, bool32 *reserved);

Here 1000 samples are read and written to an array of the same size as the number of samples acquired.

Finally the DAQmxStopTask and DAQmxClearTask, stops the task and returns it to the state it was in before you called DAQmxStartTask and releases any resources reserved by the task. You cannot use a task once you clear the task without recreating or reloading the task.

DAQmx Programming in .NET

A similar pseudocode for the same operation can be written using the API for Microsoft .NET Framework DAQmx library for both Visual Basic and C#. The API contains classes, delegates, and enumerations that provide a .NET interface to NI-DAQmx. Example code for a very simple read operation is shown below:


// Create a channel
   myTask.AIChannels.CreateVoltageChannel(physicalChannelComboBox.Text, "", (AITerminalConfiguration)(-1), rangeMinimum, rangeMaximum,    AIVoltageUnits.Volts);

// Configure timing specs
   myTask.Timing.ConfigureSampleClock("", sampleRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples, samplesPerChannel);

// Verify the task

// Prepare the table for data
   InitializeDataTable(myTask.AIChannels, ref dataTable);
   acquisitionDataGrid.DataSource = dataTable;

// Read the data
   reader = new AnalogMultiChannelReader(myTask.Stream);

// clear task


Note: That the NationalInstruments.DAQmx class library must be included to successfully run the program.


Example Code

NI-DAQmx also comes with set of examples for each of the programming environment.  You can find examples using the C API in one of the following directory locations:
<Program Files>\National Instruments\NI-DAQ\Examples\DAQmx ANSI C
<Documents and Settings>\All Users\Documents\National Instruments\NI-DAQ\Examples\DAQmx ANSI C

For the .NET API, you can find examples in one of the following directory locations:
C:\Program Files\National Instruments\MeasurementStudioVS2005\DotNET\Examples\DAQmx
<Documents and Settings>\All Users\Documents\National Instruments\NI-DAQ\Examples\DotNET2.0

Folders named VB contain Visual Basic .NET examples, and folders named CS contain C# examples.

Visual Basic 6.0 examples can be found in one of the following directory locations:
<Program Files>\National Instruments\NI-DAQ\Examples\Visual Basic 6.0
<Documents and Settings>\All Users\Documents\National Instruments\NI-DAQ\Examples\Visual Basic 6.0

NI-DAQmx Help and API Documentation

After installing the NI-DAQmx driver and choosing support for C and/or .NET, shortcuts to the help will be located in the Start menu under Programs » National Instruments » NI-DAQ » Text-Based Code Support

Additional documentation covering NI-DAQmx concepts in-depth is found in the NI-DAQmx Help located under Programs » National Instruments » NI-DAQ

Was this information helpful?