LAST PAGE  BACK TO INDEX  NEXT PAGE

[17.0] Some Worked Examples (1)

[17.0] Some Worked Examples (1)

v5.0 / 1 of 23 / 01 sep 99 / gvg

* Just what it says!


[17.1] A SIMPLE TEST EXAMPLE
[17.2] FREQUENCY RESPONSE
[17.3] TAKING STATISTICS FROM SPECTRA
[17.4] INSTRUMENT FINDER PROGRAM
[17.5] ALTERNATING TRACE DISPLAYS
[17.6] HANDLING TOGGLE BUTTONS

 BACK TO INDEX

[17.1] A SIMPLE TEST EXAMPLE

* A user called with a problem in running a simple voltage test using VEE and a 34401 DMM. She was running into an obscure problem, and rather than try to debug it and figure out what was going on I suggested that she rethink how she was running the test. I came up with a clean and simple example to suggest alternatives.

In this example, the test checks to see if a voltage input is within 0.5 volts of a 5 VDC or 10 VDC spec, and announces if the test passes or fails -- both in the VEE program and on the display of the 34401. The test runs in a loop, with each test initiated by the user pressing on a button in the VEE program.

The overall block diagram of the program is as follows (source is available in the file xtinytst.vee):


                 +-----------------------+
                 |    Confirm Device     |  The first DIO resets the DMM,
    +-------+    +-----------------------+  checks the DMM's ID string, and
    | DIO 1 +--->|                       |  displays a prompt on the DMM.
    +---+---+    +-----------------------+
        |
    +---+---+
    | Until |
    | Break +-----+
    +-------+     |
                  |
        +---------+                      
        |                               
        | OK button to run test.         
  +-----+-----+                    +-------+ OK button to quit tests.
  | Run Test  +--+                 | Quit  +--+
  +-----------+  |                 +-------+  |
                 |                            |
                 |                        +---+---+
                 |                        | Stop  |
                 |                        +-------+
                 |          +---------+       
                 |          |  Value  |
             +---+---+      +---------+  The second DIO runs the 
             | DIO 2 +--+-->|         |  test and gets the results.
             +-------+  |   +---------+
                        |
       +----------------+   +---------+
       |                    | Results |
       |   +---------+      +---------+  The formula determines if
       +-->| Formula +--+-->|         |  the test passes or fails.
           +---------+  |   +---------+
                        |
       +----------------+
       |
       |   +----------------------+
       |   |     If/Then/Else     |
       |   +---+-----------+------+
       +-->| A |[A=="FAIL"]| Then +--------------+
           |   |           | Else +--+           |
           +---+-----------+------+  |           |
                                     |           |
                                 +---+---+   +---+---+
                DIO 3 announces  | DIO 3 |   | DIO 4 |  DIO 4 announces
                the test passed. +---+---+   +---+---+  the test failed.
                                     |           |
                                     |           +-->+-----+
                                     |               | JCT +--+
                                     +-------------->+-----+  |
                                                              |
                                   DIO 5 waits 3 seconds  +---+---+
                                   and prompts for the    | DIO 5 |
                                   next test.             +---+---+
                                                              |
                                                          +---+---+
                                     Go back to run test. | Next  |
                                                          +-------+
 
The Panel View of this program is quite simple:

   +------------------------------------------------+
   |                                                |
   |  +--------------------------+                  |
   |  |     Confirm Device       |                  |
   |  +--------------------------+                  |
   |  |                          |                  |
   |  +--------------------------+                  |
   |                                                |
   |  +----------+  +------------+  +------------+  |
   |  | Run Test |  |   Value    |  |  Results   |  |
   |  +----------+  +------------+  +------------+  |
   |                |            |  |            |  |
   |                +------------+  +------------+  |
   |                                                |
   |  +----------+                                  |
   |  |   Quit   |                                  |
   |  +----------+                                  |
   +------------------------------------------------+
 
The DIO 1 object -- which clears the device, queries it for its ID, and puts a prompt on it -- contains the transactions:

   EXECUTE CLEAR
   WRITE TEXT "*RST;*CLS" EOL
   WRITE TEXT "*IDN?" EOL
   READ TEXT X STR
   WRITE TEXT "DISP:TEXT \'RUN TEST?\'" EOL
 
The DIO 2 object -- which runs the test -- contains:

   WRITE TEXT "MEAS:VOLT:DC?" EOL
   READ TEXT X REAL
 
The results are tested by the Formula box, which contains a nested triadic operation:

   (abs(5-A)<0.5 ? "PASS5" : (abs(10-A)<0.5 ? "PASSTEN" : "FAIL" ))
 
This returns "PASS5" if the result of the measurement is within half a volt of 5 VDC, returns "PASSTEN" if it is within half a volt of 10 VDC, and returns "FAIL" otherwise.

If the test passes, DIO 3 is executed to display a "PASS!" prompt on the DMM:


   WRITE TEXT "DISP:TEXT \'PASS!\'" EOL
 
If it fails, DIO 4 is exected to display a "FAILED!" prompt on the DMM and cause a beep:

   WRITE TEXT "DISP:TEXT \'FAILED!\'" EOL 
   WRITE TEXT "SYST:BEEP" EOL
 
In either case, DIO 5 waits 3 seconds and prompts for the next test:

   WAIT INTERVAL:3
   WRITE TEXT "DISP:TEXT \'RUN TEST?\'" EOL
 
This scheme is quite flexible and can be modified and extended as needed.

 TOP OF PAGE

[17.2] FREQUENCY RESPONSE

* This example -- see the file xspecanl.vee for source -- simulates the analysis of a band-pass filter. You can select the amplitude of the sweep signal, its start and stop frequencies, and the number of steps, and then view the response curve.

The Panel view is laid out as follow:


   +--------------------------------------------------------+
   |                   Frequency Response                   |
   +--------------------------------------------------------+
   |  +-----------------+ +-----------------+ +-----------+ |
   |  |    Num Steps    | |    Amplitude    | |   Start   | |
   |  |     slider      | |     slider      | | Frequency | |
   |  +-----------------+ +-----------------+ |   slider  | |
   |  +-------------------------------------+ +-----------+ |
   |  |     Magnitude Spectrum display      | +-----------+ |
   |  |                                     | |    Stop   | |
   |  |                                     | | Frequency | |
   |  |                                     | |   slider  | |
   |  +-------------------------------------+ +-----------+ |
   +--------------------------------------------------------+
 
The program itself is laid out as follows:

                                +--------------+
                   +----------->|              |
                   |  +-------->| Concatenator +--+
                   |  |  +----->|              |  |
                   |  |  |  +-->|              |  |
                   |  |  |  |   +--------------+  |
                   |  |  |  |                     |
                   |  |  |  |  +------------------+
                   |  |  |  |  |
                   |  |  |  |  |   +----------+
                   |  |  |  |  |   |  Shift   +-->+--------------+
                   |  |  |  |  +-->| Register |   | If/Then/Else +--+
                   |  |  |  |      |          +-->+-------+------+  |
     +-------+     |  |  |  |      +----------+           |         |
     | Until |     |  |  |  |                         +---+---+     |
     | Break +--+  |  |  |  |                         | Next  |     |
     +-------+  |  |  |  |  |                         +-------+     |
                |  |  |  |  |                                       |
         +------+  |  |  |  |        +------------------------------+
         |         |  |  |  |        |
   +-----+-----+   |  |  |  |        |      +--------------------------
   | Amplitude +---+  |  |  |        |      |       Magnitude Spectrum       
   +-----+-----+   |  |  |  |        |      +-------------+------------
         |         |  |  |  |     +--+--+   |             |
   +-----+-----+   +--|--|--|---->| UUT |   |             |
   | Num Steps +------+--|--|---->|     +-->|[  Trace1  ] |
   +-----+-----+         |  |     |     |   |             |
         |               |  |     |     |   |             |
   +-----+-----+         |  |     +--+--+   |             |
   | Start Freq+---------+  |        |      |             |
   +-----+-----+            |        |      |             |
         |                  |        |      |             |
   +-----+-----+            |        |      |             |
   | Stop Freq +------------+        |      |             +--------
   +-----------+                     |      |
                                     |      |
                                     +----->|[Auto Scale] 
                                            |
                                            +--------------------
 
The four sliders are at left, and feed the UserObject named "UUT" in the middle. This User Object contains the program elements needed to do the computation, and drives the results to the Magnitude Spectrum object.

The Sliders are "free-running" -- that is, they neither have "Wait For Input" nor "Auto-Execute" (a dubious feature best left alone, by the way) set. They are continuously driven by an Until Break object. The four inputs are fed into a Concatenator, which in turn feeds a Shift Register. An If/Then/Else Object checks the two outputs of the Shift Register and strobes the UUT UserObject when the inputs change. This scheme allows the example to display a trace at initial startup and when any of the inputs change.

The UUT UserObject contains a Formula object that generates the sweep using the "ramp" function


   ramp(numElem, from, thru)
 
-- plus another Formula object (fed by two constants) that implements the filter:

   f*(fo/Q)/((f^2-fo^2)+j(f*fo/Q))
 
Note that this generates a complex output. A Multiplier multiplies the filter output to the proper amplitude, and a Build Spectrum object implements the final spectrum:

      +-------------------------------------------------------+
      |                      Build Spectrum                   |
      +----------------+---------------------------+----------+
   -->| Array PComplex |   [ Start/Stop Freq ]     |          |
      +----------------+                           +----------+
   -->|   Start Real   |   [ 814.7 ] [ 376.6 ]     | Spectrum +-->
      +----------------+                           +----------+
   -->|   Stop Real    | Freq. Sampling [ Linear ] |          |
      +----------------+---------------------------+----------+
 
This gives a UserObject with the contents:

  +-------------------------------------------------------------------------+
  |                                  UUT                                    |
  +-------+-------------------------------------------------------------+---+
  |       |          amplitude                                          |   |
  |   A   +---------------------------+                                 |   |
  |       |                           |    start                        |   |
  |       |  +------------------------|---------------+                 |   |
  |       |  |                        |               |  +----------+   |   |
  |       |  |      +------+          +------->+---+  +->|  Build   |   |   |
  |numElem+--|----->|      |   f    +------+   | * +---->| Spectrum +-->| X |
  |       |  +----->| ramp +------->| band +-->+---+  +->|          |   |   |
  |       |  |  +-->|      |  +---->| pass |          |  +----------+   |   |
  |       |  |  |   +------+  | +-->|      |          |                 |   |
  |       |  |  |             | |   +------+          |                 |   |
  |       |  |  |   +------+  | |                     |                 |   |
  | from  +--+  |   |  Q   +--+ | Q=5                 |                 |   |
  |       |     |   +------+    |                     |                 |   |
  |       |     |               |                     |                 |   |
  |       |     |   +------+    |                     |                 |   |
  |       |     |   |  fo  +----+ fo=500              |                 |   |
  |       |     |   +------+                          |                 |   |
  | thru  +-----+-------------- stop -----------------+                 |   |
  |       |                                                             |   |
  +-------+-------------------------------------------------------------+---+
 
The rest of the implementation is a simple matter of wiring the parts and placing them on the display.

 TOP OF PAGE

[17.3] TAKING STATISTICS FROM SPECTRA

* For a more complicated example, consider the problem of a French VEE user. She had a dataset of spectra and wanted to perform an analysis on the set. The idea was to take all the spectra, get a sum of all the data points through the set that were above a particular value at each frequency, and then plot the result as a spectrum.

I wrote an example to accomplish this task (see xspecsts.vee for source). The design of a program necessarily includes the design of the tools for testing, so the first thing I did was to create a dummy dataset of ten spectra using the following code:


  +---------------+
  | For Count: 10 +--+-------------------->+--------------+   +-------------+
  +-------+-------+  |           +-----+   | Build Record +-->| To Data Set |
          |          |        +->| fft +-->+--------------+   +-------------+ 
          |    +-----+-----+  |  +-----+
          |    |   Noise   +--+
          |    | Generator |
          |    +-----------+
	  |
 
Not much to this. It generates ten noise waveforms, converts them to spectra with an FFT, builds the loop count and waveform into a record, and shoves the record into a dataset. The real work is done by the following code:

          |                                  +---------------------------
          |                                  |       Magnitude Spectrum
          +------+                           +-----------+--------------
                 |                           |           |
   +----+   +----+---+-->+---------------+   |           |
   | 90 +-->| Crunch +-->| BuildSpectrum +-->|  Trace1   |
   +----+   +--------+-->+-------+-------+   |           |
                                 |           |           |
                                 +---------->| AutoScale |
                                             |           |
                                             |           |
                                             +-----------+-------
 
The threshold value is stored in the Real constant at left. The program itself consists mainly of two UserFunctions: "Crunch" (which does most of the work) and "BuildSpectrum" (which converts the results into a spectrum format for display).

The "Crunch" UserFunction contains the following objects:


   +-----------------------------------------------------------------------+
   |                               Crunch                                  |
   +-----------+---------------------------------------------------+-------+
   |           |  +-------+                         +----------+   |       |
   |           |  | Start |                         |          |   |       | 
   |           |  +---+---+                         +-->+---+  |   |       |
   |           |      |                                 | + +--+-->| Data  |
   |           |  +---+---+                         +-->+---+      |       |
   |           |  | Until |                         |              |       | 
   |           |  | Break +--+                      |              |       |
   |           |  +-------+  |                      +----------+   |       |
   |           |             |                                 |   |       |
   |           |        +----+-----+                           |   |       |
   |           |        |   From   +------------>+----------+--+   |       |
   | Threshold +----+   | Data Set +--+          | U_MkData +----->| Start |
   |           |    |   +----------+  |      +-->+----------+--+   |       |
   |           |    |                 |      |                 |   |       |
   |           |    |             +---+---+  |                 |   |       |
   |           |    |             | Break |  |                 |   |       |
   |           |    |             +-------+  |                 |   |       |
   |           |    +------------------------+                 +-->| Stop  |
   |           |                                                   |       |
   +-----------+---------------------------------------------------+-------+
 
All "Crunch" does is get each spectrum out of the dataset, run it through "MkData" to convert it into an array of 1s and 0s (where 1 means the array value is above the Threshold and 0 means it is equal to or below it), and then sum the arrays using the "+" object. This UserFunction provides as outputs the final sum of the arrays ("Data") and the start and stop frequencies of the spectra so that the data can be converted back into into a spectrum after processing.

Note that enclosing this circuit in a UserFunction not only makes the program neater, it also allows all the data to be accumulated and then output to the rest of the program.

* The "MkData" UserFunction contained within "Crunch" performs the heart of the processing:


   +---------------------------------------------------------------------+
   |                              MkData                                 |
   +-----------+-------------------------------------------------+-------+
   |           |                                                 |       |
   |           |             +----------+                        |       | 
   |           |         +-->| UnBuild  +--------->+---------+   |       |
   |           |         |   | PComplex |          | Formula +-->| Array |
   |           |         |   +----------+      +-->+---------+   |       |
   |           |         |                     |                 |       |
   |           |         +-----------------+   |                 |       |
   |           |                           |   |                 |       | 
   |           |   +-----+   +----------+  |   |                 |       |
   | Record    +-->| A.B +-->| UnBuild  +--+   |                 |       |
   |           |   +-----+   | Spectrum +------|---------------->| Start |
   |           |             |          +------|-------------+   |       |
   |           |             +----------+      |             |   |       |
   |           |                               |             |   |       |
   | Threshold +-------------------------------+             +-->| Start |
   |           |                                                 |       |
   +-----------+-------------------------------------------------+-------+ 
 
This UserFunction extracts the spectrum from the record (using the Formula box at left that contains the expression "A.B") and tears apart the spectrum to get a linear array of data (plus the start and stop frequencies for reconstruction later). This linear array is shoved through a second Formula box to convert it to 1s and 0s.

This Formula box is the only really subtle thing in this program. It contains the formula:


   signof( clipLower( A, B ) - B )
 
This works as follows:

* Moving back up to the top-level program, the "BuildSpectrum" UserFunction converts the sum array into a spectrum for display:


   +------------------------------------------------------------------+
   |                          BuildSpectrum                           |
   +-------+-----------------------------------------------+----------+
   |       |              +----------+                     |          |
   | Data  +------------->|  Build   |                     |          |
   |       |          +-->| PComplex +--+                  |          |
   |       |   +---+  |   +----------+  |                  |          |
   |       |   | 0 +--+                 |   +----------+   |          |
   |       |   +---+                    +-->|  Build   |   |          |
   | Start +------------------------------->| Spectrum +-->| Spectrum |
   |       |                            +-->|          |   |          |
   |       |                            |   +----------+   |          |
   | Stop  +----------------------------+                  |          |
   |       |                                               |          |
   +-------+-----------------------------------------------+----------+
 
This UserFunction's operation is obvious. The only slightly tricky thing is that the value 0 is used to restore the sum data array to a polar complex format by adding a phase of 0. (There's no reason to need the phase data in this case, but you can't have a spectrum without it.)

* This example makes good use of VEE array-processing capabilities and UserFunctions to perform a sophisticated task with a minimum of objects.

 TOP OF PAGE

[17.4] INSTRUMENT FINDER PROGRAM

* A user was having problems with the VEE Instrument Finder, and as an alternative I came up with a VEE program that did the same thing.

The essential trick is to configure a dummy instrument under VEE -- call it "DummyIO" for short -- and assignive it a short timeout, maybe half a second; then obtain a Direct I/O box, bring out the Address pin, scan through every available address and do a serial poll (SPOLL), and see which ones time out (no device) do not (valid device).

It's not quite that simple, of course, the program has to scan through primary HPIB addresses. If it doesn't find a device at the primary address, it has to scan the "00" secondary base address for that primary address to see if there is a secondary-addressed device there. If there is, it has to scan all the secondary addresses for that base address.

This is particularly tricky because if the program performs an SPOLL using a secondary base address such as:


   70900
 
-- it will find a device with the address 709 or 70900 -- while if you perform an SPOLL on:

   709
 
-- it will only acknowledge a device with the address 709, not one with 70900. This means that the program must screen out all the primary-address devices and then check the remaining addresses to see if they respond secondary-address base address, or it will get a false indication of a secondary-address device.

So the scanning scheme is as follows. First, scan all primary addresses (an asterisk -- "*" -- denotes that an instrument is found):


   700   -> *701   ->  702   ->  703   ->  704   ->  705   ->  706   ->
   707   ->  708   ->  709   ->  710   ->  711   ->  712   -> *713   ->
   714   ->  715   ->  716   ->  717   ->  718   ->  719   ->  720   ->
   721   -> *722   -> *723   ->  724   ->  725   ->  726   ->  727   ->
   728   ->  729   ->  730
 
This done, scan the remaining addresses as secondary base addresses:

   70000 ->            70200 ->  70300 ->  70400 ->  70500 ->  70600 ->
   70700 ->  70800 -> *70900 ->  71000 ->  71100 ->  71200 ->          
   71400 ->  71500 ->  71600 ->  71700 ->  71800 ->  71900 ->  72000 ->
   72100 ->                      72400 ->  72500 ->  72600 ->  72700 ->
   72800 ->  72900 ->  73000
 
Since one secondary base address was found, then all secondary addresses following that base address have to be scanned next:

             70901 ->  70902 ->  70903 ->  70904 ->  70905 ->  70906 ->
   70907 ->  70908 ->  70909 ->  70910 ->  70911 -> *70912 ->  70913 ->
   70914 ->  70915 ->  70916 ->  70917 ->  70918 ->  70919 ->  70920 ->
   70921 ->  70922 -> *70923 ->  70924 ->  70925 ->  70926 ->  70927 ->
   70928 ->  70929 ->  70930
 
The results of all these tests are assembled and sorted, giving the following output:

   701
   70900
   70912
   70923
   713
   722
   723
 
* The overall program architecture is as follows (see xifind.vee for the source):

   ISC               
  +------+   +-------------+-------->+--------------+   +--------+
  | 7    +-->| ScanPrimary |    +--->| Concatenator +-->| sort() +-->
  +------+   +-------------+--+ | +->+--------------+   +--------+
                              | | |
       +----------------------+ | |
       |                        | |
       |   +---------------+    | |
       +-->| ScanSecondary +----+ |
           +---------------+    | |
                                | |
           +--------------------+ |
           |                      |
           |   +-----------+      |
           +-->| ScanFrame +------+
               +-----------+
 
The heart of this program are the three UserObjects ScanPrimary (which checks all the primary addresses), ScanSecondary (which checks all the remaining addresses for valid secondary base addresses), and ScanFrame (which checks all the secondary addresses for each valid secondary base address) -- and a UserFunction named TestAddr, that actually does the SPOLL test. The results of the three UserObjects are concatenated, sorted, and then output to a display, or whatever.

* The TestAddr UserFunction has the form:


   +----------------------------------------------------------------------+
   |                      UserFunction:  TestAddr                         |
   +-+------------------------------------------------------------------+-+
   | |                                                                  | |
   | |                      +---+                                       | |
   | |                      | 0 +-------------------------+             | |
   | |                      +-+-+                         |             | |
   | |                        |                           |             | |
   | |   +--------------------+--------------------+      |             | |
   | |   |                 DummyIO                 |      |             | |
   +-+   +---------+-----------------------+-------+      |             | |
   |A+-->| Address | WAIT SPOLL:0x40 CLEAR | Error +--+   |             | |
   +-+   |         |                       |       |  |   |             | |
   | |   +---------+-----------------------+-------+  |   |             | |
   | |                                                |   +-->+-----+   +-+
   | |                                              +-+-+     | JCT +-->|X| 
   | |                                              | 1 +---->+-----+   +-+
   | |                                              +---+               | |
   | |                                                                  | |
   +-+------------------------------------------------------------------+-+
   |                             [ Close ]                               |
   +---------------------------------------------------------------------+
 
As noted, all this does is perform an SPOLL (to the device named DummyIO, with the address given by the input pin). If it times out, it returns a 1 (no device), otherwise it returns a 0 (valid device).

* The ScanPrimary UserObject has the form:


   +------------------------------------------------------------------+
   |                          ScanPrimary                             |
   +-+--------------------------------------------------------------+-+
   | |                                                              | |
   | | count primary addresses                                      | |
   | |  +-----------+                                               | |
   | |  | For Count |                                               | |
   | |  | [   31  ] +----->+---------+     compute full address     | |
   | |  +-----+-----+      | B*100+A +--+  using ISC & HPIB         | |
   | |        |        +-->+---------+  |  primary address count    | |
   | |        |        |                |                           | |
   |I+--------|--------+                |                           | |
   | | ISC    |                         |                           | |
   | |        |  +------- address ------+                           | |
   | |        |  |                               A==0?              | |
   | |        |  |   +-----------------+   +--------------+-----+   | |
   | |        |  +-->| Call TestAddr() +-->| If/Then/Else |     |   | |
   | |        |  |   +-----------------+   +--------------+--+  |   | |
   | |        |  |                                           |  |   | |
   | |        |  |          address test == 0, valid device  |  |   | |
   | |        |  |       +-----------------------------------|--+   | |
   | |        |  |       |                                   |      | |
   | |        |  |   +---+---+       valid devices           |      | |
   | |        |  +-->| Gate  +----->+-----------+            |      +-+
   | |        |  |   +-------+      | Collector +------------|----->|Y|
   | |        |  |              +-->+-----------+            |      +-+
   | |        |  |              |                            |      | |
   | |        +--|--------------+                            |      | |
   | |        |  |                                           |      | |
   | |        |  |          address test == 1, test failed   |      | |
   | |        |  |       +-----------------------------------+      | |
   | |        |  |       |                                          | |
   | |        |  |   +---+---+         failures                     | |
   | |        |  +-->| Gate  +----->+-----------+                   +-+
   | |        |      +-------+      | Collector +------------------>|N|
   | |        |                 +-->+-----------+                   +-+
   | |        |                 |                                   | |
   | |        +-----------------+                                   | |
   | |                                                              | |
   +-+--------------------------------------------------------------+-+
 
This UserObject ultimately generates two arrays as outputs: one with a list of devices it found, another with a list of failed address tests. The list of found devices is passed on to the Concatenator.

* The list of failures is passed on to the ScanSecondary UserObject to check for secondary base addresses. This UserObject has the form:


   +------------------------------------------------------------------+
   |                          ScanSecondary                           |
   +-+--------------------------------------------------------------+-+
   | |                                                              | |
   | |       use totsize                        index list,         | |
   | |        output pin      list size         convert to          | |
   | |      +------------+   +-----------+      secondary address   | |
   | |  +-->| Get Values +-->| For Count +----->+----------+        | |
   | |  |   +------------+   +-----+-----+      | B[A]*100 +--+     | |
   | |  |                          |        +-->+----------+  |     | |
   | |  |        +-----------------+        |                 |     | |
   +-+  |        |                          |                 |     | |
   |N+--+--------|--------------------------+                 |     | |
   +-+           |                                            |     | |
   | |           |            secondary base address          |     | |
   | |           |   +----------------------------------------+     | |
   | |           |   |                                              | |
   | |           |   |                               A==0?          | |
   | |           |   |   +-----------------+   +--------------+     | |
   | |           |   +-->| Call TestAddr() +-->| If/Then/Else +--+  | |
   | |           |   |   +-----------------+   +--------------+  |  | |
   | |           |   |                                           |  | |
   | |           |   |       +-----------------------------------+  | |
   | |           |   |       |                                      | |
   | |           |   |   +---+---+       valid devices              | |
   | |           |   +-->| Gate  +----->+-----------+               +-+
   | |           |       +-------+      | Collector +-------------->|Y|
   | |           |                  +-->+-----------+               +-+
   | |           |                  |                               | |
   | |           +------------------+                               | |
   | |                                                              | |
   +-+--------------------------------------------------------------+-+
 
This UserObject gets a list of the failed tests on primary addresses as an input. It scans through the list, converts each primary address in the list into a secondary base address, scans for the secondary base address, and collects all the positive tests into an array for output. This array is output to the Concatenator.

The counter at top simply counts from zero to the total size of the input list of failed tests. A formula uses this count as an index into the input array. The total size of the list is given by the "totsize" output pin of a Get Values object. You cannot use the "totsize()" function, since if you give it a NIL array (one with nothing in it), you would in that case still get a "totsize" of 1 and the address would not be valid. The Get Values object gives a "totsize" of 0 for a NIL array and the UserObject exits without doing anything.

* Finally, the ScanFrame UserObject scans for the secondary-addressed devices for each secondary base address. It is very similar to the ScanSecondary UserObject:


   +------------------------------------------------------------------+
   |                             ScanFrame                            |
   +-+--------------------------------------------------------------+-+
   | |                                                              | |
   | |       use totsize                                            | |
   | |        output pin      list size                             | |
   | |      +------------+   +-----------+                          | |
   | |  +-->| Get Values +-->| For Count +---+                      | |
   | |  |   +------------+   +-----+-----+   |                      | |
   | |  |                          |         |                      | |
   | |  |        +-----------------+         |                      | |
   | |  |        |                           |                      | |
   | |  |        |    +----------------------+                      | |
   | |  |        |    |                                             | |
   | |  |        |    |    index into list                          | |
   | |  |        |    +-->+-------+                                 | |
   +-+  |        |        | B[A]  +-------->+-------+               | |
   |N+--+--------|------->+---+---+         | A + B +---------+     | |
   +-+           |            |         +-->+-------+         |     | |
   | |           |      +-----+-----+   |    create           |     | |
   | |           |      | For Range +---+    secondary        |     | |
   | |           |      | [ 1:30  ] |        address          |     | |
   | |           |      +-----------+                         |     | |
   | |           |      count through                         |     | |
   | |           |      secondary addresses                   |     | |
   | |           |                                            |     | |
   | |           |                                            |     | |
   | |           |               secondary address            |     | |
   | |           |   +----------------------------------------+     | |
   | |           |   |                                              | |
   | |           |   |                               A==0?          | |
   | |           |   |   +-----------------+   +--------------+     | |
   | |           |   +-->| Call TestAddr() +-->| If/Then/Else +--+  | |
   | |           |   |   +-----------------+   +--------------+  |  | |
   | |           |   |                                           |  | |
   | |           |   |       +-----------------------------------+  | |
   | |           |   |       |                                      | |
   | |           |   |   +---+---+       valid devices              | |
   | |           |   +-->| Gate  +----->+-----------+               +-+
   | |           |       +-------+      | Collector +-------------->|Y|
   | |           |                  +-->+-----------+               +-+
   | |           |                  |                               | |
   | |           +------------------+                               | |
   | |                                                              | |
   +-+--------------------------------------------------------------+-+
 
The main difference from ScanSecondary is that ScanFrame gets a list of secondary base addresses, and then scans through secondary addresses 1 to 30 for each base address. ScanFrame returns an array of valid device secondary addresses, which is output to the Concatenator.

* The Concatenator assembles all the valid device addresses together, and the "sort()" function then puts them in a rational order. One last thing that the program could do is then query the devices for ID. However, doing so (or determining the wisdom of doing so) is left as an exercise for the reader.

 TOP OF PAGE

[17.5] ALTERNATING TRACE DISPLAYS

* A VEE user wanted to know if there was some way he could select between different traces and display them at will in a single XY Trace object.

As it turns out, this is essentially simple to do and can be demonstrated with the following program:


  +-------+
  | Start | Start is required on VEE 3.X, not recommended for VEE 4.X.
  +---+---+
      |                            +---------------------+
  +---+---+  +----------+          |                     |
  | Until |  |          |          +-->+--------------+  |
  | Break +--+  +-------+-------+      | Concatenator +--+---+
  +-------+     | Random Number +----->+--------------+      |
                +-------+-------+                            |
                        |                                    |
                        |          +---------------------+   |
                        |          |                     |   |
                        |          +-->+--------------+  |   |
                +-------+-------+      | Concatenator +--+-+ |
                | Random Number +----->+--------------+    | |
                +-------+-------+                          | |
                        |                                  | |
                        |          +---------------------+ | |
                        |          |                     | | |
                        |          +-->+--------------+  | | |
                +-------+-------+      | Concatenator +--+ | |
                | Random Number +----->+--------------+  | | |
                +-------+-------+                        | | |
                        |                +---------------+ | |
          +-------------+                | +---------------+ |  
          |                              | | +---------------+
          |             +--------------+ | | |                  +----------+
          |             | AlphaNumeric | | | |  +---------+     | XY Trace |
          |             +--------------+ | | |  | Formula |     +----------+
          |          +->| Trace3       | | | |  +---+-----+     |          |
  +-------+-------+  |  +--------------+ | | +->| A |     +---->|          |
  | Radio Buttons |  |                   | +--->| B |     |     |          |
  +---------------+  |       +---------+ +----->| C |     |  +->|          |
  | < > Trace1    +--+------>| Ordinal +------->| X |     |  |  +-----+----+
  | < > Trace2    |          +---------+        +---+-----+  |        |
  | <*> Trace3    |        Use Ordinal pin                   +--------+
  +---------------+        instead on VEE 4.X            AutoScale    |
                                                                 +----+----+
				                                 | Delay 1 |
				                                 +---------+
 
The three Concatenators at top simulate three measurement inputs. The three measurement traces are fed to the Formula box, which also accepts an input from the Radio Buttons object to determine what trace to display, as per the Formula:

   ( X==0 ? A : (X==1 ? B : C ))
 
The limitation of this example is that display and simulated data acquisition have to occur in lockstep. In practice, to allow independent data acquisition and display, the display part of this program would likely need to be implemented as its own thread, with the traces provided by Global Variables, loaded by another independent thread or threads. However, this would make for an unmanageable and unclear example program.

This example program is available as xtrace3.vee.

 TOP OF PAGE

[17.6] HANDLING TOGGLE BUTTONS

* A user contacted support with an interesting question: He wanted to have a panel in VEE that controlled whether one of three tests were performed using VEE Toggle Controls (which one didn't matter, really) -- and have a fourth Toggle Control that could turn the other three Toggles ON or OFF. He also wanted to store the output of the three test Toggles in a Global Variable.

I tinkered with this a little bit, ran into a dead end and figured it was impossible, then tried something as a guess. It worked. It turns out to be easy to do.

The program that does this is as follows:


  +-------+
  | Until |
  | Break +--+
  +-------+  |
             |                       +---------------------------------+
    +--------+                       |           If/Then/Else          |
    |        |        +----------+   +---+-------------------+---------+
    |   +----+----+   | Shift    +-->| A | (A!=B) AND (B==1) | Then    +-+  
    |   | Toggle  +-->| Register +-->| B | (A!=B) AND (B==0) | Else If +-|-+
    |   +---------+   +----------+   +---+-------------------+---------+ | |
    |      MASTER                                                        | |
    |   +-------------- Then --------------------------------------------+ |
    |   |  +----------- Else If -------------------------------------------+
    |   |  |         
    +---|--|---------------------+
    |   |  |                     |
    |   |  |  Default Value +----+----+
    |   |  +--------------->| Toggle  +-----+
    |   +--|--------------->|         |     |
    |   |  |          Reset +---------+     |
    |   |  |                   TEST 1       |
    +---|--|---------------------+          |
    |   |  |                     |          |
    |   |  |  Default Value +----+----+     |
    |   |  +--------------->| Toggle  +--+  |
    |   +--|--------------->|         |  |  |
    |   |  |          Reset +---------+  |  |
    |   |  |                   TEST 2    |  |
    +---|--|---------------------+       |  |
        |  |                     |       |  +-->+--------------+
        |  |  Default Value +----+----+  +----->| Concatenator +--+
        |  +--------------->| Toggle  +-------->+--------------+  |
        +------------------>|         |                           |
                      Reset +---------+                           |
                               TEST 3                             |
    +------------------------------------------+------------------+
    |                                          |
    |                  +-------------------+   |
    |                  |   If/Then/Else    |   |
    |   +----------+   +---+--------+------+   |
    |   | Shift    +-->| A | (A!=B) | Then +---|-----------+
    +-->| Register +-->| B |        | Else |   |           |
        +----------+   +---+--------+------+   |   +-------+-------+
                                               |   | Set Variable  |
                                               |   +---------------+
                                               +-->|     flags     |
                                                   +-------+-------+
                                                           |
                         +---------------------------------+
			 |
			 |           +--------------+
                 +-------+-------+   | AlphaNumeric |
                 | Get Variable  |   +--------------+
                 +---------------+   | 0: 0         |
                 |     flags     +-->| 1: 1         |
		 +---------------+   | 2: 2         |
				     +--------------+
 
This program is divided into three main sections, from top to bottom:

Source for this program is available in the file xmastrsl.vee.

 TOP OF PAGE


 LAST PAGE  BACK TO INDEX  NEXT PAGE