Using DAQ Event Messaging under Windows NT/95/3.1
Overview
The NI-DAQ language interface for PCs is mostly a "polling-oriented" Application Programming Interface, which means after you initiate a data acquisition process, you need to poll the driver to determine the current status.
When NI-DAQ 4.4.1A Windows 3.1 was released, it included a new subsystem called DAQ Event Messaging. With this mechanism, the driver actively notifies the user of a specific DAQ Event by either posting a message on a message queue or calling a callback function. This new feature opened a new world of possibilities for data acquisition programming. To see if an acquisition is done, your program can simply tell you when it is finished. Furthermore, in 32-bit Windows environments, using DAQ Events will improve the performance of your data acquisition application.
This document explains how to use DAQ Events in NI-DAQ, as well as the LabVIEW implementation of DAQ Events -- DAQ occurrences. The Appendix includes three example programs using DAQ Events in NI-DAQ.
Table of Contents
DAQ Event Types
DAQ Events can be configured in NI-DAQ by calling any of the following functions:Low-Level: Config_DAQ_Event_Message
High-Level: Config_ATrig_Event_Message
Config_Alarm_Deadband
Using Config_DAQ_Event_Message, you can configure any one of 10 different general DAQ Events:
DAQ Event type 0 – Acquire or Generate N Scans
DAQ Event type 1 – Every N Scans
DAQ Event type 2 – Completed Operation or Stopped by Error
DAQ Event type 3 – Voltage out of bounds
DAQ Event type 4 – Voltage within bounds
DAQ Event type 5 – Analog Positive Slope Triggering
DAQ Event type 6 – Analog Negative Slope Triggering
DAQ Event type 7 – Digital Pattern Not Matched
DAQ Event type 8 – Digital Pattern Matched
DAQ Event type 9 – Counter Pulse Event
Calling Config_ATrig_Event_Message is equivalent to calling Config_DAQ_Event_Message with either DAQ Event 5 or 6. Calling Config_Alarm_Deadband is equivalent to calling Config_DAQ_Event_Message with DAQ Event 3 and 4, because it will check for both the “within bounds” alarm (DAQ Event 4) and out of bounds alarm (DAQ Event 3).
For further information about each DAQ Event Type, refer to the NI-DAQ Function Reference Manual.
- NOTE: Not all DAQ Events can be used on all PC-based DAQ devices. For instance, DAQ Events 7 and 8 require an 8255-based DIO port. Also, the only DAQ device that works with all 10 DAQ Events is the AT-MIO-16D. The description forConfig_DAQ_Event_Message in the NI-DAQ Function Reference Manual has a table that identifies which DAQ Events work with which DAQ devices.
In LabVIEW, DAQ Events are presented as DAQ Occurrences, and fit into the general Occurrences scheme. Also, the DAQ Event codes map a bit differently, which is discussed in a later section.
See Also:
About the NI-DAQ Function Reference
NI-DAQ Function Reference Manual for PC Compatibles
Configuring DAQ Event Messaging in NI-DAQ
Three example programs using DAQ Events in NI-DAQ are included in the Appendix. In NI-DAQ, the DAQ Event messaging configuration is done in the following steps:
Step 1 – Configure the DAQ Event Parameters
In languages other than Visual Basic, you can call the Config_DAQ_Event_Message function. Its function prototype looks like this:
status = Config_DAQ_Event_Message (deviceNumber, mode, chanStr, DAQEvent, DAQTrigVal0, DAQTrigVal1, trigSkipCount, preTrigScans, postTrigScans, handle, message,callbackAddr)
You do not have to set all parameters to meaningful values for every single DAQ Event Type. Refer to the NI-DAQ Function Reference Manual for further details (Usable Parameter List.)
If you are using Visual Basic, place the General DAQ Event Custom Control on your Visual Basic form and set the properties using the property page. Refer to Chapter 3, Software Overview, in the NI-DAQ User Manual for further details.
Step 2 – Set Up a Way to Handle the DAQ Event Messages
The action of "handling a message" refers to the definition of what you want your program to do when the event happens. You can use one of these methods to handle the DAQ Event Messages:
a. Set up a callback function
b. Set up a message handler and use a message loop to check for posted messages
c. Set up a Visual Basic event handler (only if using the General DAQ Event Custom Control in Visual Basic).
You can set up a callback function for all Windows platforms if you are using NI-DAQ 5.0 or later. If you are using NI-DAQ 4.9.0 or before, callbacks can be configured in only Windows 3.1 and LabWindows/CVI.
This topic is discussed in detail in the next section.
Step 3 – Start an Asynchronous DAQ Operation
Configuring a DAQ Event actually places a hook in the NI-DAQ interrupt service routine for your DAQ device. This means the criteria for the configured DAQ Events are actually checked at interrupt time and the driver decides whether to "post a message." For this to work, you must have an asynchronous DAQ operation going on in the background.
Also, some DAQ Events (DAQ Events 3 through 8, and 9, if using counter events on the waveform generation counter with a non-E Series MIO device) require you to explicitly change the data transfer mode from DMA to interrupts, by using the Set_DAQ_Device_Info function. For instance, to change the Analog Input data transfer mode to use interrupts, you can call Set_DAQ_Device_Info as such:
status = Set_DAQ_Device_Info(device, ND_DATA_XFER_MODE_AI, ND_INTERRUPTS);
Some functions that initiate asynchronous DAQ operations are:
Analog Input: DAQ_Start, SCAN_Start, Lab_ISCAN_Start
Analog Output: WFM_Group_Control
Digital I/O: DIG_Block_In, DIG_Block_Out
Counter/Timer: CTR_Square, CTR_Pulse (these are not necessary for DAQ Event 9 if you are generating pulses externally.)
While the asynchronous DAQ operation is in progress, you should get your event messages whenever the event conditions are met.
If you are going to have NI-DAQ jump to the callback function, make sure to keep the program running! If the program terminates, all the DAQ Events you have configured will be deleted as the NI-DAQ driver unloads. An easy thing to do is to wait for a keyboard key to be hit.
Step 4 – Clearing DAQ Events
After you are finished with the messaging, make sure to call the Config_DAQ_Event_Message function to clear the DAQ event messaging.
See Also:
NI-DAQ User Manual for PC Compatibles
The Callback Mechanism versus Polling for DAQ Events
As mentioned previously, there are three ways to receive these messages:
a. Callback Mechanism – You define a callback function; and when the event happens, the program will automatically jump to that callback function.
b. Message Handler – You define messages to be posted to the message queue when the event happens. Your program will have to get messages actively using the Windows API function Get_Message in a loop. Based on the message received in Get_Message, you can take appropriate action.
c. Visual Basic Custom Control – You define the GeneralDAQEventn_Fire routine; and when the event happens, the program will automatically jump to that routine.
Notes on Using Callback Functions
There are certain development environments in which you can use either event notification mechanism. They are:
- Any C/C++ compiler (Visual C++, Borland C++, LabWindows/CVI)
- Any other programming language that uses function pointers
If you are programming a Windows 3.1 executable with a C/C++ development environment other than LabWindows/CVI, your callback function must have a unique prototype. You must place it in a dynamic link library (DLL) and follow the Windows programming conventions on DLLs. (For more details, refer to the Config_DAQ_Event_Message function descriptions in the NI-DAQ Function Reference Manual.)
If you are programming in LabWindows/CVI or a 32-bit Windows application with a C/C++ programming environment, you can simply define a callback function anywhere in the program.
Notes on Windows Messages
If you are writing a Windows GUI application in C/C++ (not including LabWindows/CVI), you should have a message handler function, such as WindowProc, and a corresponding window handle, such as hWnd. The message handler function, identified with hWnd and WindowProc, can have a switch statement, in which you can check for the event message you specified in Config_DAQ_Event_Message. (In this case, set the callbackAddr parameter in Config_DAQ_Event_Message to zero.) For example:
LRESULT CALLBACK WindowProc
(HWND hWnd, UINT uMsgId, WPARAM wParam, LPARAM lParam)
{
switch (uMsgId)
{
case WM_PAINT:
// repaint the window" (code omitted)
return 0;
break;
case WM_NIDAQ_MSG: // user defined
// upperbyte of wParam is ‘doneFlag’
// lowerbyte of wParam is device number
// lParam indicates the scan # at which the event occurred
// handle the message here" (code omitted)
return 0;
break;
default:
// handle other usual messages...
return DefWindowProc(hWnd, uMsgId, wParam, lParam);
}
}
From the Config_DAQ_Event_Message function, you can specify that a specific Windows message code be sent at event time, or you can specify your own message code.
In using callbacks or message loops, the event handler will give you the following data through its parameters.
Device number: upper byte of wParam
"done" flag: lower byte of wParam
Scan number: lParam (all 32-bits)
Notes on Visual Basic Custom Controls
If you are programming with Visual Basic for Windows, there are three custom controls that make the event handling mechanism easy. For further information on how to incorporate them into your programs, refer to Chapter 3, Software Overview, in the NI-DAQ User Manual.
Comparing DAQ Event Handling Methods
Here is a cross-reference chart comparing the different DAQ event programming methods and the programming steps for DAQ Events.
Windows Callbacks or LabWindows/CVI | Windows Messages | Visual Basic Custom Control | |
| Step 1. Configure DAQ Event Parameters | Call Config_DAQ_Event_Message to set up DAQ Events | Call Config_DAQ_Event_Message to set up DAQ Events | Place custom control on form and set properties. |
| Step 2. Setup a way to handle the DAQ events | Create a callback function and fill in the code to specify action upon DAQ event. | Specify the message handler address in the wndClass. In the message handler, switch on msg. | Fill in code for the GeneralDAQEvent_Fire routine to specify action upon DAQ event. |
| Step 3. Start asynch. Operation | Start any asynchronous DAQ operation. | Start any asynchronous DAQoperation. | Set the.Enabled property to True and start any asynch DAQ operation. |
| Step 4. Clear DAQ events | Clear asynchronous DAQ operation; then call Config_DAQ_Event_Message to clear DAQ Events. | Clear asynchronous DAQoperation; then call Config_DAQ_Event_Message to clear DAQ Events. | Clear the asynch DAQ operation and set the.Enabled property to False. |
Windows Callbacks | LabWindows/CVI | Windows Messages | Custom Control | |
| Performance | Fastest Win3.1 – the callback is invoked at interrupt time 32-bit Win –thread-based; thread is woken up at interrupt time | Moderate Message-based; response is dependent on the number of messages already in the queue. | Moderate Same as LabWindows/CVI. | Moderate Same as LabWindows/CVI, but also affected by the Visual Basic run-time engine (up to VB 4.0). |
| Ease of Implementation | Easy Just another function in your code. If your CVI program already handles CVI user interface events, then your DAQ callback function fits into the same scheme. | Easy Just another function in your program. | Moderate to Difficult Need a Windows message handler (easy, if your program already has one). | Easiest Visual Basic pops up the code window for you when you double-click on the custom control. Also, all the properties are displayed on the Properties page. |
Configuring Multiple DAQ Events
You can configure your program to handle multiple DAQ Events. Here are some specific issues depending on programming environments for configuring N DAQ Events.
- C/C++ or LabWindows/CVI
Call Config_DAQ_Event_Message N times.
- If you write N callbacks or message handlers, you can map each DAQ Event to individual callbacks (specify different callbackAddr) or message handlers (specify different handle).
- If you just want to define a single callback or message handler to handle DAQ Events, you can distinguish by handle or message in that callback or message handler.
Visual Basic
Use N custom controls.
- If you name each instance of the control differently (for example, GeneralDAQEvent1, GeneralDAQEvent2, etc.), each will have a separate GeneralDAQEventn_Fire routine.
- If you make a control array, the GeneralDAQEventn_Fire routine will have an extra parameter Index as Integer, so you can distinguish by Index.
The LabVIEW Implementation of DAQ Events as DAQ Occurrences

Just as in NI-DAQ, you configure DAQ Occurrence parameters, set up a way to handle the occurrences using the Wait on Occurrence primitive, and start an asynchronous DAQ operation. When you are finished, clear the DAQ operation and the occurrences (using the DAQ Occurrence Config.vi).
In the DAQ Occurrence Config.vi, the DAQ Event terminal accepts the following codes, as shown in this table that cross-references the DAQEvent parameter in Config_DAQ_Event_Message:
DAQ Occurrence Config “DAQ Event” | DAQ Occurrence Description | Equivalent "DAQEvent" in Config_DAQ_Event_Message |
0 | Set the occurrence only once when LabVIEW acquires a number of scans or updates equal to of the general value A control. | 0 |
1 | Set the occurrence every time LabVIEW acquires the number of scans or updates equal to the general value A control. | 1 |
2 | Set the occurrence when the acquisition completes or stops because of an error. | 2 |
3 | Set the occurrence when the analog input data obtained from any channel list in the channel control meets the conditions specified by the level conditions cluster. | 5, 6 |
4 | Set the occurrence every time the output of the counter specified by the channel changes state so that it generates an interrupt. | 9 |
5 | Set the occurrence when data from any port in channel causes this statement to be true: data AND general value A is NOT equal to general value B. | 7 |
6 | Set the occurrence when data from any port in channel causes this statement to be true: data AND general value A equals general value B. | 8 |
Below is an example of a continuous analog input data acquisition that uses DAQ Occurrences to get data when the acquisition is finished (DAQ Event 2).

To handle N DAQ Events, you can call the DAQ Occurrence Config.vi N times, and use the Wait on Occurrence primitive N times. One thing to watch out for is that if you set your time limit on Wait on Occurrence to -1 (wait forever), and if the DAQ Event never happens, your LabVIEW diagram will simply keep on waiting for the event. Setting a timeout limit is recommended.
When You Can Benefit from Using DAQ Events
Here are some examples of when you can benefit from implementing DAQ events in your application:
- When you do not want to block a foreground process by reading data with conventional methods, such as DAQ_DB_Transfer in NI-DAQ, or AI Buffer Read in LabVIEW. For instance, if your foreground tasks, such as graphing data, is taking a while, then the your analog input operations may be overflowing the acquisition buffer. Conversely, if your foreground data gathering is taking a while, then other tasks, such as graphing data, may not be running as fast as you want.
- When some special handling is required for every N scans of analog input data acquired, or for that matter, every N updates of analog output data or digital I/O data. (You can use DAQ Event 0, 1, or 2 for this.) When analog-trigger-like acquisition methods are needed from a DAQ device without hardware analog triggering capabilities. (You may want to use DAQ Event 3 or 4, or the Config_ATrig_Event_Message function for this.)
- When you want to be notified when the analog input data goes into or out of a certain hysteresis range, and you do not want to poll for such events. (You may want to use DAQ Event 5 or 6, or the Config_Alarm_Deadband function for this.)
- When you want to do something immediately after a particular digital input/output line changes state at handshaking time. (You can use DAQ Event 7 or 8 for this. Remember, an 8255-based DIO device is required, and you must use handshaking!)
- When the CPU needs to be interrupted at regular time intervals for some periodic operation (you may want to use DAQ Event 9 for this).
You probably should not use DAQ Events on the following occasions:
- If the DAQ events occur too fast. In the case of the message-handling method and the Visual Basic custom control, you will end up with a large backlog of messages, and in Windows 3.1, you may never see some messages due to the limited Windows message queue size! In the case of Windows 3.1 callbacks, if the events simply occur too fast, you may end up crashing your machine. The threshold rate depends on the computer, but usually is in the range of 8,000 to 10,000 events/s.
- When you simply need to read single-point analog input data at a regular interval in a loop and performance is acceptable even in a single-process environment (such as Windows 3.1 or LabVIEW) perhaps even software double-buffering, if necessary. However, the modifications required to implement DAQ Events in your program may not really be worth the trouble. (Refer to the performance versus ease of implementation earlier.)
- When you want to watch for state changes on several digital lines but do not want to use handshaking ay want to poll the digital line just every once in a while with the DIG_Prt functions. Otherwise, setting up the DAQ events for each line will slow down the overall DAQ Event response.
- When you need to trap an NI-DAQ error AND find out the error code. DAQ Event 2 will notify when an error has occurred during an asynchronous DAQ operation, but does not have a way of passing back the NI-DAQ error code. Make sure you check error codes returned from all NI-DAQ functions.
Conclusion
Appendix -- Examples of Using DAQ Events in NI-DAQ
Example 1 Using DAQ Event 1 in LabWindows/CVI with Callbacks
File: daqevent.c
/*
* EXAMPLE: Handling DAQ Events using Callbacks
*
* Filename: DAQEvent.C
*
* Other files: DAQEvent.PRJ - automatically generated by CVI
*
* Compiler: LabWindows/CVI
*/
/** GUIDE TO USING THIS EXAMPLE ******************************************
*
* This example shows how to setup DAQ Events and how to use callback
* functions to trap the DAQ Events.
*
* This particular example was written to use DAQ Event 1.
*
* To modify this example, you can change the following functions:
*
* SetupNIDAQEvents(),
* CleanupNIDAQEvents(), and
* the code inside Callback().
*
* The LabWindows/CVI specific items are noted by a [CVI].
* If you want to use a different compiler, you may have to modify them.
*
* Also, if you are using a C/C++ development environment other than
* LabWindows/CVI under Windows 3.1, you will have to place the CallBack
* in a DLL. Refer to the NI-DAQ Function Reference Manual for details.
*************************************************************************/
/*
* Program Includes
*/
#include <stdio.h>
/* [CVI] these are for LabWindows/CVI */
#include <utility.h>
#include <userint.h>
#include <dataacq.h> /* NI-DAQ API Header file */
/*
* Program constants and defines
*/
#define COUNT 1000
#define CHECK_RETURN_CONDITION(err) if (err) return (err)
/*
* Program globals (static)
*/
static short
buffer[COUNT] = {0},
doneFlag = 0;
/*
* Function Prototypes
*
* Note: the types DAQEvent... are defined in dataacq.h as:
*
* Win3.1 Win95/NT
* DAQEventHandle short int
* DAQEventMsg short int
* DAQEventWParam unsigned short unsigned int
* DAQEventLParam long long
*/
void CallBack (DAQEventHandle handle,
DAQEventMsg msg,
DAQEventWParam wParam,
DAQEventLParam lParam);
/* ----------------------------------------------------------------------
* FUNCTION: Callback
* ************************
* CHANGE THIS AS NECESSARY
* ************************
*/
void CallBack (DAQEventHandle handle,
DAQEventMsg msg,
DAQEventWParam wParam,
DAQEventLParam lParam)
{
/* check which device called the callback */
short iDeviceCalled = (wParam & 0x00FF);
/* display the number of scans */
printf("%ld scans have been acquired from device #%d...\n",
lParam, iDeviceCalled);
/* check 'doneFlag' */
doneFlag = (wParam & 0xFF00) >> 8;
if (doneFlag)
printf("Data acquisition is done!\n");
}
/* ----------------------------------------------------------------------
* FUNCTION: SetupNIDAQEvents
* ************************
* CHANGE THIS AS NECESSARY
* ************************
*/
short SetupNIDAQEvents(short iDevice, short iChan)
{
short iStatus = 0,
iDevCode, /* DAQ device code - from Init_DA_Brds */
iTimeBase; /* DAQ timebase - from DAQ_Rate */
unsigned short
uSampInterval; /* DAQ sample interval - from DAQ_Rate */
unsigned long
ulCount = 1000; /* number of total samples to acquire */
long eventInterval = 100; /* the "N" in Every N scans */
char cpChanStr[5] = {0};
/*
* INITIALIZE DAQ Device (optional)
*/
iStatus = Init_DA_Brds(iDevice, &iDevCode);
CHECK_RETURN_CONDITION(iStatus);
/*
* CONFIGURE DAQ Event
*/
/* setup channel string for DAQ Event */
sprintf(cpChanStr, "AI%-d\0", iChan);
/* call Config_DAQ_Event_Message */
iStatus = Config_DAQ_Event_Message (iDevice,
1, /* DAQ Event 1 */
cpChanStr, /* chan string */
1, /* Add message */
eventInterval, /* DAQTrigVal0 */
0, 0, 0, 0, 0, 0,
&CallBack /* the callback */
);
CHECK_RETURN_CONDITION(iStatus);
/*
* Start Async operation
*/
iStatus = DAQ_Rate (200.0, 0, &iTimeBase, &uSampInterval);
CHECK_RETURN_CONDITION(iStatus);
iStatus = DAQ_Start (iDevice, iChan, 1, buffer,
ulCount, iTimeBase, uSampInterval);
CHECK_RETURN_CONDITION(iStatus);
return 0;
}
/* ----------------------------------------------------------------------
* FUNCTION: CleanupNIDAQEvents
* ************************
* CHANGE THIS AS NECESSARY
* ************************
*/
void CleanupNIDAQEvents(short iDevice)
{
/*
* Stop async operation
*/
DAQ_Clear(iDevice);
/*
* CLEAR all DAQ Events!
*/
Config_DAQ_Event_Message (iDevice, 0, "",
1, 0, 0, 0, 0, 0, 0, 0, 0);
}
/* ----------------------------------------------------------------------
* FUNCTION: main
*/
void main(void)
{
/* declare/initialize local variables */
short iStatus = 0,
iDevice = 2, /* DAQ device to use: device #1 */
iChan = 1; /* DAQ device channel to sample */
long loopCount = 0;
/* [CVI] Clear screen */
Cls();
printf("DAQ Events with Callback Example\n\n");
/* setup */
iStatus = SetupNIDAQEvents(iDevice, iChan);
/* check if any error occurred during setup */
if (iStatus == 0)
{
/* everything is fine, so loop around until done!
* This keeps the program running.
*/
while (!doneFlag)
{
/* [CVI] this allows you to break in LabWindows/CVI */
ProcessSystemEvents();
loopCount++;
}
}
/* cleanup */
CleanupNIDAQEvents(iDevice);
}
/* end of program: daqevent.C */
Example 2 Using DAQ Event 1 in Visual C++ with Message Handling
File: daqevent.cpp
//
// EXAMPLE: Handling DAQ Events using Windows Messages
//
// Filename: DAQEvent.CPP
//
// Other files needed:
// DAQEvent.MAK - automatically generated by VC++
// DAQEvent.DEF - automatically generated by VC++
// NI-DAQ API header file (NIDAQ.H)
// NI-DAQ Import Library (NIDAQ.LIB or NIDAQ32.LIB)
//
// Compiler: Visual C++ (VC++ 4.2-32bit was used)
//
/** GUIDE TO USING THIS EXAMPLE ******************************************
*
* This example shows how to setup DAQ events and how to use Windows
* Messaging to trap the DAQ events in Windows.
*
* This particular example was written to use DAQ Event 1.
*
* To modify this example, you can change the following functions:
*
* SetupNIDAQEvents(),
* CleanupNIDAQEvents(), and
* the code inside the WM_NIDAQ_MSG case in WindowProc().
*
* The WM_NIDAQ_MSG case in WindowProc() is where you can do any
* necessary DAQ event handling. You can also define and configure
* different WM_??? messages by #define-ing them and calling
* Config_DAQ_Event_Message with each new WM_??? message code.
*
* Since this code all runs in "User Mode", there are absolutely NO
* restrictions on what NI-DAQ functions you can or cannot call.
*
* NOTE: If you are using Microsoft Foundation Classes (MFC), there is
* an easier way to do this.
* You use the MESSAGE_MAP directive to map your NI-DAQ message,
* such as WM_NIDAQ_MSG, to an event handler function, such as
* OnNIDAQEvent(...). In this case, OnNIDAQEvent will not need
* to switch on messages, thus simplifying the code a bit.
*************************************************************************/
//
// Program Includes
//
#include <windows.h>
#include <string.h>
#include <stdlib.h>
// NI-DAQ API Header file (before NI-DAQ 5.0, this was called WDAQ_C.H)
#include "nidaq.h"
//
// Program constants - change these as needed
//
#define iDEVICE 1
#define iCHAN 1
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 80
#define REDRAW_WIDTH 300
#define REDRAW_HEIGHT 50
// WM_USER is the beginning of the user-definable range of msg codes
#define WM_NIDAQ_MSG_BASE (WM_USER + 0x100)
#define WM_NIDAQ_MSG WM_NIDAQ_MSG_BASE
// define more messages if necessary up to this value!
#define WM_USER_LAST 0x7FFF
#define CHECK_RETURN_CONDITION(err) if (err) return (err)
//
// Program globals
//
static char pszMessage[80] = {0};
//
// Prototypes
//
int WINAPI WinMain
(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pszCmdLine,
int nCmdShow
);
void CheckError
(
HWND hWnd,
short iDevice,
short iErrCode,
char* pszFunc
);
i16 SetupNIDAQEvents
(
HWND hWnd,
short iDevice,
short iChan
);
void CleanupNIDAQEvents
(
short iDevice
);
LRESULT CALLBACK WindowProc
(
HWND hWnd,
UINT uMsgId,
WPARAM wParam,
LPARAM lParam
);
// ---------------------------------------------
// FUNCTION: WinMain
//
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR pszCmdLine,
int nCmdShow
)
{
static char szAppName[] = "DAQ Events with Windows Messaging Example";
HWND hWnd;
MSG msg;
WNDCLASS wndClass;
short iErr = 0,
iDevice = iDEVICE,
iChan = iCHAN;
// register the window class
wndClass.style = 0;
wndClass.lpfnWndProc = WindowProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szAppName;
if (RegisterClass(&wndClass) == 0)
return 0;
// create window
hWnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
WINDOW_WIDTH, //nWidth: change if needed
WINDOW_HEIGHT, //nHeight: change if needed
NULL, NULL, hInstance, NULL);
if (!hWnd)
return 0;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//
// place NI-DAQ functions to start event messaging here!
//
iErr = SetupNIDAQEvents(hWnd, iDevice, iChan);
CheckError(hWnd, iDevice, iErr, "SetupNIDAQEvents");
//
// generic message handling loop...
// messages are trapped and handled here.
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// ---------------------------------------------
//
// FUNCTION: CheckError
//
void CheckError
(
HWND hWnd,
short iDevice,
short iErrCode,
char* pszFunc
)
{
if (iErrCode)
{
char pszErrMsg[80];
wsprintf(pszErrMsg, "Error code %d at %s\n", iErrCode, pszFunc);
// display message box
MessageBox(hWnd, pszErrMsg, "NI-DAQ Error",
MB_APPLMODAL | MB_ICONEXCLAMATION | MB_OK );
// clean up the mess
CleanupNIDAQEvents(iDevice);
}
}
// ---------------------------------------------
// FUNCTION: SetupNIDAQEvents
// ************************
// CHANGE THIS AS NECESSARY
// ************************
i16 SetupNIDAQEvents
(
HWND hWnd,
short iDevice,
short iChan
)
{
// declare/initialize local variables
short iErr = 0,
iDevCode = 0,
iTimeBase = 0;
static short
ipBuffer[1000] = {0};
unsigned short
uSampInterval = 0;
unsigned long
ulCount = 1000;
long eventInterval = 100;
char cpChanStr[5] = {0};
/*
* INITIALIZE DAQ Device (optional)
*/
iErr = Init_DA_Brds(iDevice, &iDevCode);
CHECK_RETURN_CONDITION(iErr);
/*
* CONFIGURE DAQ Event
*/
// setup channel string for DAQ Event
wsprintf(cpChanStr, "AI%-d\0", iChan);
// call Config_DAQ_Event_Message
iErr = Config_DAQ_Event_Message(iDevice,
(i16) 1, // add message
cpChanStr, // channel string
(i16) 1,// daq event type
(i32) eventInterval,// trig val 0
(i32) 0,// trig val 1
(u32) 0,// trigSkipCount
(u32) 0,// preTrigScans
(u32) 0,// postTrigScans
(void*) hWnd, // handle of window
(i16) WM_NIDAQ_MSG, // message to post
(u32) NULL);
CHECK_RETURN_CONDITION(iErr);
/*
* Start Async operation
*/
iErr = DAQ_Rate(100.0, 0, &iTimeBase, &uSampInterval);
CHECK_RETURN_CONDITION(iErr);
iErr = DAQ_Start(iDevice, iChan, 1, ipBuffer, ulCount,
iTimeBase, uSampInterval);
CHECK_RETURN_CONDITION(iErr);
return 0;
}
// ---------------------------------------------
// FUNCTION: CleanupNIDAQEvents
// ************************
// CHANGE THIS AS NECESSARY
// ************************
void CleanupNIDAQEvents
(
short iDevice
)
{
/*
* Stop async operation
*/
DAQ_Clear(iDevice);
/*
* CLEAR all DAQ Events!
*/
Config_DAQ_Event_Message(iDevice,
(i16) 0,
"",
(i16) 2,
(i32) 0,
(i32) 0,
(u32) 0,
(u32) 0,
(u32) 0,
(void*) NULL,
(i16) NULL,
(u32) NULL);
}
// ---------------------------------------------
// WINDOWS MAIN CALLBACK FUNCTION: WindowProc
// This is where you handle the events.
//
LRESULT CALLBACK WindowProc
(
HWND hWnd,
UINT uMsgId,
WPARAM wParam,
LPARAM lParam
)
{
static unsigned long
uNIDAQeventCount = 0;
PAINTSTRUCT
paintStruct;
HDC hDC;
RECT lpRect;
short iErr,
iDeviceFromWparam;
switch (uMsgId)
{
case WM_PAINT:
// window needs repainting, reprint text in global string
hDC = BeginPaint(hWnd, &paintStruct);
TextOut(hDC, 0, 0, pszMessage, lstrlen(pszMessage));
EndPaint(hWnd, &paintStruct);
return 0;
break;
case WM_DESTROY:
// user hit close button
CleanupNIDAQEvents(iDEVICE);
PostQuitMessage(0);
return 0;
break;
case WM_NIDAQ_MSG:
// **************************************
// put your NI-DAQ Message handling here!
// **************************************
// increment static counter
uNIDAQeventCount++;
iDeviceFromWparam = (wParam & 0x00FF);
// toggle a digital line using NI-DAQ functions!
iErr = DIG_Prt_Config(iDeviceFromWparam, 0, 0, 1);
CHECK_RETURN_CONDITION(iErr);
iErr = DIG_Out_Port(iDeviceFromWparam, 0, 1);
CHECK_RETURN_CONDITION(iErr);
iErr = DIG_Out_Port(iDeviceFromWparam, 0, 0);
CHECK_RETURN_CONDITION(iErr);
// check wParam to see if DAQ is done...
if (((wParam & 0xFF00)>> 8) == 1)
{
strcpy(pszMessage, "Data acquisition is done!");
CleanupNIDAQEvents(iDEVICE);
}
else
// construct generic message showing # of scans done
wsprintf(pszMessage, "%ld scans have been acquired.", lParam);
// invalidate window region to repaint
lpRect.left = 0; // left edge
lpRect.top = 0; // top edge
lpRect.right = REDRAW_WIDTH; // arbitrary...
lpRect.bottom = REDRAW_HEIGHT; // arbitrary...
InvalidateRect(hWnd, &lpRect, TRUE);
// let window repaint - this sends WM_PAINT msg to redisplay text
UpdateWindow(hWnd);
return 0;
break;
default:
// handle other usual messages...
return DefWindowProc(hWnd, uMsgId, wParam, lParam);
}
}
// end of program: daqevent.CPP
Example 3 Using DAQ Event 1 in Visual Basic (32-bit) with the GeneralDAQEvent Custom Control
The form for this Visual Basic program would have two buttons, one with the name "cmdDoOperation" and the other with the name "cmdExit". Also, make sure you add the General DAQ Event custom control to the form. To enter the code for GeneralDAQEvent1_Fire, simply double-click on the custom control on the form.
File: daqevent.frm
‘NOTE: user interface (form) details are omitted from this example.
Option Explicit
Dim iDevice as Integer
' ************************************************************************
' SUBROUTINE: CleanUp
' DESCRIPTION: Cleans up the DAQ operation.
' INPUTS: none
' ************************************************************************
Sub CleanUp ()
Dim iStatus As Integer
' Turn off DAQ Events
GeneralDAQEvent1.Enabled = False
GeneralDAQEvent1.Refresh
' Clear DAQ operation. Don't check errors on purpose.
iStatus% = DAQ_Clear(iDevice%)
End Sub
' ************************************************************************
' SUBROUTINE: cmdDoOperation_Click
' DESCRIPTION: The main NI-DAQ operations are here
' ************************************************************************
Sub cmdDoOperation_Click ()
' Local Variable Declarations:
Dim iStatus As Integer
Dim iChan As Integer
Dim iGain As Integer
Dim dSampRate As Double
Dim ulCount As Long
Dim dGainAdjust As Double
Dim dOffset As Double
Dim iUnits As Integer
Dim iSampTB As Integer
Dim uSampInt As Integer
Static piBuffer(5000) As Integer
iDevice% = 1
iChan% = 1
iGain% = 1
dSampRate# = 1000#
ulCount& = 5000
dGainAdjust# = 1#
dOffset# = 0#
' Convert sample rate (S/sec) to appropriate timebase and sample
' interval values.
iStatus% = DAQ_Rate(dSampRate#, iUnits%, iSampTB%, uSampInt%)
' setup the GeneralDAQEvent control
GeneralDAQEvent1.Board = iDevice%
GeneralDAQEvent1.DAQEvent = 1
GeneralDAQEvent1.ChanStr = "AI" + Trim$(Str$(iChan%))
GeneralDAQEvent1.DAQTrigVal0 = ulCount& / 10
GeneralDAQEvent1.Enabled = True
GeneralDAQEvent1.Refresh
' Acquire data from a single channel
iStatus% = DAQ_Start(iDevice%, iChan%, iGain%, piBuffer%(0), ulCount&, iSa
' Also, there is no polling for completion.
' See the GeneralDAQEvent1_Fire() routine for the event handler.
End Sub
' ************************************************************************
' SUBROUTINE: cmdExit_Click
' DESCRIPTION: Clean up and exit
' ************************************************************************
Sub cmdExit_Click ()
Call CleanUp
End
End Sub
' ************************************************************************
' SUBROUTINE: GeneralDAQEvent1_Fire
' DESCRIPTION: Gets automatically called at DAQ Event
' ************************************************************************
Sub GeneralDAQEvent1_Fire (DoneFlag As Integer, Scans As Long)
If (DoneFlag = 1) Then
Call CleanUp
Print "Acquisition is done!"
Else
' you can use DAQ_Monitor to index into the data at this point.
Print Str$(Scans&) + " scans acquired."
End If
End Sub
Related Links:
About the NI-DAQ Function Reference
NI-DAQ Function Reference Manual for PC Compatibles
NI-DAQ User Manual for PC Compatibles
Reader Comments | Submit a comment »
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/).
