LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Use output of one Event Case as input to another Case?

Solved!
Go to solution

To control a little I/O device that we've made, I need to send an 8-bit data value and a Device ID string to our DLL:

  1. Init the DLL, which returns the number of our devices it's found.
  2. Loop thru NumDevices to return their IDs.
    1. The IDs are numbers from 0 - 7, but expressed as strings.
    2. Display all returned ID strings in table.
  3. Select a Device by ID using a control.
    1. Select from the array by index; display as string.
    2. Call ConfigurePortsEx() using the Device ID string and "0", to enable the ports as Output ports.
  4. Call WriteBytePortA(), using the Device ID string and the data byte to be written
  5. Do steps 3-4 whenever the controls change either the Device ID or the byte.

I have this working by putting both the Configure and the Write call library functions in a big While loop, and it works. But I gather that that's inefficient, since it's constantly calling the DLL regardless of whether the values are changing:

 USB_IO_1-Port_While.png

 

I tried replacing the While with an Event, with the Device ID string updated when Select Device changes value, and the Writing of bytes triggered by the Data to Write control, but I can't figure out how to get the output of the array selector in one Event Case wired to the input of the Call Library function in a different Event Case:

 

USB_IO_1-Port_Event_Select.pngUSB_IO_1-Port_Event_Write.png

 

I tried putting the indicator outside the Event structure, and I tried wiring the output of the Array Index to the Event Structure as a tunnel, but in both cases I can't wire those back into the Call Library function.

 

Thanks!

 

p.s. the VIs call a simple DLL that loads a Microchip USB driver, but I don't think any of that is relevant. The device also has Ports A - E that can be configured and written to, but that's also irrelevant.

0 Kudos
Message 1 of 12
(5,157 Views)

To pass data between loop iterations you can use shift registers. For the events where the data doesn't change, just wire it straight through.

0 Kudos
Message 2 of 12
(5,154 Views)

I would tell you to use two parallel loops, but I'm guessing you are a LabVIEW beginner as you insist on using Frame Sequences when they are absolutely not needed (and, indeed, are rarely needed) -- let LabVIEW's Principle of Data Flow handle the sequential ordering of the frames for you, resulting in a much more compact (and generally more readable) Block Diagram.

 

Here's what I think you want to do:

  • Once, get a list of the Devices (the first two frames).  Bring this List into a WhilIne Loop.
  • The While Loop does the Device Selection, Port A Config, and Write to Port A.  But you don't want to do all of these on every iteration of the While Loop.  You could use an Event structure to tell you when something changes, but there's another way -- have three Shift Registers, one to hold the Device Selection, one for Port A Config, and one for data to Write to Port A (it's not clear if you only want to write new data to Port A, or if it's OK to write the same value over and over, as fast as possible ...).  Here's how this works:
    • Initialize the Shift Register (by writing to it from the Outside) with a value that is not in the three Controls.
    • Inside the Loop, ask "Does the Shift Register for Device Selection match the Device Selection Control?  If yes, do nothing.  If No, save the Control's value in the Shift Register and use it to Select the Device.
    • Do the same with the other two Controls.
    • Note you now have three Cases inside the While that basically check if the Control's Value has Changed, and "does something" (and remembers the value for next time in the Shift Register).
  • You might consider putting a Wait function with a value of 10-100 msec as you don't need this loop running "as fast as it can" and using up all your CPU cycles.

Bob Schor

0 Kudos
Message 3 of 12
(5,112 Views)

Thanks, but this isn't a loop iteration; it's two different event cases. I can't wire one to the other, because they're never visible at the same time.

 

I want to wire the outputs of the Index Array to the input of the Call Library Function, just as I've in the big While loop example. 

0 Kudos
Message 4 of 12
(5,095 Views)

Ah, I realized I omitted some important stuff from my OP:

 

I want to write the Config only when the Select Device (and therefore the Selected ID) changes.

 

I want to write the Port A data only when the Port A data changes. This will change a lot more frequently than Select Device, e.g. the user will select a device, then fiddle with the control by incrementing up/down a few times, or by typing a value, and then they might change the Select Device and do the same with the other device.

 

I definitely don't want to hammer the device with DLL calls when nothing changes.

 

Yes, I'm pretty new to LabVIEW, and I need to read up on data flow, but in the meantime, is there a way to do what I am asking now, which is to take the result of one Event case and use it as an input in a different Event case, without constantly looping? 

 

Thanks!

0 Kudos
Message 5 of 12
(5,091 Views)

@TheWaterbug wrote:

 

Yes, I'm pretty new to LabVIEW, and I need to read up on data flow, but in the meantime, is there a way to do what I am asking now, which is to take the result of one Event case and use it as an input in a different Event case, without constantly looping? 


Yes. Use the Shift Registers as mentioned by gregoryj. You'll need to put your Event Structure in a While loop (as you already have) but if an Event doesn't occur, the loop won't iterate until one does.

 

You also need (basically) to place the Stop control in its own Value Change event, and wire the output out of the edge of the Event Structure to the Stop terminal (or connect a true constant in that case). You can use "Use Default if Unwired" for the tunnel for the other cases.

 

Place the device ID (string) on a shift register. Place the Port A Config inside the Port A Config:Value Change event. Typically you want the control inside the Value Change event, because otherwise the value will be old (so move the Device control (numeric) inside the Event Structure for the "Select Device:Value Change" event). Take the output of the Shift Register as the input for the two library calls.

 

Edit: I added an example VI saved with 2017. I didn't add snippets because I didn't want to add one per case, but it looks like the printed output will be the same. I've placed them as images below. Apologies about the spacing, which may be better or worse on different devices.

 

exampleEventStructured.jpgexampleEventStructured1.jpgexampleEventStructured2.jpgexampleEventStructurep.jpg


GCentral
0 Kudos
Message 6 of 12
(5,081 Views)

Thanks for putting so much work into this! I'm still trying to figure out how it works. I see that you've put an Index Array into two places--outside the While Loop and inside one event, and they're both "controlled" by two items called Select Device. One of them is a classic control, inside the Event case, and I can't figure out what the other one (outside the While loop) is.

 

If I double click either one of them, it highlights the same control. 

0 Kudos
Message 7 of 12
(5,052 Views)
Solution
Accepted by topic author TheWaterbug

The control outside of the loop is a Local Variable. It can be used to either read or write the value of an existing Control or Indicator. However, you should be careful when using them because they can lead to poor programming and race conditions. When you double click, it demonstrates that they both refer to the same control.

 

In this case, it's used to allow me to place the terminal inside the event structure, to make sure it's read properly (i.e., after the value change and not before), but still know what the value is when the VI starts (which is when the local variable will be read).

The Index Array outside of the While Loop sets the initial, starting value of the Shift Register.

If you don't have an initial value connected to the outside of the left side shift register (i.e. where the output of the Index Array, outside of the loop is connected) then the starting value will be whatever it was the last time the VI ran. It reverts to the default only when you allow the VI to leave memory. More detail can be found here.

If you don't place that in that location, then it would be possible that you had a different value on the Shift Register when you started to what was the value of the Control, which probably isn't what you want.


GCentral
Message 8 of 12
(5,044 Views)

Ah, the Local Variable was the solution I'd been looking for. That's what allows me to get the Selected ID from one Case to the other Case.

 

I'm going to work on the data flow now, but at least everything's working.

 

Thanks!

0 Kudos
Message 9 of 12
(5,018 Views)

You DON'T NEED and shouldn't use a Local Variable.  You just need to think where you need what.  Here's the same Event Loop, with the "real" variable being used outside the Loop to initialize things, and when its value is changed, the Event Structure has the "New Value" as part of its structure, so you use that.  Like this ...

No Local Var.png

No Race Conditions, no wondering "Where did that come from", no finger-waggling from People Who Know Better (I'm not counting myself, of course) ...

 

Bob Schor

Message 10 of 12
(5,012 Views)