04-14-2016 02:06 PM
Thank you all so much for your time and kindness to help me out! Greatly appreciated!!!
I found a horrible mistake in my code. The closing curly bracket for the switch statements was in a wrong spot. How stupid can I be? I moved this closing curly bracket to an appropriate place (i.e., immediately after the printf("Unrecognizable sequence number") statement. And the error message disappeared. Hooray!!!
However, as you have foreseen and indicated in your comments, the AO and AI tasks will stop immediately after they are started. So, I did the following modifications to the program. And it WORKED!!!!
I am very happy for what I have learned so far. I love NI Discussion Forum. I do. Call this a flattery if you want. But I do appreciate your kindness and time to help me out.
I guess now the only major thing left is that Step 13 is somewhat meaningless, because the user can no longer interrupt the program once the For loop has started. It appears to me that this requires some knowledge of multithreading, which I currently do not possess. I will spend some time to study on this subject, and will get back to this forum at a later time.
For your review and advising, I am posting my revised program below for comments. Please feel free to let me know if there is anything that can be done to further improve this program.
Thank you SO MUCH!!!
#include <stdio.h> #include <NIDAQmx.h> // DAQmx 9.3 #include <math.h> // sin() #define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else #define PI 3.141592653589793238 // function prototypes int32 CVICALLBACK EveryNCallback(TaskHandle taskHandleAI, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData); void StopTaskAOAI(); // initialize parameters at a global scope, so they are accessible inside any subroutine functions. const unsigned int N = 10000; // number of data points (This number refers to the number of data points per sweep, which include the stimulus duration and silent interval data points) const unsigned int BUFFER_SIZE = N; // buffer size in data points, [default 1000]. // declare nSweeps parameters const unsigned int N_SWEEPS_TARGET = 10; // number of sweeps to be obtained (i.e., the targeted number of sweeps to be obtained after the user has initiated the AI task) unsigned int nSweepsRecorded = 0; // number of sweeps that have been obtained via AI task // declare and initialize an error code and error buffer. This will be used for both the AO and AI tasks. int32 error = 0; // error code char errBuff[2048] = {'\0'}; // error message // create and initialize AO and AI task handles TaskHandle taskHandleAO = 0; TaskHandle taskHandleAI = 0; int main(void) { // prepare two sine waves that will be delivered via an AO channel, in a pre-defined arbitrary sequence double frequency1 = 100; // frequency in Hz, for stimulus 1 double frequency2 = 50; // frequency in Hz, for stimulus 2 double amplitude = 1.0; // baseline-to-peak amplitude of a sine wave (roughly in volts). Should be between +- 10 volts. double samplingRateWav = 20000.0; // sampling rate of the sine wave float64 stimulus1[N]; // stimulus 1 (e.g., a 100 Hz tone) float64 stimulus2[N]; // stimulus 2 (e.g., a 50 Hz tone) for (int i = 0; i < N; i++) // generate two sine waves (i.e., stimulus 1 and stimulus 2) { stimulus1[i] = amplitude * sin(2.0 * PI * frequency1 * (double)(i) / samplingRateWav); stimulus2[i] = amplitude * sin(2.0 * PI * frequency2 * (double)(i) / samplingRateWav); } // a variable indicating whether the AO task is done bool32 isTaskDoneAO = false; // arbitrarily define a presentation sequence int sequence[N_SWEEPS_TARGET] = {1, 1, 2, 1, 1, 1, 2, 1, 1, 1}; // 1 for stimulus 1, and 2 for stimulus 2 /* ---- Step 1 User presses Enter to start AO and AI tasks ----*/ printf("Press Enter to start AO and AI tasks"); getchar(); /* ---- Step 2 Loop through AO and AI tasks for N_SWEEPS_TARGET times ---- */ for (unsigned int sweep = 0; sweep < N_SWEEPS_TARGET; sweep++) { /* --- Step 3 Create AO and AI tasks --- */ DAQmxErrChk(DAQmxCreateTask("taskAO", &taskHandleAO)); DAQmxErrChk(DAQmxCreateTask("taskAI", &taskHandleAI)); /* --- Step 4 Create and configure an Analog Output Voltage channel and an Analog Input Voltage channel --- */ DAQmxErrChk(DAQmxCreateAOVoltageChan(taskHandleAO, "Dev1/ao0", "", -10.0, 10.0, DAQmx_Val_Volts, NULL)); DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandleAI, "Dev1/ai0", "", DAQmx_Val_Cfg_Default, -10.0, 10.0, DAQmx_Val_Volts, NULL)); /* --- Step 5 Define sampling rate and related parameters for the AO task and the AI task ---*/ DAQmxErrChk(DAQmxCfgSampClkTiming(taskHandleAO, "", 20000.0, DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, N)); DAQmxErrChk(DAQmxCfgSampClkTiming(taskHandleAI, "", 20000.0, DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, BUFFER_SIZE)); /* --- Step 6 setup a Digital Edge, Start Trigger --- */ DAQmxErrChk(DAQmxCfgDigEdgeStartTrig(taskHandleAO, "/Dev1/ai/StartTrigger", DAQmx_Val_Rising)); /* --- Step 7 setup parameters for AI buffer ---*/ DAQmxErrChk(DAQmxRegisterEveryNSamplesEvent(taskHandleAI, DAQmx_Val_Acquired_Into_Buffer, BUFFER_SIZE, 0, EveryNCallback, NULL)); /* ---- Step 8 write signal via AO ---- */ switch (sequence[nSweepsRecorded]) { case 1: DAQmxErrChk(DAQmxWriteAnalogF64(taskHandleAO, N, 0, 10.0, DAQmx_Val_GroupByChannel, stimulus1, NULL, NULL)); break; case 2: DAQmxErrChk(DAQmxWriteAnalogF64(taskHandleAO, N, 0, 10.0, DAQmx_Val_GroupByChannel, stimulus2, NULL, NULL)); break; default: printf("Unrecognizable sequence number"); } /* ---- Step 9 start AO and AI tasks --- */ DAQmxErrChk(DAQmxStartTask(taskHandleAO)); DAQmxErrChk(DAQmxStartTask(taskHandleAI)); /* --- Step 10 read data via AI ----*/ // This step is executed through EveryNCallback() function --- /* ---- Step 11 waite until AO task is done ----*/ DAQmxErrChk(DAQmxWaitUntilTaskDone(taskHandleAO, 10)); DAQmxErrChk(DAQmxIsTaskDone(taskHandleAO, &isTaskDoneAO)); /* ---- Step 12 stop and clear AO and AI tasks ---- */ if (isTaskDoneAO) StopTaskAOAI(); else printf("AO task got timed out.\n"); } /*--- Step 13 User presses Enter to exit the program --- */ printf("Press Enter to stop AO and AI tasks\n"); getchar(); Error: if( DAQmxFailed(error) ) DAQmxGetExtendedErrorInfo(errBuff, 2048); if( taskHandleAI!=0 ) { StopTaskAOAI(); } if( DAQmxFailed(error) ) printf("DAQmx Error: %s\n", errBuff); printf("End of program, press Enter to quit\n"); getchar(); return 0; } // A function to execute when every N samples have been obtained via AI int32 CVICALLBACK EveryNCallback(TaskHandle taskHandleAI, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData) { static int totalRead = 0; int32 read = 0; float64 data[BUFFER_SIZE]; // N /*********************************************/ // DAQmx Read Code /*********************************************/ DAQmxErrChk(DAQmxReadAnalogF64(taskHandleAI, BUFFER_SIZE, 10.0, DAQmx_Val_GroupByScanNumber, data, BUFFER_SIZE, &read, NULL)); // N, N if( read > 0 ) { totalRead += read; // increment totalRead nSweepsRecorded++; // increment nSweepsRecorded printf("Sweep %d: Acquired %d samples, total %d samples.\n", nSweepsRecorded, read, totalRead); if (nSweepsRecorded == N_SWEEPS_TARGET) // If N_SWEEPS_TARGET has been obtained, stop AO and AI tasks. { StopTaskAOAI(); printf("%d sweeps have been obtained. Press Enter to exit.\n", N_SWEEPS_TARGET); } } Error: if( DAQmxFailed(error) ) { DAQmxGetExtendedErrorInfo(errBuff, 2048); StopTaskAOAI(); printf("DAQmx Error: %s\n", errBuff); /* NOTE: If an error occurs here, the user will see the error message and will respond accordingly*/ } return 0; } // A function to stop and clear AO and AI tasks void StopTaskAOAI() { /* --- stop AI and AO tasks --- */ DAQmxStopTask(taskHandleAO); DAQmxStopTask(taskHandleAI); /* --- clear AI and AO tasks --- */ DAQmxClearTask(taskHandleAO); DAQmxClearTask(taskHandleAI); /* --- reset AI and AO task handles --- */ taskHandleAO = 0; taskHandleAI = 0; }