// // Programmer: Craig Stuart Sapp // Creation Date: Sun Oct 4 21:47:33 PDT 1998 // Last Modified: Wed Oct 7 17:15:12 PDT 1998 // Filename: balance.c // Based on: scope.c // Syntax: C; National Instruments LabWindows/CVI 4.0 // // Description: Input data comes from measured A/D voltages from an input // sensor connected to the National Instrument Digital AQuisition // Card (NIDAQ). The goal of this task is to "balance" a stick without // dropping it. The input represents your hand upon which the bottom of // the stick is resting. The output represents the position // of the top of the stick which you are trying to keep balanced above // your hand. You can control the sticks length -- a long stick // is easier to balance than a shorter stick. // // This program also illustrates the use of the DAQ double buffered // analog input functions for acquiring voltage data continuously. // // Control enumerations for items on the program's two windows: // // MAIN = window: main // MAIN_INPUTMIN = box: input's minimum value (inputMin) // MAIN_INPUTMAX = box: input's maximum value (inputMax) // MAIN_MARGIN = box: boundary limiting the range of the output (margin) // MAIN_INPUT = slider: displaying input sensor values (stickBottom) // MAIN_OUTPUT = slider: displaying output values (stickTop) // MAIN_STICKLENGTH = slider: for controlling stick length // MAIN_TOGGLEBUTTON = toggle: select manual or automatic stick length control // MAIN_CONFIG = button: to open configuration panel // MAIN_START = button: to start aquiring data from NIDAQ card // MAIN_STOP = button: to stop aquiring data from NIDAQ card // MAIN_QUIT = button: to quit program // // CONFIG = window: configure // CONFIG_CHANNEL = box: for setting variable aiChannel // CONFIG_TRIGGER = toggle: for setting variable aiTrigger // CONFIG_DAQRATE = box: for setting variable sampleRate // CONFIG_DEVICE = box: for setting variable device // #include #include #include #include #include #include "balance.h" /* LabWindows/CVI automatically generated include file */ #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #define FRAMECOUNT (1024) /* number of samples transfered each frame */ // global variables: double inputMin = 0.0; // minimum voltage of the input sensor double inputMax = 5.0; // maximum voltage of the input sensor double stickTop = 2.5; // output value (simulating top of stick) double stickBottom = 2.5; // input value (simulating bottom of stick) double stickLength = 10.0; // length of stick (inv. difficulty index) double margin = 1.0; // prevent output from exceeding input range unsigned long sampleCount = FRAMECOUNT; double averageInput; // average value of transfered frame int device = 1; // National Instruments input device int aiChannel = 0; // analog input channel int aiTrigger; // analog input sample trigger location ??? double sampleRate = 20000; // sampling rate in Hertz short timebase; // ??? unsigned short interval; // ??? int mainHandle; // the window number for the main window. int configHandle; // the window number for the configure window. short frameTransferQ = 0; // boolean for data frame coming from NI card short daqStopped; // ??? int startQ = 0; // boolean for when data is being input. double gain = 1.0; // gain to scale the input voltages by. int err; // error flag double inputData[FRAMECOUNT]; // array into which input data arrives in prog short buffer[FRAMECOUNT]; // ??? short halfbuffer[FRAMECOUNT/2]; // ??? int lengthType = 0; // 0=manual adjustment of length, 1=automatic /////////////////////////////////////////////////////////////////////////// int main(void) { InstallMainCallback(runLoop, 0, 1); SetIdleEventRate(1); mainHandle = LoadPanel(0, "balance.uir", MAIN); configHandle = LoadPanel(0, "balance.uir", CONFIG); // set the default min, max and margin for the user interface. inputMin = 0.0; inputMax = 5.0; margin = 0.5; SetCtrlVal(mainHandle, MAIN_INPUTMIN, inputMin); SetCtrlVal(mainHandle, MAIN_INPUTMAX, inputMax); SetCtrlVal(mainHandle, MAIN_MARGIN, margin); // set the input and output ranges to their default values SetCtrlAttribute(mainHandle, MAIN_INPUT, ATTR_MIN_VALUE, inputMin + margin); SetCtrlAttribute(mainHandle, MAIN_OUTPUT, ATTR_MIN_VALUE, inputMin + margin); SetCtrlAttribute(mainHandle, MAIN_INPUT, ATTR_MAX_VALUE, inputMax - margin); SetCtrlAttribute(mainHandle, MAIN_OUTPUT, ATTR_MAX_VALUE, inputMax - margin); // ignore out-of-range value display for input/output SetCtrlAttribute(mainHandle, MAIN_INPUT, ATTR_CHECK_RANGE, VAL_IGNORE); SetCtrlAttribute(mainHandle, MAIN_OUTPUT, ATTR_CHECK_RANGE, VAL_IGNORE); stickTop = (inputMin + inputMax) / 2.0; // put top of stick in middle DisplayPanel(mainHandle); RunUserInterface(); // event loop return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // runLoop -- the main callback function. This function is useful // whenever there is some sample data to transfer from the NI board // to this program // int runLoop(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int i; switch (event) { case EVENT_IDLE: if (startQ == TRUE) { // Check to see if a half-buffer is ready to be transfered DAQ_DB_HalfReady(device, &frameTransferQ, &daqStopped); // Call function to transfer and plot data if buffer is ready if (frameTransferQ) { err = DAQ_DB_Transfer(device, halfbuffer, &sampleCount, &daqStopped); if (err < 0) break; DAQ_VScale(device, aiChannel, gain, 1.0, 0.0, sampleCount, halfbuffer, inputData); averageInput = 0.0; for (i=0; i inputMax - margin) { stickTop = inputMax - margin; } // set the slider display of the stick top: SetCtrlVal(mainHandle, MAIN_OUTPUT, stickTop); // if doing automatic stick length, adjust the stick length if (lengthType == 1) { // // put the length adjusting code here for automatic stick-length control. // if (stickLength < 0.0) { stickLength = 0.0; } else if (stickLength > 10.0) { stickLength = 10.0; } SetCtrlVal(mainHandle, MAIN_STICKLENGTH, stickLength); } } // end of if (startQ == TRUE) break; } // end of switch (event) return 0; } ////////////////////////////// // // displayConfig -- callback function for displaying the configuration // panel // int displayConfig(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: DisplayPanel(configHandle); break; } return 0; } ////////////////////////////// // // configureDAQ -- callback function which will configure the NI DAQ card. // int configureDAQ(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(configHandle, CONFIG_CHANNEL, &aiChannel); GetCtrlVal(configHandle, CONFIG_TRIGGER, &aiTrigger); GetCtrlVal(configHandle, CONFIG_DAQRATE, &sampleRate); GetCtrlVal(configHandle, CONFIG_DEVICE, &device); // close the configuration panel: HidePanel(configHandle); break; } return 0; } ////////////////////////////// // // startDAQ -- callback function which will start the NI DAQ card. // int startDAQ(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: SetCtrlAttribute(mainHandle, MAIN_CONFIG, ATTR_DIMMED, 1); // set the DAQ device number and trigger info: DAQ_Config(device, aiTrigger, 0); DAQ_DB_Config(device, TRUE); DAQ_Rate(sampleRate, 0, &timebase, &interval); DAQ_Start(device, aiChannel, gain, buffer, sampleCount, timebase, interval); SetInputMode(mainHandle, MAIN_START, 0); SetInputMode(mainHandle, MAIN_STOP, 1); startQ = TRUE; break; } return 0; } ////////////////////////////// // // stopDAQ -- a callback function for stopping input from the NI DAQ card // int stopDAQ(int panel, int control, int event, void* callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: if (startQ == TRUE) { SetCtrlAttribute(mainHandle, MAIN_CONFIG, ATTR_DIMMED, 0); DAQ_Clear(device); DAQ_DB_Config(device, FALSE); SetInputMode(mainHandle, MAIN_START, 1); SetInputMode(mainHandle, MAIN_STOP, 0); startQ = FALSE; } break; } return 0; } ////////////////////////////// // // setStickLength -- this callback function is called whenever the stick length // in the main window is changed so that the stickLength global variable // can be updated // int setStickLength(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(mainHandle, MAIN_STICKLENGTH, &stickLength); break; } return 0; } ////////////////////////////// // // setInputMin -- this callback function is called whenever the input min // in the main window is changed so that the inputMin global variable can // be updated. // int setInputMin(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(mainHandle, MAIN_INPUTMIN, &inputMin); // reset the maximum value of the input and output SetCtrlAttribute(mainHandle, MAIN_INPUT, ATTR_MIN_VALUE, inputMin + margin); SetCtrlAttribute(mainHandle, MAIN_OUTPUT, ATTR_MIN_VALUE, inputMin + margin); break; } return 0; } ////////////////////////////// // // setInputMax -- this callback function is called whenever the input max // in the main window is changed so that the inputMax global variable // can be updated. // int setInputMax(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(mainHandle, MAIN_INPUTMAX, &inputMax); // reset the maximum value of the input and output SetCtrlAttribute(mainHandle, MAIN_INPUT, ATTR_MAX_VALUE, inputMax - margin); SetCtrlAttribute(mainHandle, MAIN_OUTPUT, ATTR_MAX_VALUE, inputMax - margin); break; } return 0; } ////////////////////////////// // // setMargin -- this callback function is called whenever the margin // in the main window is changed so that the margin global variable // can be updated. // int setMargin(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(mainHandle, MAIN_MARGIN, &margin); break; } return 0; } ////////////////////////////// // // setLengthType -- toggles between manual and automatic stick length control // by setting the global variable lengthType. 0=manual, 1=auto. // int setLengthType(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(mainHandle, MAIN_TOGGLEBUTTON, &lengthType); break; } return 0; } ////////////////////////////// // // Shutdown -- what to do when stopping // int Shutdown(int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: if (startQ == TRUE) { // if DAQ card is running DAQ_Clear(device); DAQ_DB_Config(device, FALSE); // when quit button is selected startQ = FALSE; } QuitUserInterface(0); break; } return 0; }