Measurement Studio for VC++

cancel
Showing results for 
Search instead for 
Did you mean: 

How to timestamp the start of an acquisition triggerd by an analog edge

Hi,

i use a PCI-4474 with Visual C++ an NI Measurement Studio.

I start a voltage acquisition on an analog edge rising and i need to know when the acquisition realy begin. In fact i need to timestamp with the pc clock the start of the acquisition.

My code is very similar to the "AcqVoltageSamples_IntClkAnalogStart" sample with
    Dev2/ai0,Dev2/ai1 as physical channel
    and Dev2/ai1 as trigger source

Is it possible ?

An average solution would be to calculate the start of the acquisition from the call of the "OnEvent" function (set by m_reader->InstallEventHandler) but can i be sure that this function is called immedialty at the end of the acquisition ?

Guillaume.


0 Kudos
Message 1 of 5
(7,967 Views)
Hi,
 
Could you send the part of your code concerning your problem ? Another way to get it resolved would be to use some Windows SDK's functions like QueryPerformanceCounter and QueryPerformanceFrequency, you can have a look of these functions right there :
 
QueryPerformanceCounter :
 
QueryPerformanceFrequency :
 
Here is an example that you could use in your application :
 
#define Ms 1000       // Unit is in miliseconds
#define Us 1000000    // Unit is in microsenconds
#define Ns 1000000000 // Unit is in nanoseconds


__int64 freq, t0, t1;
DWORD time_elapsed;

/* Freq : Clock frequency
   t0 : initial time
   t1 : time juste after edge rising
   time_elapsed : variable containing the time elapsed
*/


// We retrieve the clock frequency of the computer

QueryPerformanceFrequency((LARGE_INTEGER*)&freq);

// We retrieve the initial count of the performance counter

QueryPerformanceCounter((LARGE_INTEGER*)&t0);

/*

  Here is the code containing the trigger function


*/


// Just after the egde rising trigger we retrieve the counts of the performance counter

QueryPerformanceCounter((LARGE_INTEGER*)&t1);

// We convert the counts of the performance counter in time

unit = Ns;

time_elapsed= (DWORD)(((t1 - t0) * unit) / freq);

Best regards,



Message Edité par Maxime MULLER le 01-11-2008 02:22 AM
0 Kudos
Message 2 of 5
(7,949 Views)
Hi,

and thanks Maxime for looking at my problem.

In fact the problem is that I do not know when the edge rising trigger occur so when to call the QueryPerformanceCounter function.

My code (from AcqVoltageSamples_IntClkAnalogStart) is :

    try
    {
        // Create the voltage channel
        m_task->AIChannels.CreateVoltageChannel(channelName, "",
            static_cast<DAQmxAITerminalConfiguration>(-1),
            minimum, maximum, DAQmxAIVoltageUnitsVolts);

        // Configure the internal clock
        m_task->Timing.ConfigureSampleClock("", rate, DAQmxSampleClockActiveEdgeRising,
            DAQmxSampleQuantityModeFiniteSamples, samplesPerChannel);

        // Set up a start trigger
        m_task->Triggers.StartTrigger.ConfigureAnalogEdgeTrigger(triggerSource,
            m_referenceTriggerEdge, triggerLevel);

        m_task->Triggers.StartTrigger.AnalogEdge.Hysteresis = hysteresis;

        // Set up the graph
        m_graph.Plots.RemoveAll();

        for (unsigned int i = 0; i < m_task->AIChannels.Count; i++)
        {
            m_graph.Plots.Add();
            m_graph.Plots.Item(i+1).LineColor = m_colors[i % 8];
        }

        // Begin reading
        m_reader = std::auto_ptr<CNiDAQmxAnalogMultiChannelReader>
            (new CNiDAQmxAnalogMultiChannelReader(m_task->Stream));
        m_reader->InstallEventHandler(*this, &CAcqVoltageSamples_IntClkAnalogStartDlg::OnEvent);
        m_reader->ReadMultiSampleAsync(samplesPerChannel, m_data);
    }
    catch (CException* e)
    {
        e->ReportError();
        e->Delete();
    }

so the CAcqVoltageSamples_IntClkAnalogStartDlg::OnEvent function is called when the acquisition is done are samples are copied in memory but I can not find a way to know when the trigger occur ?

Regards, Guillaume.
0 Kudos
Message 3 of 5
(7,943 Views)

Hi,

I was looking at your problem since you posted, and I finally found a piece of answer that could help you.

A way, to know when the trigger occurs is to use the DAQ Events with a callback function.

In this case, you should use the function Config_ATrig_Event_Message whose purpose is :

"Notifies NI-DAQ applications when the trigger channel signal meets certain criteria you specify. NI-DAQ sends your application a message or executes a callback function that you  provide."

You'll be able to find more informations about this function in the PDF Manual here : http://www.ni.com/pdf/manuals/321645e.pdf and more information about DAQ Events and callback functions here :  http://zone.ni.com/devzone/cda/tut/p/id/3010#toc2.

Hope this helps,

0 Kudos
Message 4 of 5
(7,915 Views)
Hi,

thanks again Maxime !

your solution seems to be good but we only use Measurement Studio VC 2005 C++ in our developpement and I think it does not mix very well with NI DAQ C code.

I found a workaround by doing a read of a single sample triggered by the analog edge and then on the callback reading the other datas. So my goal (having a callback on the reception of the trigger) is almost reach :

    // preparing the task for the reading
      try
    {
        // Create the voltage channel
        m_task->AIChannels.CreateVoltageChannel(channelName, "",
            static_cast<DAQmxAITerminalConfiguration>(-1),
            minimum, maximum, DAQmxAIVoltageUnitsVolts);

        // Configure the internal clock
        m_task->Timing.ConfigureSampleClock("", rate, DAQmxSampleClockActiveEdgeRising,
            DAQmxSampleQuantityModeFiniteSamples, samplesPerChannel);

        // Set up a start trigger
        m_task->Triggers.StartTrigger.ConfigureAnalogEdgeTrigger(triggerSource,
            m_referenceTriggerEdge, triggerLevel);

        m_task->Triggers.StartTrigger.AnalogEdge.Hysteresis = hysteresis;

        // Begin reading
        m_reader = std::auto_ptr<CNiDAQmxAnalogMultiChannelReader>
            (new CNiDAQmxAnalogMultiChannelReader(m_task->Stream));
        m_reader->InstallEventHandler(*this, &CAcqVoltageSamples_IntClkAnalogStartDlg::OnEvent);

       // I read only one sample
        m_reader->ReadSingleSampleAsync( m_sample);
    }
    catch (CException* e)
    {
        e->ReportError();
        e->Delete();
    }
}

// the callback
void CAcqVoltageSamples_IntClkAnalogStartDlg::OnEvent(CNiDAQmxAsyncOperation asyncHandle, void* userData)
    CNiComInitialize com(CNiComInitialize::Apartment);
    try
    {
        asyncHandle.CheckForAsyncException();

         // i read the remaining samples
         m_reader->ReadMultiSample( m_lsamplesPerChannel, m_data);
    }
    catch (CException* e)
    {
        e->ReportError();
        e->Delete();
    }
}

I have two remaining questions :

As I read only one sample first the callback happens roughly when the trigger is received. The precision seems to be good but can anyone tell me how good it is ?

then in the callback i read the remaining samples. For what I have seen, i do not lost any samples between the two read (ReadSingleAsync and ReadMultiSample) but can I be sure of that point ?

Regards,

Guillaume.

0 Kudos
Message 5 of 5
(7,880 Views)