### Tutorial #9 - A/D Conversion Using the ADC0831

copyright, Peter H. Anderson, Baltimore, MD, Jan, '98 Introduction.

This tutorial focuses on interfacing with the ADC0831 8-bit analog to digital converter.

The operation of the A/D is discussed and examples are presented which illustrate how to measure voltage, angular displacement and barometric pressure.

The DC motor provided with the starter package provides two terminals which provide a means of measuring the speed of the motor. The tutorial illustrates how this voltage may be constantly monitored and the duty varied so as to "home" in on a desired speed.

The ADC0831 is an 8-bit serial analog to digital converter which uses the successive approximation technique discussed in Tutorial #5.

See Figure #1.

Note that Stamp pins P7 (terminal 12) and P6 (term 11) are used as outputs. Pin P8 (term 13) is used as an input. Any LEDs, DIP switches and pushbuttons on other terminals may be left in place.

The ADC0831 is selected by bringing /CS low. CLK is then brought momentarily high, initiating the A/D conversion.

The data is then clocked in a serial fashion by bringing CLK momentarily high and then reading each of the eight bits in turn. Note that the first bit is the most significant bit.

In Tutorial #5, the intelligence to perform the successive approximation algorithm was incorporated in the Stamp program. Recall the "child guess the number" scenario. In this case, the ADC0831 performs this function in exactly the same fashion.

Program VOLT.BS2.

In the following program measurements are continually performed and the voltage on the wiper of the potentiometer is displayed.

```' Program VOLT.BS2
'
' Peter H. Anderson, Jan '98

N         VAR BYTE
BAND      VAR BYTE
VOLTS_100 VAR WORD

DIRS=\$00FF

MAIN:
GOSUB MAKE_MEAS
VOLTS_100 = BAND * 125 / 64
DEBUG DEC VOLTS_100 DIG 2, ".", DEC VOLTS_100 DIG 1, DEC VOLTS_100
DIG
0, CR
PAUSE 1000     ' one second between samples
GOTO MAIN

MAKE_MEAS:

OUT6=1    ' be sure CS is high
OUT7=0    ' CLK low
OUT6=0    ' initiate the conversion

GOSUB CLK

BAND=0
FOR N=0 TO 7   ' fetch each bit in turn
GOSUB CLK
BAND = (BAND <<1) | IN8
NEXT

OUT6=1    ' ADC0831 no longer selected

RETURN

CLK: OUT7=1
OUT7=0
RETURN

```
Discussion.

In subroutine MAKE_MEAS, /CS is brought low. As it is actually the negative transition of /CS from a high to low state which selects and clears the ADC0831, the /CS is first brought high.

A single clock pulse is sent to initiate the conversion.

Reading the result is performed in the FOR NEXT loop. For each bit, a clock pulse is sent clock and BAND is shifted one place to the left and logically ored with IN8 in the least significant bit position. You should be able to convince yourself that after eight iterations, the first bit received has been shifted to the most significant bit position, the second bit to the bit six position and so on.

A question may arise as to why not use the SHIFTIN command. Frankly, my feeling is that a great deal of understanding is lost. It always seems as if I spend a great deal of time just understanding the sequencing of serial reads and writes for various ICs. There are all manner of combinations; most significant or least significant bit first. The quiescent state of the clock may be a logic one or zero and reading the data may be either pre or post clock. In my mind, the above FOR NEXT is a clear implementation of the timing diagram shown in Figure #1. Why then complicate the matter by reworking this simple and clear implementation to utilize the SHIFTIN. However, this is personal preference. Some folks see the SHIFTIN and SHIFTOUT as being the greatest thing since sliced bread. I don't.

Note that the result of the A/D conversion is in variable BAND. The DC voltage is then calculated as;

```     V_A_D = 5.00 * band / 256

or   VOLTS_100 = 500 * band / 256

```
where VOLTS_100 is 100 times the voltage.

This is reduced to the following to prevent an overflow;

```
VOLTS_100 = 125 * band / 64
```
Program ANGLE.BS2.

The following is a snippet of code to display the angle of a 360 degree potentiometer which is used in many wind direction devices. That is, there is no mechanical stop and the resistance varies from 0 to 10K and then back to zero.

The potentiometers provided in the Starter Package provide nominally 270 degrees of travel. Thus, if the pot is turned to its limits, the voltage into the A/D will be either 0.0 (band=0) or 5.0 Volts (band = 255) corresponding to angles of 0 and 270.

Thus for the 270 degree potentiometer, the angle is calculated as;

```     ANGLE = 270 * band / 256

or   ANGLE = 135 * band / 256

```
In the following, I assumed a 360 degree potentiometer and thus;
```     ANGLE = 360 * band / 256

or   ANGLE = 45 * band / 32
```
```' Program ANGLE.BS2
'
' Peter H. Anderson, Jan, '98

N         VAR BYTE
BAND      VAR BYTE
ANGLE     VAR WORD

DIRS=\$00FF

MAIN:
GOSUB MAKE_MEAS
ANGLE = BAND * 45 / 32
DEBUG DEC ANGLE DIG 2, ".", DEC ANGLE DIG 1, DEC ANGLE DIG 0, CR
PAUSE 1000     ' one second between samples
GOTO MAIN
```
Discussion.

Note that the implementation of subroutine MAKE_MEAS is the same as in VOLTS.BS2.

Motorola MPX4115 Barometric Pressure Sensor.

See Figure #2.

The MPX4115 is a piezoresitive transducer which converts pressure to a DC voltage in the range of 0.2 to 5.0 Volts. A data sheet is available at http://www.motorola.com. (Search on MPX4115). It is available from Newark Electronics (http://www.newark.com) at nominally \$30.00.

Don't get too bogged down with the following algebra.

```     V_OUT = V_S (0.009 * P_kPa - 0.095)
```
Where V_S is the supply voltage and P_kPa is the pressure in kilo Pascals.

Thus;

```     V_OUT / V_S = 0.009 * P_kPa - 0.095
```
Thus;
```     band / 256 = 0.009 * P_kPa - 0.095
```
Solving for P_kPa;
```     P_kPa = 0.434 * band + 10.55
```
Barometric Pressure is one of those delightful quantities where everyone uses a different measure!
```     P_hPa = 4.34 * band + 105.5
```
where P_hPa is the pressure in hecto Pascals. This is the same as millibars.

Thus, a Stamp expression;

```     P_hPa = (4 * band) + (3 * band /10) + (4 * band / 100) + 105
```
However, in many parts of the world, pressure is measured in millimeters of mercury where one hecto Pascal equals 0.75 mm Hg. Thus;
```     P_mmHg = 3.25 * band + 79.1
```
Thus, a Stamp expression;
```     P_mmHg = (3 * band) + (2 * band/10) + (5 * band / 100) + 79
```
And of course, in the United States, we cling to our inches. One hPa = 29.53e-3 inches of mercury.

Thus;

```     P_in_Hg = 0.128 * band + 3.12

or   P_100_in_Hg = 12.8 * band + 312
```
Where P_100_in_Hg is 100 times the pressure in inches of mercury.

Thus, an expression that the Stamp can handle;

```     P_100_in_Hg = (12 * band) + (8 * band / 10) + 312
```
The following is a snippet of code that displays the pressure in inches of mercury.
```' Program PRESSURE.BS2
'
' Peter H. Anderson, Jan, '98

N         VAR BYTE
BAND      VAR BYTE
P         VAR WORD

DIRS=\$00FF

MAIN:
GOSUB MAKE_MEAS
P = (12 * BAND) + (8 * BAND / 10) + 312
DEBUG DEC P DIG 3, DEC P DIG 2, ".", DEC P DIG 1, DEC P DIG 0, CR
PAUSE 1000     ' one second between samples
GOTO MAIN
```
Discussion.

Note that there is a deficiency in this approach. The dynamic range of the barometer is from 0 to 35.75 inches of mercury. However, the ADC0831 is an eight bit A/D and thus each of the 256 bands is about 0.13 inches of mercury. That is, the readings are quantized.

```     BAND P_100_in_Hg

205       29.36
206       29.48
207       29.61
208       29.74
```
If we are only interested in the range of 27 to 33 inches, corresponding to bands 186 and 233, we are throwing away much of the dynamic range of the A/D.

If you would like a gain and shift circuit which maps 27 inches of mercury to a band of 0 and 33 inches to a band of 255 reducing the quantizing error to 0.02 inches of Hg, please let me know. The circuit may be implemented using the 324 quad operational amplifier provided with the Starter package and a few resistors.

DC Motor Feedback.

See Figure #3.

The idea here is to monitor the speed of a motor and turn it either more quickly or more slowly so as to turn it at a constant speed.

The DC Motor provided with the Starter package provides a means for measuring the actual speed of the motor. The rotation of the motor generates an AC voltage on two terminals which is nominally 3.1 VRMS per 1000 RPM. These two terminals are the only two which are not equipped with "quick connect" lugs.

Assume the maximum speed is 3000 RPM (12 VDC). The generated voltage is then 9.3 VAC or 13.2 V peak. This is then half wave rectified using a single 1N4004 diode (0.7 Volt drop) and attenuated by a factor of three using the resistive voltage divider. Thus the voltage V_tach at the output of the divider is between 0.0 and 1/3 (13.2 - 0.7) or 4.17 VDC, depending on the speed of the motor.

Note that RPM is nominally;

```     RPM_DIV_10 =  300 * V_tach / 4.17
=  300 * V_tach_100 / 417
```
where V_tach_100 is 100 times V_tach.

This is then fed back to the input of the A/D converter. Thus;

```     V_tach_100 = 500 * band / 256
= 125 * band / 64
```
Thus;
```     RPM_DIV_10 = 37500 * band / 26688
```
Thus, if one desires to turn the motor at a specific speed, the target band may be calculated;
```     target_band = 26688 / 37500 * RPM_DIV_10

= 0.711 * RPM_DIV_10
```
For example, if one desires to turn the motor at 1800 RPM, RPM_DIV_10 is 180 and the target band is 128.

Thus, to maintain the DC motor at this speed, the motor is turned using the PWM command with a certain duty. The tachometer voltage V_tach is then measured and if the measured band is less than the target band, the motor is turning too slowly and the PWM duty is increased. However, if the measured band is larger than the target band, the PWM duty is decreased.

Program FD_BK_1.BS2.

The following program turns the motor at 1800 RPM.

```' FD_BK_1.BS2
'
' Uses PWM to turn motor.  A reading of the tachometer is constantly made
' and compared with a target value.  Duty is adjusted so as to "home" in
' on the desired speed
'
' Direction is controlled by S15.
'
' P. H. Anderson, Jan, '98

DUTY           VAR BYTE
N              VAR BYTE

RPM_DIV_10     VAR BYTE
TARGET_BAND    VAR BYTE
MEAS_BAND      VAR BYTE

DIRS = \$00FF
DUTY = 110           Start out with motor near off
RPM_DIV_10 = 180
TARGET_BAND = (7 * RPM_DIV_10/10) + (RPM_DIV_10/100) +
(RPM_DIV_10/1000)

TOP:
BRANCH IN15, [ONE_WAY, OTHER_WAY]    ' read S15

ONE_WAY:
OUT0 = 0
OUT1 = 1
GOTO TOP_1

OTHER_WAY:
OUT0 = 1
OUT1 = 0
GOTO TOP_1

TOP_1:
PWM 2, DUTY, 100    ' pwm at given duty for 100 msecs
GOSUB MAKE_MEAS     ' measure the tachomoter

IF MEAS_BAND < TARGET_BAND THEN INCREASE
DUTY=DUTY-2         ' else, it is too fast
GOTO  TOP_2
INCREASE:
DUTY=DUTY+2         ' too slow
GOTO TOP_2
TOP_2:
GOTO TOP

MAKE_MEAS:

OUT6=1         ' be sure CS is high
OUT7=0         ' CLK low
OUT6=0         ' initiate the conversion

GOSUB CLK

MEAS_BAND=0
FOR N=0 TO 7   ' fetch each bit in turn
GOSUB CLK
MEAS_BAND = (MEAS_BAND <<1) | IN8
NEXT

OUT6=1    ' ADC0831 no longer selected

RETURN

CLK: OUT7=1
OUT7=0
RETURN
```
Discussion.

This program turns the motor at 1800 RPM. The target band is calculated.

The motor is then PWMed for nominally 100 ms with an initial PWM duty of 110. The value of V_tach is then measured using the A/D. On finding, the measured band is too low, the duty is increased by two, and the process repeats.

Note that I used a very simple algorithm to adjust the duty and it will take some time for the motor to come up to speed. You might experiment with others. For example, adjust the duty by an amount proportional to the difference between the target and the measured band.

Program FD_BK_2.BS2.

In the following program, S15 determines the direction and S14, S13 and S12 specify various target speeds.

```     Switch         Target RPM
Setting

0         		500
1         		750
2         		1000
3         		1250
4         		1500
5         		1750
6         		2000
7         		2250

```
```' FD_BK_2.BS2
'
' Uses PWM to turn motor.  A reading of the tachometer is constantly made
' and compared with a target value.  Duty is adjusted so as to "home" in
' on the desired speed.
'
' Direction is controlled by S15.  Target speed is set by S14, S13 and
S12.
'
' P. H. Anderson, Jan, '98

DUTY           VAR BYTE
N              VAR BYTE

RPM_DIV_10     VAR BYTE
TARGET_BAND    VAR BYTE
MEAS_BAND      VAR BYTE

DIRS = \$00FF
DUTY = 110           ' Start out with motor near off

TOP:
BRANCH IN15, [ONE_WAY, OTHER_WAY] ' read S15
LOOKUP IND&\$07, [50, 75, 100, 125, 150, 175, 200, 225], RPM_DIV_10
TARGET_BAND = (7 * RPM_DIV_10/10) + (RPM_DIV_10/100) +
(RPM_DIV_10/1000)

ONE_WAY:
OUT0 = 0
OUT1 = 1
GOTO TOP_1

OTHER_WAY:
OUT0 = 1
OUT1 = 0
GOTO TOP_1

TOP_1:
PWM 2, DUTY, 100    ' pwm at given duty for 100 msecs
GOSUB MAKE_MEAS          ' measure the tachomoter

IF MEAS_BAND < TARGET_BAND THEN INCREASE
DUTY=DUTY-2         ' else, it is too fast
GOTO  TOP_2
INCREASE:
DUTY=DUTY+2         ' too slow
GOTO TOP_2
TOP_2:    GOTO TOP

MAKE_MEAS:

OUT6=1         ' be sure CS is high
OUT7=0         ' CLK low
OUT6=0         ' initiate the conversion

GOSUB CLK

MEAS_BAND=0
FOR N=0 TO 7   ' fetch each bit in turn
GOSUB CLK
MEAS_BAND = (MEAS_BAND <<1) | IN8
NEXT

OUT6=1         ' ADC0831 no longer selected

RETURN

CLK: OUT7=1
OUT7=0
RETURN
```
Discussion.

The settings of switches S14, S13 and S12 is read and mapped into an RPM_DIV_10 value using the LOOKUP command. The target band is then calculated. Otherwise, the program is the same as FD_BK_1.BS2.

Summary.

The analog to digital converter is a powerful technique for interfacing with the real world which is decidedly analog in nature. It is another tool to add to using the 555 and RCTIME which have been discussed in previous tutorials.

The tutorial provided a subroutine MAKE_MEAS which causes the ADC0831 to perform an A/D conversion. Examples were provided which illustrated how the A/D may be used to measure and display voltage, the angle of a potentiometer and barometric pressure. The final example illustrated how the A/D result may be used to control a process. 