10-12-2010
04:59 AM
- last edited on
08-14-2025
02:03 PM
by
Content Cleaner
Hello everybody.
I have a problem with an example provided by NI for DAQmx ANSI C programmation. I putted this question here, because I could not find a suitable board for it.
About the problem: I'm currently working with a NI PCI-6120 device and therefore I like to connect a trigger signal to PFIO and a AI channel at which the software should acquire data in combination with a trigger event (->PFIO). Serveral times.
I found a good example (https://www.ni.com/en/support/documentation/supplemental/21/retriggerable-tasks-in-ni-daqmx.html) which should do the things I'd like to have, but I have problems to understand the code or maybe I don't really understand the way they realized it.
Here the code:
#include <string.h>
#include <stdio.h>
#include <NIDAQmx.h>
static TaskHandle AItaskHandle=0,DItaskHandle=0;
#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else
static int32 GetTerminalNameWithDevPrefix(TaskHandle taskHandle, const char terminalName[], char triggerName[]);
int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData);
int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData);
int main(void)
{
int32 error=0;
char errBuff[2048]={'\0'};
char trigName[256];
/*********************************************/
// DAQmx Configure Code
/*********************************************/
DAQmxErrChk (DAQmxCreateTask("",&AItaskHandle));
DAQmxErrChk (DAQmxCreateAIVoltageChan(AItaskHandle,"Dev1/ai0","",DAQmx_Val_Cfg_Default,-10.0,10.0,DAQmx_Val_Volts,NULL));
DAQmxErrChk (DAQmxCfgSampClkTiming(AItaskHandle,"",10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));
DAQmxErrChk (GetTerminalNameWithDevPrefix(AItaskHandle,"ai/SampleClock",trigName));
DAQmxErrChk (DAQmxCreateTask("",&DItaskHandle));
DAQmxErrChk (DAQmxCreateDIChan(DItaskHandle,"Dev1/port0","",DAQmx_Val_ChanForAllLines));
DAQmxErrChk (DAQmxCfgSampClkTiming(DItaskHandle,trigName,10000.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));
DAQmxErrChk (DAQmxRegisterEveryNSamplesEvent(AItaskHandle,DAQmx_Val_Acquired_Into_Buffer,1000,0,EveryNCallback,NULL));
DAQmxErrChk (DAQmxRegisterDoneEvent(AItaskHandle,0,DoneCallback,NULL));
/*********************************************/
// DAQmx Start Code
/*********************************************/
DAQmxErrChk (DAQmxStartTask(DItaskHandle));
DAQmxErrChk (DAQmxStartTask(AItaskHandle));
printf("Acquiring samples continuously. Press Enter to interrupt\n");
printf("\nRead:\tAI\tDI\tTotal:\tAI\tDI\n");
getchar();
Error:
if( DAQmxFailed(error) )
DAQmxGetExtendedErrorInfo(errBuff,2048);
if( AItaskHandle ) {
/*********************************************/
// DAQmx Stop Code
/*********************************************/
DAQmxStopTask(AItaskHandle);
DAQmxClearTask(AItaskHandle);
AItaskHandle = 0;
}
if( DItaskHandle ) {
/*********************************************/
// DAQmx Stop Code
/*********************************************/
DAQmxStopTask(DItaskHandle);
DAQmxClearTask(DItaskHandle);
DItaskHandle = 0;
}
if( DAQmxFailed(error) )
printf("DAQmx Error: %s\n",errBuff);
printf("End of program, press Enter key to quit\n");
getchar();
return 0;
}
static int32 GetTerminalNameWithDevPrefix(TaskHandle taskHandle, const char terminalName[], char triggerName[])
{
int32 error=0;
char device[256];
int32 productCategory;
uInt32 numDevices,i=1;
DAQmxErrChk (DAQmxGetTaskNumDevices(taskHandle,&numDevices));
while( i<=numDevices ) {
DAQmxErrChk (DAQmxGetNthTaskDevice(taskHandle,i++,device,256));
DAQmxErrChk (DAQmxGetDevProductCategory(device,&productCategory));
if( productCategory!=DAQmx_Val_CSeriesModule && productCategory!=DAQmx_Val_SCXIModule ) {
*triggerName++ = '/';
strcat(strcat(strcpy(triggerName,device),"/"),terminalName);
break;
}
}
Error:
return error;
}
int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
{
int32 error=0;
char errBuff[2048]={'\0'};
static int totalAI=0,totalDI=0;
int32 readAI,readDI;
float64 AIdata[1000];
uInt32 DIdata[1000];
/*********************************************/
// DAQmx Read Code
/*********************************************/
DAQmxErrChk (DAQmxReadAnalogF64(AItaskHandle,1000,10.0,DAQmx_Val_GroupByChannel,AIdata,1000,&readAI,NULL));
DAQmxErrChk (DAQmxReadDigitalU32(DItaskHandle,1000,10.0,DAQmx_Val_GroupByChannel,DIdata,1000,&readDI,NULL));
printf("\t%d\t%d\t\t%d\t%d\r",readAI,readDI,totalAI+=readAI,totalDI+=readDI);
fflush(stdout);
Error:
if( DAQmxFailed(error) ) {
DAQmxGetExtendedErrorInfo(errBuff,2048);
/*********************************************/
// DAQmx Stop Code
/*********************************************/
if( AItaskHandle ) {
DAQmxStopTask(AItaskHandle);
DAQmxClearTask(AItaskHandle);
AItaskHandle = 0;
}
if( DItaskHandle ) {
DAQmxStopTask(DItaskHandle);
DAQmxClearTask(DItaskHandle);
DItaskHandle = 0;
}
printf("DAQmx Error: %s\n",errBuff);
}
return 0;
}
int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData)
{
int32 error=0;
char errBuff[2048]={'\0'};
// Check to see if an error stopped the task.
DAQmxErrChk (status);
Error:
if( DAQmxFailed(error) ) {
DAQmxGetExtendedErrorInfo(errBuff,2048);
DAQmxClearTask(taskHandle);
if( DItaskHandle ) {
DAQmxStopTask(DItaskHandle);
DAQmxClearTask(DItaskHandle);
DItaskHandle = 0;
}
printf("DAQmx Error: %s\n",errBuff);
}
return 0;
}
Here my questions:
1: DAQmxErrChk (GetTerminalNameWithDevPrefix(AItaskHandle,"ai/SampleClock",trigName));
I don't get this. Why don't they just put one specific channel name at var: trigName?
2.1: DAQmxErrChk (DAQmxRegisterEveryNSamplesEvent(AItaskHandle,DAQmx_Val_Acquired_Into_Buffer,1000,0,EveryNCallback,NULL));
2.2: DAQmxErrChk (DAQmxRegisterDoneEvent(AItaskHandle,0,DoneCallback,NULL));
Why do they setup the event on the AI channel? I thought I have to check for events on the trigger channel?!
3: int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
Does this event occur for every N samples acquired?
In summary I don't understand how the program is realising the 'wait on trigger' and then starts to acquire the data. In my eyes they just plot the data on both channels without any trigger.
Thank you for reading that far. Maybe someone can help me to understand it correctly!
Bye
Denis
10-13-2010 08:05 AM
Hi Denis,
if you want to measure a specific amount of samples on multiple triggers while the task is running, this is not the apropriate example!
With the new X-Series, it is very easy to retrigger the acquisition since this is a builtin feature.
With your S-Series Card, you will have to create a CounterPulseOutput-Task
int32 DAQmxCreateCOPulseChanFreq (TaskHandle taskHandle, const char counter[], const char nameToAssignToChannel[], int32 units, int32 idleState, float64 initialDelay, float64 freq, float64 dutyCycle);
which is generating the SampleClock for your AnalogInput-Task.
You first start the Counter Output, then start the AI-Task whose Timing is configured to the source terminal "Ctr0InternalOutput"
This should do the job.
regards
Marco Brauner NIG
10-13-2010 10:50 AM
Hello!
Thank you for your answer. I have the feeling that maybe I was explaining it a bit wrong.
I do have one physical channel coming from an external system which is connected to the device providing real data (on ai0). And I have a physical second channel/line coming from an external system which is connected to the device providing a trigger (on PFIO). This external system is creating several triggers and on/at each trigger event it will send a specific amount of data.
So, I start my program and it waits on a number of trigger events. If the trigger is detected by the device it starts to read the data.
The problem is I can't retrigger efficiently with my programmation (see code below).
Code:
DAQmxErrChk (DAQmxCreateTask("",&taskHandle));
DAQmxErrChk (DAQmxCreateAIVoltageChan(taskHandle, Channels, "", DAQmx_Val_Cfg_Default, -ChanVolts, ChanVolts, DAQmx_Val_Volts, NULL));
DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle, "", ChanSR,DAQmx_Val_Falling, DAQmx_Val_FiniteSamps, (int32) ChanSmpPts));
DAQmxErrChk (DAQmxCfgDigEdgeStartTrig(taskHandle,"PFI0", DAQmx_Val_Rising));
DAQmxErrChk (DAQmxStartTask(taskHandle));
for(i=0; i<TrigEvents; i++)
{
DAQmxErrChk (DAQmxReadAnalogF64(taskHandle, (int32) ChanSmpPts, 5.0, DAQmx_Val_GroupByChannel, buffer, (int32) ChanCount * (int32) ChanSmpPts, &read, NULL));
DAQmxStopTask(taskHandle);
DAQmxErrChk (DAQmxCfgDigEdgeStartTrig(taskHandle,"PFI0", DAQmx_Val_Rising));
for(k = 0; k < len; k++)
{
result[k + i*len] = buffer[k];
}
}
But this is not working. The reinitialisation takes to much time and windows xp sp3 is not deterministic so sometimes it catches the triggerevent and sometimes not - I guess.
Greetings,
Denis
10-13-2010 11:02 AM
Hi Denis, that is exactly what I was describing. With your PCI/PXI-6120 you must use a Counter Pulse Output which can be retriggered as your AI-SampleClock as I have described before.
Try it out.
regards
Marco Brauner NIG
10-14-2010 04:46 AM
Okay I changed my code and it is not working.
I really don't know how to make it the way I want it to work.
So far I did the following:
- created a AITask
- created AIVoltchan (@AITask, "Dev3/ai0")
- created COTask
- created COPulseChan(@COTask, "Dev3/ctr0")
- configed SampClkTiming(@AITask, "Ctr0InternalOutput")
- started(COTask)
- started(AITask)
- looping Nr_Trig_Events
-- cfgDigEdgeTrig(@COTask, "PFI0")
-- ReadAnalogF64(@AITask)
- end loop
I really have no clue how this should work.
Could you provide me a basic idea how to setup everything? My trigger events are also not with the same delay between each other.
Trigger: _____|____|__|______|
AcqData ____|||___|||_|||______|||
Regards
Denis
10-14-2010 06:47 AM
Hi Denis, thx for tryin it by yourself first. I´ll try to set up an example for you, but I´m not sure if I can do it today.
Tomorrow I´ll be out of office, so most certainly it will be monday.
regards
Marco Brauner NIG
10-22-2010 07:32 AM
Hello!
I had no time the last days to continue and now the time went away and it is friday - yay ;-). But maybe you can still help me out with this problem the following week. So far, I could not figure out how you might find a way to manage this multitrigger event. My new thought would be to use 'DoneEvents' and 'NSamples'. A 'schematic' would be helpfull so I can try it on my own.
Regards,
Denis
10-27-2010 09:20 AM
Hi Denis, finally, here is an example for what I meant in my posts before.
It is AI with a retriggerable sampleclock which you can use with you´re card.
Marco Brauner NIG
10-28-2010 03:25 AM - edited 10-28-2010 03:26 AM
Hello!
Thank you very much! I am going to test it right now and hopefully I can give you a positiv response these days. I have to modify it a bit because I dont use a interface. We will see if I can manage it!
Regards,
Denis
10-29-2010 03:58 AM
Hello,
it is me again. I modified the code you provided to me. So far I can say it is working 😃
But there are some things I like to know and maybe you can explain it to me.
Right now my code acquires data from two channels. I removed the BufferInput-function, because he was not able to trigger or run corretly if I have serveral scans/triggers.
Questions:
Why does it run if I dont use a specific InputBufferSize?
// ---------------------------------------- code snippet ----------------------------------------------
// ChanSR - SampleRate
// ChanSmpPts - SamplesPerChan
// Channels = \Dev3\ai0:1 (2 channels)
// -- create Tasks
DAQmxErrChk (DAQmxCreateTask("", &AItaskHandle));
DAQmxErrChk (DAQmxCreateTask("", &COtaskHandle));
// -- create voltage chan, configure timing and optional the buffer size
DAQmxErrChk (DAQmxCreateAIVoltageChan(AItaskHandle, Channels, "", DAQmx_Val_Cfg_Default, -ChanVolts, ChanVolts, DAQmx_Val_Volts, NULL));
DAQmxErrChk (DAQmxCfgSampClkTiming(AItaskHandle, "Ctr0InternalOutput", ChanSR, DAQmx_Val_Falling, DAQmx_Val_ContSamps, (int32) ChanSmpPts));
//DAQmxErrChk (DAQmxSetBufferAttribute (AItaskHandle, DAQmx_Buf_Input_BufSize, ChanSmpPts*2));
// -- create the clock for the acquistion
DAQmxErrChk (DAQmxCreateCOPulseChanFreq (COtaskHandle, "Dev3/ctr0", "", DAQmx_Val_Hz, DAQmx_Val_Low, 0., ChanSR, 0.5));
DAQmxErrChk (DAQmxCfgImplicitTiming (COtaskHandle, DAQmx_Val_FiniteSamps, ChanSmpPts));
// -- create trigger and define the edge
DAQmxErrChk (DAQmxCfgDigEdgeStartTrig(COtaskHandle,"PFI0", DAQmx_Val_Rising));
DAQmxErrChk (DAQmxSetTrigAttribute (COtaskHandle, DAQmx_StartTrig_Retriggerable, TRUE));
// -- start the tasks
DAQmxErrChk (DAQmxStartTask(COtaskHandle));
DAQmxErrChk (DAQmxStartTask(AItaskHandle));
// -- knowing the numbers of triggers we repeat the acquisition
for(i=0; i<TrigEvents; i++)
{
DAQmxErrChk (DAQmxReadAnalogF64(AItaskHandle, (int32) ChanSmpPts, 2.0, DAQmx_Val_GroupByChannel, buffer,
(int32) (ChanCount * ChanSmpPts), &read, NULL));
for(k = 0; k < len; k++)
{
result[k + i*len] = buffer[k]; // just plot/save the data
}
}
Cleanup();
// ----------------------------------------------------------------------------------------------
Bye
Denis