Using NI-DAQmx in Text Based Programming Environments
Table of Contents
The National Instruments Getting Started with NI-DAQmx Series is aimed at helping you learn NI-DAQmx programming fundamentals. Through video and text tutorials, this series will take you from verifying your device's operation in Measurement & Automation Explorer (MAX) to programming data acquisition applications using LabVIEW. It is intended for both the beginner who wants to learn how to use the DAQ Assistant, as well as the experienced user who wishes to take advantage of advanced NI-DAQmx functionality.
Overview
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-programmming environment is very similar to the LabVIEW NI-DAQmx programming as the functions calls is the same as the NI-DAQmx VI’s.
Create a Task and Virtual Channels
A 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.
A 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:
|
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(); |
Configure the Timing Parameters
Most National Instruments 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.
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 start trigger to start an acquisition. In addition to specifying the action you want a trigger to cause, you must select the type of trigger to use, which determines how the trigger is produced.
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:
analogInTask.Timing.ConfigureSampleClock(
|
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 confure 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 be implicitly transitioned to the running state, or automatically started, 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:
| DAQmxStartTask(taskHandle); |
To start a task in .NET, use the Task.Start function:
| analogInTask.start(); |
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 deals with the type of the data that is returned. For example, counter reads can return integers or floating-point formats. The second category, data organization, deals with the structure the data is returned in. For example, analog reads have a variety of array and scalar organizations.
Depending on the data acuisition operation, data may be acquired or generated. In acquisition mode, a read operation is required to read all specified number of samples from the buffer while in data generation mode, sample are been written out onto the data acquisition board in form of output operation.
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
It is necessary to stop all tasks that are running after completion and deallocate all reserved resources. The NI-DAQmx Clear Task function clears the specified task. If the task is currently running, the function first stops thetask 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:
| DAQmxStopTask(taskHandle); DAQmxClearTask(taskHandle); |
To stop and clear a task in .NET use the Task.Stop and Task.Dispose methods as shown below:
| analogInTask.Stop(); analogInTask.Dispose(); |
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 the data acquisition operations such as analog input, analog output, Counter and Digital Input/Output. 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 contains 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)
Each of these APIs contains detailed information on how to use all the library of functions and classes to communicate with and control a NI data acquisition (DAQ) device
DAQmx programming in C
Assumming we are interested in performing an analog input voltage operation to acquire a finite number of voltage sample from a transducer using one of the data acqusition boards, then a typical code in ANSI C programmig environment will look like
| ******************************************************************************** #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
// DAQmx Start Code
// DAQmx Read Code
// Stop and clear task Error: if( DAQmxFailed(error) ) DAQmxGetExtendedErrorInfo(errBuff,2048); if( taskHandle!=0 ) { DAQmxStopTask(taskHandle); DAQmxClearTask(taskHandle); } if( DAQmxFailed(error) ) printf("DAQmx Error: %s\n",errBuff); return 0; } ******************************************************************************** |
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, a task was created using the function;
int32 DAQmxCreateTask (const char taskName[], TaskHandle *taskHandle);
This assigns a name to the task with an output referencing the task created. A virtual voltage channel was then configured with the function;
int32 DAQmxCreateAIVoltageChan (TaskHandle taskHandle, const char physicalChannel[], const char nameToAssignToChannel[], int32 terminalConfig, float64 minVal, float64 maxVal, int32 units, const char customScaleName[]);
This function call specify a reference to the task created, the physical channels name, 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 functions was called to specify the sampling rate and mode and number of samples to read.
int32 DAQmxCfgSampClkTiming (TaskHandle taskHandle, const char source[], float64 rate, int32 activeEdge, int32 sampleMode, uInt64 sampsPerChanToAcquire);
The same 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 myTask.Control(TaskAction.Verify); // Prepare the table for data InitializeDataTable(myTask.AIChannels, ref dataTable); acquisitionDataGrid.DataSource = dataTable; // Read the data reader = new AnalogMultiChannelReader(myTask.Stream); // clear task myTask.Dispose(); ******************************************************************************** |
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:
C:\Program Files\National Instruments\NI-DAQ\Examples\DAQmx ANSI C or
C:\Documents and Settings\All Users\Documents\National Instruments\NI-DAQ\Examples\DAQmx ANSI C
Also for .NET API, you can find examples in one of the following directory locations:
C:\Program Files\National Instruments\MeasurementStudioVS2005\DotNET\Examples\DAQmx or C:\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:
C:\Program Files\National Instruments\NI-DAQ\Examples\Visual Basic 6.0 or
C:\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 verifing support for C and/or .NET was checked during the installation process, shortcuts to the help will be located in the Start menu under Programs » National Instruments » NI-DAQ » NI-DAQmx C Reference Help and/or NI-DAQmx .NET 2.0 Framework Help.
Additional documentation convering NI-DAQmx concepts in-depth is found in the NI-DAQmx Help located in the same Start menu folder as the API documentation mentioned above.
Reader Comments | Submit a comment »
Will this work when developing a
application for Windows Mobile 6 in .NET
(Creating a smartdevice project)? or
does it only work on a normal desktop
application?
- Dennis Francek, AD. 05731@iha.dk - Feb 6, 2009
Will this be working when developing a
Windows Mobile 6 application in .NET
(Creating a smartdevice project) or does
this only work creating desktop
applications?
- 05731@iha.dk - Feb 6, 2009
I implemented the following code to handle
the Error Checking:
int DAQmxErrChk (int32 status)
{
char errBuff[2048];
if (status < 0)
{
DAQmxGetExtendedErrorInfo(errBuff,2048);
fprintf(stderr,
"DAQmx Error: %s\n",errBuff);
return 1;
}
else return 0; /* Success or Warning */
}
- fparisi@tiscali.it - Sep 27, 2008
Legal
This tutorial (this "tutorial") was developed by National Instruments ("NI"). Although technical support of this tutorial may be made available by National Instruments, the content in this tutorial may not be completely tested and verified, and NI does not guarantee its quality in any way or that NI will continue to support this content with each new revision of related products and drivers. THIS TUTORIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND AND SUBJECT TO CERTAIN RESTRICTIONS AS MORE SPECIFICALLY SET FORTH IN NI.COM'S TERMS OF USE (http://ni.com/legal/termsofuse/unitedstates/us/).
