LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Change Analog Outputs Dynamically

I am trying to solve a problem that I'm having. I am using daqmx as an analog output and feeding it a sine waveform that is built in the vi, with with the frequency and amplitude values as numeric controls.

 

In my vi I am doing some calculations and I want to feedback lower or higher values to these. I setup a event structure to try and detect when the value is changed, and then either restarting the daqmx or keeping it running while using the new values.

 

Is there a way to change what the daq outputs dynamically (while the vi is running)? And how can I do it with the least delay?

 

Thanks for any help someone can offer.

Arthur J.

 

Im using labview 8.2 but I have access to labview9

The vi is slightly complicated but I have attached it as a reference. The upper loop is generating and outputting the waveform.

0 Kudos
Message 1 of 17
(4,924 Views)

I just wanted to add one thing. Is there a difference programatically between reinitializing a daq task, and physically stoping the vi and restarting it?

0 Kudos
Message 2 of 17
(4,916 Views)

Don't physically stop the vi with the Abort button.  This leaves references open and can cause other problems on subsequent runs.   You can change the output dynamically with the right code.  Always let the program come to a natural end so that it can close the DAQmx task and such.

 

You must use a loop.  Inside the loop you create the waveform you want to generate.  You can use a case statement to select which waveform or to change the values.  After the waveform formation, and still within the loop, you write the data to the DAQ buffer by using DAQmx Write.  If you DAQ is setup for auto start, the waveform should be generated by the DAQ.  If not auto start, you need to use the DAQmx Start Task function to start the AO.  End of loop.  Use a stop button to stop the loop.  Be sure to put a small delay, Wait(ms), inside the loop to prevent using 100% CPU time.  Also use shift registers for the error wires and the DAQmx task wires to propogate the information from one loop iteration to the next.  Here is an example:

 

21401iFAF0D8E867D3D1C3

 

The above is just an example and is not complete.  The case structure is not finished, there is nothing in the other case.  The For Loop has nothing wired to N.  You could use a While Loop with a stop button instead.

 

- tbob

Inventor of the WORM Global
0 Kudos
Message 3 of 17
(4,908 Views)

Thanks tbob, that sounds pretty good. In the vi I have posted above, I have the components of the waveform that is being generated changed from within the program. I thought to use an event loop to detect when those values are being changed and updating what the write daqmx is doing.

But, when I run it, the values on the front panel indicators are changing, but the hardware receiving the daqmx write does not seem to reflect that change. 

 

In the beginning I wasn't sure what was happening. So I tried to stop the program. Then restart without changing any of the values for the waveform inputs. When I restart I see the change in value reflected. In my program's case this change is the amplification, therefore seeing a larger waveform amplitude.

 

From your sample example, do you think the event structure should work? Or should I try another approach. 

 

Thanks for your help,

Arthur J.

0 Kudos
Message 4 of 17
(4,894 Views)

The reason your event structure doesn't respond to value changes for Frequency, amplitude, etc is because you are writing to the Value property node.  This changes the value but it does not cause an event.  You should use the Value (Signaling) property node instead.  This will cause an event to fire and make your program work.  So everywhere that you want to change a value AND fire an event, use Value (Signaling).

 

The event structure is waiting for a user to physically change a value.  When the program does it, the event does not fire.  That is why NI came up with the Value(Signaling) property node.  To cause the event to fire programatically.

 

- tbob

Inventor of the WORM Global
Message 5 of 17
(4,876 Views)

That did the trick. What happened was that I had set one of the parameters to value signaling but not the others, so the event wasn't triggering all the times it needed to. Thanks to your help and everyone on the board I have a very decent draft of my vi.

 

There was just two kinks that I have been trying to work out today. I think they are logical conflicts within the program, I'm just not sure how/where to fix them.

1. The Start button on for the top (waveform generation loop) never works the first time I run the program. But If I run the program, then abort, then start the program again the button works like a charm.

2. If while running the program I stop the waveform generating loop (clicking the stop botton on the top of the block diagram), then stop button on the bottom loop doesn't react. But if I do the opposite; i.e. press the lower stop botton, then the upper, they both function normally.

 

Tbob mentioned about letting the program finish by itself so as to reduce possiblity of future issues on runs, but the program only functions properly if I run then abort first, lol. Would anyone have some suggestions on where to look or what could be done?

 

Thanks again for the help,

Arthur J.

 

I've attached my updated vi below.

0 Kudos
Message 6 of 17
(4,844 Views)

I figured out the kink number two that I was having. When I turned off the waveform generator, the feedback was trying to match amplitudes and using all of the processor to keep up. I just changed by logic control a little and added that the waveform generator must be true in order for the feedback loop to function.

But my first problem about the start button not working has me at a loss. Even when I highlight excecution its unclear to me where the problem is.

 

And what about being able to start, stop, and restart within the program with out exiting, which mine doesn't do right now. Is the best way just to add a extra loop outside of all the information for each part of the vi?

 

Thanks.

Arthur J.

0 Kudos
Message 7 of 17
(4,834 Views)

Not sure why you would have to abort to get the start button to work.  But I did find some other issues.

 

Your top loop has a False constant wired to the stop sign.  This loop will run forever and the VI will have to be stopped by using the abort button.  This is not good.  Use just one stop button and create local variables for all loops.

 

In the top loop,you should put the WaveStart control inside the event case for WaveStart.  This way the button gets read at the time the event happens.  This is just good practice.  If the button was a latch mechanical action, it would be read and would unlatch here.  By being outside all loops, it gets read once, at the beginning, and would never unlatch.  Since your switch action is not a latch type, you are safe.  But still it is a good habit to get into, so put the control in the event case.

 

You are using Mouse Down for all your button events.  Instead you should be using Value Change.  In your case, it might not make a difference, but it is better to use Value Change.  Just another one of those good practices things.

 

You have several event structures.  It is best to have just one to handle all events.  Your code can be condensed, to have the top loop included into the bottom loop.  This would take some doing, so I would probably leave this alone for now.  But in the future, try to keep just one event structure to handle everything.  In your case, a state machine in which one of the states would be the event structure, would be better architecture.  Your event state would be waiting for events, then when one happens, it would kick off some action, then return to the event case to wait for more commands.  The size of your block diagram could possibly fit on one screen, making it much easier to follow.

 

What happens if you enable execution highlighting (light bulb)?  Where does it get stuck?  I would bet that the top loop goes to the true case and then sits there in an endless loop.  You don't have any value for the Timeout event (hour glass).  In fact, none of your loops have anything wired to the hour glass.  You should insert a value here for all event structures so that the timeout fires occasionally.  When the WaveStart button is pressed, the event finally fires and the true case ends.  Now the False case executes.  If has an event structure also.  It waits for the WaveStart to be pressed again.  Inside the WaveStart case, you write a True to the WaitStart property node.  You can eliminate this code because the user has pressed the button, which sets it to True, which also fires the event.  By having this property node here, the event is fired when the user clicks the button, then the Value(sgnl) fires the event again, with causes another Value(sgnl), which fires the event again, and so on.  It never ends.  Another thing.  I just noticed that the WaveStart event is a "Mouse Down?".  This is a filter event.  Don't use this.  If just looks for the mouse down and may not process it fully.  Use the Value Change instead.

 

Maybe you should rewrite your code to eliminate the top loop and put its code into the bottom somewhere.  Your current architecture is not very good and it is what is causing you problems.  It is very hard to fix when the architecture is convoluted.

 

- tbob

Inventor of the WORM Global
0 Kudos
Message 8 of 17
(4,820 Views)

I found why you have to abort.  In the top loop True case, you have one event structure with a WaveStart Mouse Down event.  In the top loop False case, you have a WaveStart Mouse Down? event.  Those two conflict, even though they have not executed yet.  The compiler gets confused because of two separate instances of a mouse down event on the same control.  When you change the Mouse Down? to a Value Change, then it works fine.

 

This is what I was saying about having multiple event structures.  Re-organize your vi and use one event structure for all.  Get rid of the top loop, and put your code in the bottom loop instead.  Use an event structure (in producer loop) to send all commands and cause all actions.

 

Another thing that is bad is that in the top loop you had "Use default if unwired" for the error wire and the DAQmx task wire.  Very bad.  The default task is a null task.  how can a null task be closed or stopped?  Don't do this.  Wire the task from one side to the other.  Also, you should use a shift register for task wires and especially for error wires.  If an error occurs in one loop iteration, it will be lost in the next iteration because the input from the left does not have an error.  So you lose any errors created in any of the iterations.

 

Re write your vi to eliminate the top loop.  Use small delays in each loop.  Wire a value to the timeout of the event structure.  Don't use default if unwired, except for the stop boolean to stop the loop.  Use one stop button to stop everything.  Use only one event structure.  You've got a lot of work to do, and a lot to learn.

 

- tbob

Inventor of the WORM Global
Message 9 of 17
(4,806 Views)

Thank you very much for all the help and criticism. Theres a lot of details that I wasn't aware of, and its helped me learn quite a bit. 

I've implemented the things you pointed out, except for condensing into only two loops. I'm still working on that one. Its seems at times that in only two loops the several outputs and inputs may occur simulatneously and conflict with each other. But I'ma give it a shot.

 

Thanks again

Arthur J.

 

 

 

 

0 Kudos
Message 10 of 17
(4,761 Views)