Digital I/O

cancel
Showing results for 
Search instead for 
Did you mean: 

How does one read digital inputs only when the inputs change?

I am using LabWindows/CVI 2010 with a USB-6343.  I have ten digital inputs connected to port 0 lines 12 - 21.  I would like to read these digital inputs when any of them have changed and notify a thread the inputs have changed.  I have been trying to use DAQmxCfgChangeDetectionTiming with a DAQmxRegisterSignalEvent that registers a change detection callback.  From the callback, I call DAQmxReadDigitalLines to read the inputs and then post a message to the thread.

 

I just want to read the inputs at the time of the change.  I have tried using FiniteSamps and ContSamps.  When I read the samples, the DAQmxReadDigitalLines often times out without acquiring all of the samples.  I have also tried DAQmxRegisterEveryNSamplesEvent, without the callback for the change detection event, but the every_n_samples callback doesn't seem to be called every time the inputs change.

 

Here is my code with error handling removed to shorten the post so it may not compile.  NUMBER_OF_INPUTS is 10 and NUMBER_OF_SAMPLES_PER_INPUT is 5.

 

DAQmxCreateTask("", &inputs_task_handle) == 0);
DAQmxCreateDIChan(inputs_task_handle, input_lines, input_names, DAQmx_Val_ChanPerLine);

for (i = 0U; i < NUMBER_OF_INPUTS); ++i) {

    DAQmxSetChanAttribute(inputs_task_handle, input_config_table[i].name, DAQmx_DI_InvertLines, 0);

    DAQmxSetDIDigFltrEnable(inputs_task_handle, input_config_table[i].name, FALSE);

    DAQmxSetDIDigFltrMinPulseWidth(inputs_task_handle, input_config_table[i].name, 0.00512);

    DAQmxSetDIDigFltrEnable(inputs_task_handle, input_config_table[i].name, TRUE);
}

DAQmxCfgChangeDetectionTiming(inputs_task_handle, input_lines, input_lines, DAQmx_Val_FiniteSamps, NUMBER_OF_SAMPLES_PER_INPUT);
DAQmxRegisterEveryNSamplesEvent(inputs_task_handle, DAQmx_Val_Acquired_Into_Buffer, NUMBER_OF_SAMPLES_PER_INPUT, 0, input_number_of_samples_callback, NULL) ;

//DAQmxRegisterSignalEvent(inputs_task_handle, DAQmx_Val_ChangeDetectionEvent, 0U, input_change_callback, NULL);

DAQmxSetRefTrigPretrigSamples(inputs_task_handle, NUMBER_OF_SAMPLES_PER_INPUT - 1);

DAQmxStartTask(inputs_task_handle);

bool Perform_Read_Of_BRU_Discrete_Inputs(uInt8 * const d) //lint !e960
{

    bool ret = true;
    int32 samples_per_chan_read;
    int32 bytes_per_sample;
    uInt32 available_samples;

 

    if (0 == inputs_task_handle) {
        ret = false;
    } else {
        (void) DAQmxGetReadAvailSampPerChan(inputs_task_handle, &available_samples);

 

        if (DAQmxReadDigitalLines(inputs_task_handle, NUMBER_OF_SAMPLES_PER_INPUT, 1.0, DAQmx_Val_GroupByScanNumber,
d, NUMBER_OF_SAMPLES_PER_INPUT * NUMBER_OF_INPUTS, &samples_per_chan_read, &bytes_per_sample, NULL) < 0) {
            ret = (samples_per_chan_read == NUMBER_OF_SAMPLES_PER_INPUT) ? true : false;
        }
    }

 

    return ret;
}

 

#if 0
static int32 CVICALLBACK input_change_callback(TaskHandle taskHandle, int32 signalID, void *callbackData) {
    uInt8 temp_digital_inputs[NUMBER_OF_SAMPLES_PER_INPUT][NUMBER_OF_INPUTS];

 

    if (Perform_Read_Of_BRU_Discrete_Inputs((uInt8 *) temp_digital_inputs)) {
        memcpy(digital_inputs, temp_digital_inputs[NUMBER_OF_SAMPLES_PER_INPUT - 1], NUMBER_OF_INPUTS);
        assert(BRU_Discrete_Input_Has_Changed());
    }

   

    return 0;
} //lint !e715 !e818
#endif

static int32 CVICALLBACK input_number_of_samples_callback(TaskHandle taskHandle, int32 event_type, uInt32 num_of_samples, void *callbackData) {
    uInt8 temp_digital_inputs[NUMBER_OF_SAMPLES_PER_INPUT][NUMBER_OF_INPUTS];

 

    if (Perform_Read_Of_BRU_Discrete_Inputs((uInt8 *) temp_digital_inputs)) {
        memcpy(digital_inputs, temp_digital_inputs[NUMBER_OF_SAMPLES_PER_INPUT - 1], NUMBER_OF_INPUTS);
        assert(BRU_Discrete_Input_Has_Changed());
    }

 

    return 0;
} //lint !e715 !e818

 

0 Kudos
Message 1 of 2
(4,378 Views)

If you just want to read the current state of the lines when one changes, you could configure non-buffered change detection (call DAQmxCfgInputBuffer with 0 samples per channel after you configure change detection timing but before you start your task).

 

Use the change detection event and read just a single sample per callback.

 

 

 

If the software can't keep up though, you wouldn't have a buffer of all of the previous transitions.  If this is something you need, you'll need to keep using the buffered change detection.  Either event could work, but not without caveats:

 

1.  The Every N Samples event is generated when the requested number of samples are transferred off of the device to the host PC buffer.  It is difficult to control exactly when this transfer happens (though there are channel properties you can try setting--I can't experiment since I don't have the same hardware handy).  You're not getting the events currently because it is likely that the data is sitting in the device FIFO until the transfer is initiated.

 

2.  The change detection event is generated from the hardware signal.  You have to read the data to get the data transfer to happen though, but until you read the data you don't know how many samples there will be (if the line is changing rapidly you might get several samples per event for example).

 

 

 

For the record I find the buffering pretty awkward on USB devices when dealing with callbacks (e.g. if you are using EveryNSamples callback shouldn't the data transfer be initiated every time N samples are acquired?).  I haven't played with it in a while and it's possible the Data Transfer and Memory Channel Properties can be used to deal with the buffering issues.

 

 

Best Regards,

John Passiak
0 Kudos
Message 2 of 2
(4,365 Views)