VDAQ – A Data Acquisition Development Program

Authors

Publication

Pub Details

Date

Pages

See all articles from SyncWare News v1

Here is a program that demonstrates a simple yet effective way to get analog information (data) into your ZX81/TS1000/TS1500 computer, with a minimum of additional hardware. Also included are various plot and display routines so you can get visual and printed output of your acquired data. Along the way it will show you various “tricks” and other tidbits that might help out in your programming.

A little background is in order. My original intent was to write a “universal” data acquisition program for the popular “VOTEM” analog interface. “Universal” is a pretty broad term, though; it didn’t take me long to realize that a truly general program would be difficult to implement in 16K. A better approach is to write a number of customized programs, each tailored for a certain range of applications. If nothing else, possibilities for display and printer formats are almost endless, not to mention ways in which the data may be processed once acquired. So what I’ll try to do in this series of articles is to present some “basics” from which you can expand to suit your application.

In this issue I present a complete program which will sample data at a rate from about 1 sample per sec. to about 350 samples per second, with resolution between 8 bits (fastest sample rate) and 14 bits (slowest sample rate.) It can store 2048 discrete samples, each one consisting of two bytes. Data is organized into “screens” of 64 samples. Each screen can be acquired/displayed individually, or several screens can be chained for longer timebases. As listed, the capacity is 32 screens, but you can easily make this more or less with simple changes. TS2040 printer is supported, and you can even do “side-winder” plots with a vertical resolution of 60 points and length (width?) depending only on the number of screens plotted. Plot limits are easily changed, and screen plots are done in machine-code for speed, Since this program is optimized for speed, no data display occurs during acquisition, and there are no additional pause routines for longer time-bases, This will be the topic for the next issue. But for now, let’s backtrack a little and look at how the hardware works, and then at what you’ll need, hardware-wise, to make the software work.

Theory

There are several ways to get analog data into a computer. The usual approach is to use an analog-to-digital converter; such devices have at least one analog input channel, and a digital data bus for output. The binary number appearing at the data bus is proportional to the voltage at the analog input. Converters are available to give a resolution anywhere between 8 and 14 bits (15 bit with a minus sign is present “state of the art”; that’s 4 significant figures. ed.), depending on the accuracy required.

Eight-bit converters are relatively easy to implement on an eight-bit CPU like the Z80, since the data can be impressed directly onto the CPU’s data bus. For higher-resolution A-D’s the acquisition has to be done in two “chunks,” using some decoding scheme to first look at the first 8 bits of the output bus, then at the remaining bits. In either case, the page to start a conversion can be either I/O or memory-mapped. The resulting data is then loaded into memory for subsequent display and other processing.

With all its advantages (mainly speed) this approach does have a few drawbacks. First among these is that it requires connection to the computer’s data bus (8 lines) as well as to at least part of the address and control busses (lines like MREQ, IORQ, RAMCS, etc). Another drawback is that matters start getting quite complicated if greater than 8-bit resolution is required.

Because of all the circuitry needed, most folks would prefer simply buying a commercial module rather than mess with all those wires, decoding, timing circuits, etc. See the Ener-Z Report Generator review elsewhere in this issue for an overview of one such package. Another is the Computer Continuum “(8+8)*8” A-D, D-A board (reviewed in a future issue.)

There is another route we can take if high speed (faster than about 300 per second on the ZXTS) is not of the essence. It is an old method, but still very useful. In this method, the voltage is first converted into a stream of on-off pulses whose frequency is proportional to the input voltage. Such a device is called, aptly enough, a “voltage-to-frequency converter,” or more simply a “V-F.” Now all that is required is a single IN port bit to get the stream of pulses into the computer, It is a serial rather than parallel approach.

Your ZX/TS has a dedicated input port already the EAR jack. A single Z80 IN A,(FE) command gets the state of the EAR jack input in bit 7 (the most significant bit;) from there it is a simple matter to write software to count how many pulses (state changes) appear during a fixed time span – the resulting count will be proportional to the input voltage. By appropriately modifying the IN command, this approach will work with any computer with an IN port such as a cassette input. Calibration can be done entirely in software, making the hardware aspect simple indeed.

V-F converters almost always use a circuit ealled an “integrator,” which provides an output voltage proportional to the integral of the input voltage. This means that the higher the voltage to the input, the faster the output from the integrator will ramp up (increase). This signal is applied to a comparator, and when it exceeds the comparators upper trip point the comparator toggles (changes state), at the same time resetting the integrator. Result – the higher the input voltage, the higher the frequency of the pulses at the output of the comparator. See Figure 1. This is called “single slope V-F conversion.” Also possible is what is termed “dual-slope conversion,” in which the conversion is done in two steps; a known reference voltage is used to ramp the integrator up, and the unknown voltage is used to ramp the signal back down. The ratio of the ramp-down time to the ramp-up time equals the ratio of the reference voltage to the unknown voltage, from which the unknown voltage can be easily derived. The dual-slope approach is more immune to drift and other inaccuracies, and allows “auto-calibration” in dedicated devices like the ubiquitous Digital Volt Meter (DVM). (Virtually all inexpensive DVM’s use some variant on this approach – as I mentioned earlier, we’re not dealing with anything new and esoteric here.)

When using V-F data acquisition, accuracy depends on the “acquisition interval.” This is how long we are counting, and therefore how many counts we read for a given input voltage. If “full-scale” (the highest voltage we wish to measure) only returns 256 counts, we get 8-bit accuracy; but if it returns 16384 counts at full scale we have 14-bit accuracy. So you see that the more accurate you want it, the longer you’ll have to sample the input pulses. How fast you can go depends on computer speed; on the ZX-TS it takes about 1 second to get maximum resolution (better than 14 bit, or about -005%). At the other extreme, we can get 8-bit resolution (about .5%) with acquisition times down to a few milliseconds.

In this program we’ll experiment with the relationship between speed and accuracy by making the acquisition interval equal to the sampling interval; as soon as one sample is acquired, the program goes right on to the next, with no additional timing pauses. Timing is varied by changing the acquisition interval; as a result, the full-scale count and the number of counts per volt changes with sample-rate, and has to be compensated for when converting the counts into voltage or other units.

Next time we’ll add programmable pauses so the sampling interval is greater than the acquisition interval for longer time-bases (minutes, hours, days). This will also allow time to update a continuous display during acquisition. You are encouraged to customize and improve these programs from there, to come up with exactly what you need for your application.

What applications can it be put to? Well, just briefly mentioning some of the possible input devices should help suggest plenty of ideas. You could use a potentiometer for position sensing (simple robotics, wind or antenna rotor direction indication, ete.), a photocell (light meter, etc.) or a strain transducer (for forces, stresses.) Use a microphone as the heart of a decibel (sound level) meter, Let’s not forget about temperature probes, for clinical/ meteorological “thermographs,” solar heating control, or heat-transfer studies. For some uses you won’t even need the V-F, The obvious example is as a frequency counter (this program will handle frequencies from about 2 Hz to about 20 kHz.) Similarly, you won’t need the V-F for such things as radiation monitors (just run a Geiger counter output to the EAR jack and have the computer count the pulses. Use Tom’s moving-trend routine to smooth the data as required.)

A final point before we get on to brass tacks is that the V-F approach lends itself very well to remote sensing; you can locate the V-F with the sensing device, and bring the data to the computer along a single digital line (use a comparator for cleanup at the receiving end if needed.) This is much more accurate and free of glitches than running a long analog line, and is cheaper and easier than bringing the data in on parallel data + control lines. But now that I’ve firmly convinced you that “you NEED this program,” let’s take care of the hardware aspect, and then briefly go over the system software (the fun part).

The Hardware

If you have a ZX/TS with 16K RAM and a VOTEM analog interface, you already have all the hardware you need, If you don’t have a VOTEM, you should consider purchasing either a complete or partial kit (any combination of bare board, documentation and V-F chip). (they are still available, ed.) Down East Computers! prices are not out of line, and their unit is the best approach if you’re not willing ot build a V-F board from scratch.

For those of you who don’t mind a little hardware hacking, I’m printing a “rip-off” circuit for the LM331 V-F chip, derived from the National Semiconductor application notes for this device. It is accurate, inexpensive, and quite readily obtainable (if you can’t find it a your local jobbers’, check with the nearest location of Avnet/Hamilton). Values shown are for a 1 volt full scale sensitivity, you can easily sense higher ranges by preceding the V-F with a resistive voltage divider. The absolute precision of the other parts is non-critical, since we’ll calibrate the final circuit anyway (using a software scale constant).

What IS important is that the timing parts be stable with temperature; the timing capacitor should be polystyrene or polycarbonate, and the resistors should be metal-film. Avoid extreme temperature changes around the V-F board if possible. Wiring is non-critical, and you can use wire-wrap on a perf board to do the actual construction. You can power the V-F from the computer supply, or use a small battery (especially recommended if you’ll be locating the interface remotely).

You can use the Radio Shack 276-1790 V-F, F-V IC. Applications notes are provided with the part. (Though we won’t be using it, this unit also allows you to convert from a frequency back to a voltage you could conceivably work up a circuit which will translate a frequency -such as you can make available at the MIC jack- into an analog voltage, which can be used to control such things as proportional heaters, motors, etc. More about this in a future installment.)

If you’re using a VOTEM, you should disconnect capacitor C8 at the input to the V-F, or replace it with a much smaller unit (eg. DL uF), otherwise you’ll get considerable waveform distortion due to its filtering effect. (A 20 Hz. square wave won’t look the least bit “square.”)

Whatever V-F circuit you use, the maximum output frequency should be limited to about 25 kHz. At higher frequencies you’ll rapidly get inaccuracy due to “strobing” effects, since the rate at which the sampling loop runs is about 65 kHz. The amplitude requirement is that the “on” voltage should be 2-5 volts, and the “off” voltage should be a few tenths of a volt maximum. Duty cycle (ratio of on-time to total cycle time) is non-critical, but shouldn’t deviate too far from 50% for best results. Run the output to the EAR jack, and the hardware and interfacing is complete.

The Software

In order to be able to present the entire program in one installment, I’ll have to gloss over some “fine points” regarding the program this time. This is perhaps just as well, since what you learn on your own is much more likely to stick than what you read. Instead, I’ll concentrate on how to get the program entered into your computer, and on how to use it once it’s debugged and safely on tape. Thus you’ll have something to play with while we’re working up the additions and improvements for the next episode. You shouldn’t have much difficulty entering and debugging it, and you can use any of several different ways to enter the machine-code portion.

The Machine Code

First you have to enter the machine-code. Start with the usual line 1 REM statement, 407 bytes long. Use a toolkit or enter it the “hard way,” one character at a time. Another way of doing it is shown in the listing for line 1 in the BASIC listing on page XX. Enter 1 PRINT 9 followed by 50 repetitions of +0. The computer interprets each zero as a floating point number – so it uses up six additional bytes for the binary representation of each zero. The first 0 takes 7 bytes, each +0 takes 8 bytes. We’re using the ZX’s extravagant number storage to our advantage, requiring only 101 keystrokes to enter 407 bytes. Note that this won’t work using 1 REM 0+0+… because after a REM, the zeros are interpreted as characters (1 byte each). So use PRINT, then change the PRINT to a REM using POKE 16513,234.

However you get the REM statement in there, you can check that you have the right length by entering PRINT PEEK 16921, which should return 118 (end of line marker). If you want to make line 1 more resistant to accidental deletion, POKE 16510,0 to assign it a line number of zero. Now enter a decimal loader as on page XX, setting the counter limits (in line 10) FOR A=16514 TO 16843, and use the values shown in the decimal table. Or use a hex loader or assembler and enter the program from the Hot-Z listings. The locations from 41CCh (16844d) to 41D7h (16855) are machine-code variables, and need not be entered. Similarly, the 64 bytes at 41D8-4217h (16856-16920d) represent a machine-code “array”, which holds the “timing value” for each screen. If you want more than 32 screens, make the original REM longer – e.g. for 40 screens, add two more “+0″‘s (16 bytes). This timing value is the number that is loaded into 409C-409Dh (16551/2d) in the acquisition routine, which determines how many times the program loops to take another look at the state of the inport bit 7, and sets our acquisiton interval or “window.”

The first three routines are nested loops; MULTISCREEN calls ACQUIRE A SCREEN, which calls ACQUIRE A POINT. You could save some time between samples to improve accuracy as low timing values by writing it as one routine, but I left it as shown to make it a little easier to follow. The acquisition routine is a slight variation on the routine supplied with VOTEM. The next routine gets the start address of the specified screen being written to/read from. The data is stored in the first BASIC variable, D$(4096), which has to be twice as long as the total number of points, Although the array is actually organized as 32 screens of 64 2-byte points, DIM D$(32,64,2) or DIM D$(32,128) will not work with this storage system, D$ must be single dimensioned.

The next routine draws the axes MUCH faster than any BASIC loop could, especially for the vertical axis. The rest of the code is the data graphing program, consisting of an arithmetic package (so we can do 16-bit by 16-bit division) which is called by the plotting routine to evaluate each “position. The arithmetic package is a portion of the run-time package of Bob Berch’s ZX COMPILER, and is actually more than we need here, as it also contains multiplication, ABS, SGN and other functions. It was used here to demonstrate that a compiler (especially Bob Berch’s, of Cinagro Software, 19 Jacques St., Rochester, NY 14620) is a very worthwhile thing to buy even if you’re more interested in hand-assembly; you can find many useful routines in the run-time package that will save you time in assembly by giving you function utilities to call when needed. Stay tuned to SWN for a significant article by Bob which shows how you can drive a serial printer from your MIC jack meanwhile, make it worth his while to submit this article (and otherwise keep supporting your machine) by ordering his compiler or other programs.

If you wish to get graphs dumped to your Centronics printer via Memotech CIF, you have to enter the print buffer and conversion table as per SWN 1:3, then enter the machine-code of this program into a line 2 REM statement. It will be displaced by 348d bytes, starting at 16862. You will have to change (offset by 348) all CALLs and references to machine-code variables or use Hot-Z Ii to relocate it for you. You’ll also have to change routine addresses in the BASIC, and add the screen-dump given in 1:4 to replace the COPY command.

The BASIC

Once the machine-code is in, the BASIC should present no special problems. You might want to rearrange the menu options – e.g. put “Initialization” as option 1 and start it at line 1000, put “Acquire a Screen” at option 2 and start at 2000, or however you want it. Though the BASIC listing is only 2 pages long, there’s quite a lot going on here, including some “frills” you could do without (like the pseudo-INPUT routine at 8000, which inputs 2 digit numbers without pressing Enter, or 1 digit numbers using Enter).

When using RUN for the first time (after SAVEing in case you have bugs in the machine-code), the program goes to the initialization/ calibration part of the program. You have to calibrate first voltage (calibrating the V-F) and then the time-base (calibrating the computer). Use a voltage close to full-scale, and monitor it with an accurate DVM while pressing Enter. The reference to “switches 3, 6 and 7” refer to VOTEM, in which this connection measures the 1V reference built into the V-F. The display will disappear for about 1 second, then input the measured reference voltage. The program prints the observed count and counts per volt (at the longest timing value possible). Then you have to time how long it takes to acquire a screen of 64 points; it will be between 60 and 66 seconds, depending on the speed of your particular machine. Enter the actual time, and the computer is calibrated for time-base.

When acquiring data, you have three options for starting the acquisition; by pressing a key (option “K”), when the input frequency becomes non-zero (press “N”) or when the input frequency goes to zero (press “Z”). You may have other requirements, which you should be able to program if you study how these options work.

Some Important Variables

Here are some of the crucial variables in the program. Some (like R, CL, C0) are also machine code variables: the address is shown where applicable.

  • VREF – full scale calibration value
  • C – counts at VREF. C0=65535 (later a tem. var.)
  • C1 – counts per volt at C0=65535
  • C0 – (16540-41) Timing value (number of acquisition loops). C0=65535*TB/TREF. Stored in CO array for each screen.
  • TREF – Time required to acquire 1 screen at C0=65535
  • TB – Time-base for 64 acquisitions (1 screen)
  • SR – Sample Rate (mSec.)=1000*TB/64
  • CM – counts per volt (or kHz.)=C1*C0/65535
  • CL – (16852/53) Count at lower plot limit (=PL*CM)
  • CH – Count at upper plot limit =PH*CM
  • R – (16850/51) Plot ratio =(CH-CL)/(max. y val.) Y-position given by (count-CL)/R
  • PL – value at bottom of graph
  • PH – value at top of graph
  • DP – order of magnitude of accuracy (for # of decimal places)

Operation of the rest of the features is pretty straight-forward, and the prompts should help. When doing a side-winder plot, you might save paper if you first do a “dry run” (prints to screen only) to make sure your data doesn’t go off scale.

Multi-screen acquisition and display asks first which screen to start at, then how many screens the acquisition is to run. Obviously you can’t acquire more screens than you have available after the starting screen. The program then loads the timing value into the timing value machine-code array for each screen involved. (Assures correct scaling for each screen when plotting and printing later.)

Line 9999 shows an interesting option to the STOP command, first reported in SYNAPSE (Central PA Users’ Group). Look ma, no report code! Verify that the program indeed has stopped by pressing Enter or LISTing.

Another tidbit is demonstrated in lines 20902210 and a couple other places, S1 and S2 are the two bytes of the SEED variable which is set by RAND. This is a great way to convert a decimal number (e.g. R) into two-byte form; just RAND R, and then PEEK 16434 and 16435 to get the high and low bytes for that number. One warning – it doesn’t work with zero, since RAND 0 means the same as RAND – ie get the value currently in the FRAMES variable. So for the low-count variable CL (count corresponding to the bottom of the screen) we have to use another approach (lines 2120-2130), as this variable may be zero. I first saw this programming device in Ralph Coletti’s newsletter (no longer being published,) though it has also appeared in a couple other publications, Lines 4-7 restore the program listing cursor and the top line in automatic listings to line 8, in case you list line 1 and the automatic listing gets stuck. These POKEs can be done in the immediate mode also.

When printing the data values, the program takes the acquisition interval into account and shows you only as many decimal places as you can expect for that acquisition rate.

You may wish to change the display format; this routine prints a two-column listing specifically with the TS2040 in mind, but is a little awkward for “screen-only” data display. Likewise, you might come up with a faster side-plot approach, perhaps using a m/c routine similar to the single-screen plot.

Other challenges: – write additional lines in the printing routine to compensate for the non-zero time between acquisitions. Modify the program to VREF work with Nissim Elmaleh’s Software-only Hi-Res or Russell’s HRP hi-res printer package, or with Memotech HRG or other hi-res hardware package. Translate the program for use with the TS2068 shouldn’t give much trouble, though upgrading the display routines to hi-res might give you a challenge. Work out the machine-code to plot quantities with negative slope factors (such as most temperature probes.) Above all, have fun with this!

Products

 

Downloadable Media

Scroll to Top