05-11-2020 02:54 AM
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.
Solved! Go to Solution.
05-14-2020 04:06 AM
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
05-14-2020 08:06 PM
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.