Notes from Chapter 10 ("Easy I/O for DAQ Library") from the
LabWindows/CVI Standard Libraries book.
These notes are an attempt to figure
out how to aquire data from more than one channel on
the NIDAQ board at one time.
Here are the necessary functions described below:
- AIStartAcquisition -- used to
initialize the continuous sampling of data from NIDAQ channels.
- AICheckAcquisition -- check
to see how many samples are ready to be transfered to the program
from the NIDAQ card.
- AIReadAcquisition -- read a
specified number of samples from NIDAQ card.
- AIClearAcquisition -- end a
continuous sampling session started by AIStartAcquisition.
- Miscellaneous functions that might be useful
for Analog input.
Note: in the declarations below ulong stands for
unsigned long, ushort stands for
unsigned short, etc.
NIDAQ Board interested in is: AT-MIO-16-E. Also interested in
continuous samples at a steady sampling rate controlled by the
hardware.
Here is a disclaimer at the start of the chapter:
Note: It is recommended that you do not mix calls to the Data
Acquisition Library with similar types of calls to the Easy I/O for DAQ
Library in the same application. For example, do not mix analog input
calls to the Data Acquisition Library with analog input calls to the
Easy I/O for DAQ Library in the same program.
The sample programs for the Easy I/O are located in the
cvi/samples/easyio directory. These sample programs are
discussed in the EASYIO section of cvi/samples.doc
Note that Easy I/O for DAQ Library cannot currently
work with multirate scanning. (page 10-2).
Definitions
- scan
- A scan is a set of samples for a given time; one
sample from each channel.
- fill mode
- There are two ways that the scans can be placed in the
aquired data output: either by interleaving the samples
from each channel as they arrive (fillMode =
GROUP_BY_SCAN), or by listing all samples from
a particular channel together (fillMode =
GROUP_BY_CHANNEL). The figure below shows how
the two types of groupings work. Suppose that you have
four scans (1, 2, 3, 4) from three different channels
(a, b, c, d). Then the two type of fillModes for data
transfered with the
AIReadAcquisition function
are:
- channel string
- A channel string is a character string which lists
the channels to sample data from. The channels are
either separated by a comma(,) or a colon (:). A
comma is used to specify separate channels, e.g.:
"0,1,2,3" while a colon is used to specify
a range of channels to sample, e.g.:
"0:3". Colons and commas can be mixed in
one string. It is unknown right now whether you
can mix the order if the channels.
You can specify the voltage range for particular
channels via this example string: First suppose that
the AIStartAcqusition function set the initial voltage
range from 0 to 5 volts., then
"0,1; cmd hi 10.0 low -10.0; 2,3"
channel voltage ranges are:
0: 0 to 5
1: 0 to 5
2: -10 to 10
3: -10 to 10
AIStartAcquisition
- Declaration:
-
short AIStartAcquisition(short
device,
char* channelString,
int bufferSize,
double scansPerSecond,
double highLimitVolts,
double lowLimitVolts,
double *actualScanRate,
ulong *taskID);
|
- Purpose:
- Starts continuous sampling of the specified channels.
Sampled data is stored in an internal circular buffer.
This function will return a number
(stored in taskID) which is used later to access
the correct internal buffer according to the following
three functions.
- Use AICheckAcquisition to determine
how many samples can be read before calling AIReadAcquisition.
- Use AIReadAcquisition to retrieve
scans from the internal buffer.
- The function
AIClearAcquisition is used
to stop the continuous sample which was started by this
function.
- Return values:
-
Function call returns an error code (meaning found in Table 10-5
of LabWindows/CVI Standard Librarys book).taskID will
contain the descriptor of the particular acquisition set which is used
with other function calls to tell the internal configuration what
buffers to access/use. actualScanRate will return
the true sampling rate, since your particular NIDAQ board may not
be capable of sampling at the rate that you requested with the
input parameter scansPerSecond.
- Parameter Descriptions:
-
device
| the device number assigned by the configuration utility
(which is a separate program run beforehand).
|
channelString
| a string listing the input channels that are to be sampled.
For examle, if you want to sample channels 0, 1 and 2, then
the string would be: "0,1,2" or "0:2"
bufferSize
| The maximum number of scans which can be stored in
the internal circular buffer. A scan is a set of samples,
one from each channel being sampled.
| scansPerSecond
| The desired sampling rate for the channels. All channels
will be sampled at this rate. The actual sampling rate
will be returned by actualScanRate and
depends on what sampling rates are possible on the
NIDAQ card.
| highLimitVolts
| maximum voltage to be measured, Is this software value, or
the hardware value?
| highLimitVolts
| minimum voltage to be measured, Is this software value, or
the hardware value?
| actualScanRate
| This value will return the true sampling rate which the
board is aquiring the samples at.
| taskID
| This is the descriptor number returned by the function
AIStartAcquisition
| |
AICheckAcquisition
- Declaration:
-
short AICheckAcquisition(ulong taskID,
ulong *scanBacklog);
|
- Purpose:
- This function is used to see if there are any samples from the
NIDAQ board which are ready to be read into the program. The NIDAQ
samples are stored in a circular buffer and this function will return
(via scanBacklog) the number of scans (sample sets)
which are currently in the buffer.
- Return values:
- Function call returns an error code (meaning found in Table 10-5
of LabWindows/CVI Standard Librarys book).
scanBacklog will contain the number of scans
(samples or sets of samples if sampling more than one channel) which
are currently waiting to be transfered to your program
from the input circular buffer.
- Parameter Descriptions:
-
taskID
| This is the descriptor number returned by the function
AIStartAcquisition
|
scanBacklog
| will return the number of scans (sets of samples) waiting
in the input circular buffer. With the
AIReadAcquisition function, you
can now read up to this many scans.
|
AIReadAcquisition
- Declaration:
-
short AIReadAcquisition(ulong
taskID
long scanstoRead.
ushort readMode,
ulong *scanBacklog,
short fillMode,
double *waveforms);
|
- Purpose:
- Transfers sample data from the NIDAQ cards internal buffers to
the program that needs the samples. If you try to read more
scans (sets of samples) that exists in the internal circular
buffer, this function will wait until the number of samples
you request are available.
- Return values:
- Function call returns an error code (meaning found in Table 10-5
of LabWindows/CVI Standard Librarys book).
-
scanBacklog will return the number of scans (sets of samples)
which are still remaining in the internal circular buffer. These scans
can be read by this function at a later time.
-
waveforms will return an array of the voltage samples
aquired from the internal circular buffer. The channel samples will
be interleaved or grouped separately according to the fillMode.
- Parameter Descriptions:
-
taskID
| This is the descriptor number returned by the function
AIStartAcquisition
|
scanstoRead
| The number of scans (sets of samples) which are read
from the internal circular buffer.
|
readMode
| Can be either CONSECUTIVE_MODE which will
read from the oldest side of the buffer, or by
LATEST_MODE which will read from the
most recent side of the buffer (and which may drop
out some sample data).
|
fillMode
| Method to fill the waveforms array.
Either by GROUP_BY_CHANNEL which will arrange
samples into units by channel, or by GROUP_BY_SCAN
which will arrange samles by scan. (see definition of
fill modes for more information).
|
scanBacklog
| returns the current number of scans (sets of samples) which
are still in the input circular buffer which will be ready
to be read by a later call to AIReadAcquisition.
|
waveforms
| returns the data for the scans of each channel.
data is organized according to fillMode parameter
|
AIClearAcquisition
- Declaration:
-
short AIClearAcquisition(ulong taskID);
|
- Purpose:
- This function should more correctly be called AIStopAcquisition.
This function will stop the continuous aquisition of samples from the
channel string setup by AiStartAcquisition.
The task descriptor, taskID will not be valid after the
call to this function.
- Return values:
- Function call returns an error code (meaning found in Table 10-5
of LabWindows/CVI Standard Librarys book).
- Parameter Descriptions:
-
Miscellaneous functions:
- GetDAQErrorString -- returns a string containing the description
of the numeric error code returned by most of the functions
described above (page 10-43)
- GetNumChannels -- who knows why you need this function.
will return the number of channels that a channel string
specified.
- GetChannelIndices -- gets the channel list after removing
some with a "substring".
- GetChannelNameFromIndex -- returns the ascii name of
a channel. Suppose that the channels are "4,3,2,5" then
index 0 is channel "4", and so on.
- GetAILimitsOfChannel -- returns the high and low limits for
sampling regiou of a particular channel in the channel string.
- GroupByChannel -- changes an array filled by "group by scan"
fill mode into "group by channels" filled.
- SetEasyIOMultitaskingMode -- page 10-53. You should set the
multitasking mode to MULTITASK_AWARE if your program calls
the non-timed Easy I/O for DAQ functions and you expect another
data acquisition program to be accessing the same board while your
program is running. In this mode, the Easy I/O for DAQ functions
always recofigure the hardware on each invocation, which means that
they will not be adversely affected by other applications, but they
will not be optimized for speed. MULTITASK_UNAWARE is the
other type of mode.
Declarations for above functions:
char* errorString = GetDAQErrorString(short errorNumber);
short error = GetNumChannels(short device, char channelString[],
short channelType,
unsigned long *numberOfChannels);
short error = GetChannelIndices(short device, char channelString[],
char channelSubString[], short channelType,
long channelIndices[]);
short error = GetChannelNameFromIndex(short device, char channelString[],
long index, short channelType,
char channelName[]);
short error = GetAILimitsOfChannel(short device, char channelString[],
char singleChannel[]
double initialHighLimitVolts,
double initialLowLimitVolts,
double *highLimitVolts,
double *lowLimitVolts);
short error = GroupByChannel(float array[], long numberOfScans,
unsigned long numberOfChannels);
void SetEasyIOMultitaskingMode(int multitaskingMode);