Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

Running Multi-Counters with NI9361

Solved!
Go to solution

I have a cDAQ-9181 and 9361,To measure two angle encoder at the same time, How can I run two Task at the same time with C# , And Read the Angle respectively.

Thanks.

0 Kudos
Message 1 of 3
(1,882 Views)
Solution
Accepted by topic author Shawn_pmc

In the official documentation is an example to run a task on a different thread asynchronously you can use this with a few changes. I created my Tasks at first in the main programm. Then you can use the example and change it so that it doesnt create the task but takes a given one in the constructor. This way i could get multiple tasks running at the same time. If you update UI elements just watch out for thread save calls.

 

public class DaqThread : IDisposable
    {
        private ManualResetEvent runningTaskWaitHandle; // Used for synchronization while disposing task 
        private NationalInstruments.DAQmx.Task runningTask;
        private NationalInstruments.DAQmx.Task continuousTask;
        private AnalogMultiChannelReader analogReader;
        private AsyncCallback analogCallback;
        private AnalogWaveform<double>[] data;

        private Pruefung parentWindow;


        public DaqThread(NationalInstruments.DAQmx.Task taskToRun, Pruefung parentWindow)
        {
            runningTaskWaitHandle = new ManualResetEvent(true); // Instantiate wait handle
            continuousTask = taskToRun;
            this.parentWindow = parentWindow;
        }

        #region IDisposable Members

        // Dispose method executes on the main thread 
        public void Dispose()
        {
            SafelyDisposeTask();
        }

        #endregion

        // StartAcquisition method executes on the main thread 
        public void StartAcquisition()
        {
            try
            {
                analogReader = new AnalogMultiChannelReader(continuousTask.Stream);
                analogReader.SynchronizeCallbacks = false;
                analogCallback = new AsyncCallback(AnalogReadCallback);
                // Create a reference (runningTask) to the task running (continuousTask)
                runningTask = continuousTask;
                analogReader.BeginReadWaveform(Convert.ToInt32(continuousTask.Timing.SamplesPerChannel), analogCallback, continuousTask);

                Debug.WriteLine("Schreibe: " + continuousTask.Timing.SamplesPerChannel.ToString());
            }
            catch (DaqException ex)
            {
                // Exception thrown
                runningTask = null;
                continuousTask.Dispose();
            }
        }

        // StopAcquisition method executes on the main thread 
        public void StopAcquisition()
        {
            SafelyDisposeTask();
        }

        // AnalogReadCallback method executes on 
        //   - worker thread when SynchronizeCallback is set to false (current behavior) 
        //   - main thread when SynchronizeCallback is set to true 
        private void AnalogReadCallback(IAsyncResult ar)
        {
            try
            {
                // Check to see whether the task is still running 
                if (runningTask != null && runningTask == ar.AsyncState)
                {
                    data = analogReader.EndReadWaveform(ar);

                    // If ProcessData is updating UI components created on the main thread, then 
                    // invoke ProcessData on the main thread when SynchronizeCallback is  
                    // set to false.
                    ProcessData();

                    analogReader.BeginReadWaveform(Convert.ToInt32(continuousTask.Timing.SamplesPerChannel), analogCallback, continuousTask);
                }
                else
                {
                    // Signal waiting thread to proceed
                    SignalThread();

                }
            }
            catch (DaqException ex)
            {
                // Exception thrown
                runningTask = null;
                continuousTask.Dispose();
                // Signal waiting thread to proceed
                SignalThread();
            }
        }

        // ProcessData method executes on same thread on which AnalogReadCallback executes 
        private void ProcessData()
        {
            // If this method is updating UI components created on the main thread, then invoke 
            // the UI code or this entire method on the main thread when SynchronizeCallback 
            // is set to false.

        }

        // SafelyDisposeTask method executes on the main thread 
        private void SafelyDisposeTask()
        {
            if (runningTask != null)
            {
                if (!analogReader.SynchronizeCallbacks)
                {
                    // When SynchronizeCallback is false, the callback will be executed on  
                    // the worker thread. In that case, wait for the pending callback to be  
                    // completed before disposing task. 

                    // Reset wait handle to wait for callback, which is on the worker thread
                    runningTaskWaitHandle.Reset();

                    // Set runningTask to null to indicate the callback, not to initiate  
                    // additional reads
                    runningTask = null;

                    // Wait for pending callback on the worker thread.  
                    //   - If the last operation on runningTaskWaitHandle is Set (in SignalThread),  
                    //     WaitOne will not wait and proceed to execute the next line of code. 
                    //   - If the last operation on runningTaskWaitHandle is Reset (in  
                    //     SafelyDisposeTask), WaitOne will make the main thread wait for the signal  
                    //     (Set Operation on runningTaskWaitHandle)

                    runningTaskWaitHandle.WaitOne();
                }
                else
                {
                    // When SynchronizeCallback is true, this method and the callback will  
                    // be executed on the main thread. In that case, there is no need to wait for pending  
                    // callback to be completed before disposing task, because the callack  
                    // and this method cannot execute at the same time. 

                    // Set runningTask to null to indicate the callback, not to initiate  
                    // additional reads
                    runningTask = null;
                }
            }
            // Safe to dispose task 
            if (continuousTask != null)
            {
                continuousTask.Dispose();
            }
        }

        // SignalThread method executes on the worker thread 
        private void SignalThread()
        {
            // When SynchronizeCallback is false, the callback will be executed on the worker  
            // thread. In that case, while disposing task, the main thread is waiting on the callback 
            // which is executing on the worker thread to be completed. Signal (call Set  
            // operation on runningTaskWaitHandle) the main thread to proceed 
            if (!analogReader.SynchronizeCallbacks)
            {
                runningTaskWaitHandle.Set();
            }
        }
    }

 

This example is for reading analog data but I think you could also use this. Another way could be just to use one Task for different devices if you are reading data with the same clock.

 

Greetings

Marius

Message 2 of 3
(1,813 Views)
Solution
Accepted by topic author Shawn_pmc

Hi  Marius,

Thanks for your reply. I already found a Method (CounterMultiChannelReader) in the DAQmx Library. Which can Read two channel's Values in one Task. And It's works.

 

public ConnectingForm()
{
InitializeComponent();
asyncCB = new AsyncCallback(CounterInCallback);
}

 

private void RunTask()

{

Task = new NationalInstruments.DAQmx.Task();
Task.CIChannels.CreateAngularEncoderChannel (Channel1 , "", CIEncoderDecodingType.X4, false, 0, CIEncoderZIndexPhase.AHighBHigh, DataHost.PulsePerRevolution, 0.0, CIAngularEncoderUnits.Degrees);
Task.CIChannels.CreateAngularEncoderChannel (Channel2 , "", CIEncoderDecodingType.X4, false, 0, CIEncoderZIndexPhase.AHighBHigh, DataHost.PulsePerRevolution, 0.0, CIAngularEncoderUnits.Degrees);
Task.Timing.ConfigureSampleClock("", SampleRate, SampleClockActiveEdge.Rising, SampleQuantityMode.ContinuousSamples, 1);
runningTask = Task;
counterInReader = new CounterMultiChannelReader(Task.Stream);
counterInReader.SynchronizeCallbacks = true;
Double data = new double[NumberOfSamples, NumberOfSamples];
counterInReader.BeginReadMultiSampleDouble(NumberOfSamples, asyncCB, Task);

}

 

Still appreciate your reply. And provide a example to help others.

0 Kudos
Message 3 of 3
(1,792 Views)