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.
Operation of the ADC0831.
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.
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 RETURNDiscussion.
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 / 256where VOLTS_100 is 100 times the voltage.
This is reduced to the following to prevent an overflow;
VOLTS_100 = 125 * band / 64Program 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 / 256In 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 MAINDiscussion.
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.
V_OUT / V_S = 0.009 * P_kPa - 0.095Thus;
band / 256 = 0.009 * P_kPa - 0.095Solving for P_kPa;
P_kPa = 0.434 * band + 10.55Barometric Pressure is one of those delightful quantities where everyone uses a different measure!
P_hPa = 4.34 * band + 105.5where 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) + 105However, 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.1Thus, a Stamp expression;
P_mmHg = (3 * band) + (2 * band/10) + (5 * band / 100) + 79And of course, in the United States, we cling to our inches. One hPa = 29.53e-3 inches of mercury.
P_in_Hg = 0.128 * band + 3.12 or P_100_in_Hg = 12.8 * band + 312Where 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) + 312The 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 MAINDiscussion.
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.74If 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 / 417where 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 / 64Thus;
RPM_DIV_10 = 37500 * band / 26688Thus, 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_10For 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.
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 RETURNDiscussion.
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.
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 RETURNDiscussion.
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.
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.