This tutorial focuses on using the Stamp to generate frequencies.
Wire the circuitry as shown in Figure #1. Note that one of the special LEDs which has an internal 330 Ohm limiting resistor is connected to terminal 6 (P0) and a speaker is connected through a 22 uFd capacitor terminal is connected to terminal 7 (P1). The LED will be referred to as LED0 and the speaker as SPKR.
The function of the capacitor is to avoid placing an excessive DC load on the Stamp output connected to the 8 Ohm speaker.
In addition, the DIP switches S15, S14, S13 and S12 may be left connected to to terminals 20, 19, 18 and 17 corresponding to P15, P14, P13 and P12. The pushbutton (PB11) should be connected terminal 16 which corresponds to the P11. Only DIP switches S15 and S14 will be used.
In Program FREQ_1.BS2, LED_0 is used to simulate a relay which controls whether a telephone is on-hook (telephone hung up) (LED off) or off-hook (LED on). A speaker is used to monitor the dialing of a telephone number followed by the sending of bursts of tone to indicate a quantity.
When pushbutton PB11 is released, a logic one is seen on IN11 causing the program to continually loop, scanning PB11 and assurring that the phone is on-hook by turning LED_0 off. When PB11 is depressed, the program causes LED_0 to operate (phone off-hook) followed by pause, presummably waiting for dial tone. (Note that no provison is made to actually detect dial tone. Rather, it is assummed that dial tone will be present within two seconds).
The telephone number is "dialed" using dual tone multifrequency signaling (DTMF), also known as Touch Tone which is a well protected trademark of what was once known as the Bell System.
[One of my first assignments at Bell Laboratories was developing active filters using 741 op amps which cost some $50 each and I was fortunate to work for many years with Charlie Morrison who conceived and implemented Touch Tone.]
After "dialing", there is a ten second pause to allow the receiving party to answer the phone. Again, there is no status signal that this has actually happened. The line might well be busy or not answered, but the program assumes the phone has been answered after this 10 second pause.
Short tones are then sent to represent a quantity. For example;
beep beep pause beep pause beep beep beep endmight indicate the quantity 213.
After sending the tones, the phone is again place "on-hook" (LED off).
Important Note. I selected this application as an example as it is something most of us can identify with. However, you can not simply connect a Stamp to a phone line. A phone line normally has a -48 VDC potential across the tip and ring and ringing potentials are typically 84 VRMS 20 Hz superimposed on 48 Volts. Believe me, I happened to be in contact with many telephone lines when ringing was received and it is a jolt to remember. Connecting a Stamp directly to a phone line will definitely give your Stamp a jolt. It will destroy your Stamp.
Over the years I have seen many books related to interfacing with the telephone network and I assume, a search at http://www.amazon.com will find a number that are currently in print.
Thus, this program illustrates a nice application, but a great deal more circuitry is required to safely interface with the telephone network.
' FREQ_1.BS2 ' ' Shows how to output a sequence of Multifrequency Tones on P1 ' Followed by zips of tone which might be used to indicate the value ' of a quantity. ' ' A "relay" (LED0) on P0 is operated taking the phone off-hook followed ' by a 2 second delay. A telephone number is dialed using DTMF. ' ' The quantity is then sent by sending bursts of tone. For example ' 4053 might mean the temperature at the remote site is 40.53 degrees F. ' ' P. H. Anderson, 28 Nov, '97 QUAN VAR WORD ' quantity to be sent QUAN_COPY VAR WORD ' for temporary storage DIGIT VAR NIB ' individual digits in QUAN N VAR NIB DIRS=$00FF ' low byte is outputs QUAN = 4053 ' this is the qauntity to be sent OUT0=0 ' leave phone on hook SCAN: IF (IN11 <>0) THEN SCAN OUT0=1 ' operate a relay to take phone off-hook PAUSE 2000 ' wait for dial tone DTMFOUT 1, 200, 100, [1, 4, 1, 0, 8, 9, 3, 8, 7, 6, 2] PAUSE 10000 ' wait for someone to answer GOSUB SEND_QUAN ' send the quantity in zip tone format PAUSE 5000 OUT0=0 ' hang up DONE: GOTO DONE SEND_QUAN: ' Note. I have since found a simpler implementation - see below. QUAN_COPY = QUAN ' make a copy so as not to destroy QUAN DIGIT = QUAN_COPY / 1000 ' isolate the thousands GOSUB SEND_ZIP QUAN_COPY = QUAN_COPY // 1000 DIGIT = QUAN_COPY / 100 ' remaining hundreds GOSUB SEND_ZIP QUAN_COPY = QUAN_COPY // 100 DIGIT = QUAN_COPY / 10 ' tens GOSUB SEND_ZIP QUAN_COPY = QUAN_COPY // 10 DIGIT = QUAN_COPY / 1 ' units GOSUB SEND_ZIP RETURN SEND_ZIP: ' sends short zips of 440Hz tone based on value of DIGIT IF (DIGIT<>0) THEN SKIP_ZERO ' if DIGIT is 0, make it ten DIGIT = DIGIT + 10 SKIP_ZERO: FOR N = 1 TO DIGIT FREQOUT 1, 200, 440 ' send a burst of 440Hz PAUSE 200 NEXT ZIP_DONE: PAUSE 500 ' pause before sending the next one RETURNThe "dialing" is performed by;
DTMFOUT 1, 200, 100, [1, 4, 1, 0, 8, 3, 6, 3, 4, 2, 6]The first quantity is the pin, in this case P1. The next two indicate the number of milliseconds each digit is to present and the quiet time between digits. The number to be dialed is in the brackets, in this case 1 (410) 836-8526.
In this application, a parameter such as temperature or similar might be being monitored. The calling and reporting, in this case the depression of PB11, might be the result of an extreme temperature. Or, it the Stamp may have been programmed to call and report every hour. Another obvious application is to report intrusion, where the quantity may be the identification of the warehouse or the point of intrusion.
In this example, the parameter to be sent is QUAN and it is simply set to 4053. Note that this is decimal.
After dialing, followed by a pause for the party to answer, subroutine SEND_QUAN is called and the quantity is converted to decimal.
DIGIT = QUAN_COPY / 1000 ' this isolates the number of thousands ... QUAN_COPY = QUAN_COPY // 1000 ' this calculates the remainder ... DIGIT = QUAN_COPY / 100 ' number of 100s in the remainder etcWhy Do We Have to Do All of This?
This whole matter of binary, decimal and hexadecimal can be very confusing.
As noted above, I indicated the number is 4053 decimal and one might incorrectly assume this is stored in four nibbles as
4 0 5 3 or %0100 0000 0101 0011Thus, one might incorrectly assume we could isolate the digits;
DIGIT = QUAN_COPY.NIB3 ' isolate nibble 3 of the word ... DIGIT = QUAN_COPY.NIB2 ' isolate nibble 2 ... DIGIT = QUAN_COPY.NIB1 ' isolate nibble 1 of the word ... DIGIT = QUAN_COPY.NIB0 ' isolate nibble 0 ...Note that on digital computers, all quantities are stored in binary. When we as humans see a number such as;
%0101 0011 1001 0000it is a bit overwhelming. Imagine having conversations, conveying such numbers.
Base 16 offers a convenient shorthand, as one need only group by nibbles. In this case;
$5390But, I would defy anyone to look at the above binary number and with a glance note that it is 25,488 decimal. Thus, there is a problem; a computer works best in natural binary and we as humans have difficulty converting binary quickly to decimal.
Thus, in general a computer will accept decimal. For example, in the C language;
value = 15; scanf("%d", &quan);and in this example;
QUAN = 4053The Stamp programming package accepts this decimal value, but promptly converts it to %0000 1111 1101 0101 which is $0FD5. But, once again, this hexadecimal notation is something we use as humans to represent that confusing binary number. A binary computer works in binary.
Thus, if I had used isolated each DIGIT using;
DIGIT = QUAN_COPY.NIB3 ' isolate nibble 3 of the word ... DIGIT = QUAN_COPY.NIB2 ' isolate nibble 2 ... DIGIT = QUAN_COPY.NIB1 ' isolate nibble 1 of the word ... DIGIT = QUAN_COPY.NIB0 ' isolate nibble 0the result would have been 0, F, D, 5 which is quite different than the desired 4, 0, 5, 3.
This whole subject is confusing and perhaps I have muddied the waters even more. I hope not.
In a nutshell, a programming package will accept decimal numbers. Otherwise, no one would buy it. However, this is immediately converted to natural binary and the base_10 digits don't line up with the nibbles. The computer does all operations in natural binary. However, on outputting to the user, we expect to see decimal and the computer has to do the the conversion.
Thus in the C language; printf("%d", value)
or in PBASIC DEBUG DEC VALUE
Thus, the computer will accept decimal numbers and print decimal numbers, but everything in between is done in natural binary. In our case, we wanted to use something other than a "print" and thus we were forced to do the conversion from natural binary to decimal using the "divide and remainder" approach.
Subsequent to developing program FREQ_1.BS2, I discovered the DIG operator which makes the decimal conversion appear a whole lot easier. Consider the following implementation of subroutine SEND_QUAN.
SEND_QUAN: DIGIT = QUAN DIG 3 ' isolate the thousands GOSUB SEND_ZIP DIGIT = QUAN DIG 2 ' remaining hundreds GOSUB SEND_ZIP DIGIT = QUAN DIG 1 ' tens GOSUB SEND_ZIP DIGIT = QUAN DIG 0 ' units GOSUB SEND_ZIP RETURNI have to give the Stamp designers a great deal of credit. However, the above is simply another implementation where the Parallax designers have done a bit of work for me. It remains important to note there is a difference between a digit and a nibble.
Back to the Program!
As each digit is isolated, subroutine SEND_ZIP which sends the number of beeps specified in DIGIT. Note that a DIGIT having a value of zero would result in no beeps which could cause a problem in interpretation by the person listening. Thus, if the value of DIGIT is zero, ten beeps are sent.
A familiar FOR NEXT loop is used. On each pass through the loop, a zip tone is sent;
FREQOUT 1, 200, 440 ' send a burst of 440HzThe first arguement is the pin. The next is the number of milliseconds and the final is the frequency. Thus, in this case, 200 msecs of 440 Hz on P1.
The duration may be up to 65,535 msecs, a bit over a minute, and the specified frequency may be up to 32,768.
This is a relatively simple routine that illustrates how various interesting sounds might be implemented.
The routine uses a FOR NEXT loop to generate 10 ms tones from 300 to 1300 Hz in steps of 10 Hz. This is repeated with the frequencies going from 1300 to 300 Hz.
' FREQ_2.BS2 ' ' Illustrates how interesting sounds may be implemented using the ' FREQOUT command. ' ' P. H. Anderson, 29 Nov 97 N VAR BYTE FREQ VAR WORD DIRS=$00FF TOP: FOR N= 0 TO 100 ' go up FREQ = 300 + (10*N) FREQOUT 1, 10, FREQ NEXT FOR N= 100 TO 0 ' go down FREQ = 300 + (10*N) FREQOUT 1, 10, FREQ NEXT 'PAUSE 1000 ' another second GOTO TOPProgram FREQ_3.BS2.
This program shows how a number of different "tunes" might be selected using switches on inputs P15 and P14.
' FREQ_3.BS2 ' ' Illustrates how a number of sequences of tones might be played. ' ' The sequence is selected by switches S15 and S14. ' ' FREQOUT command. ' ' P. H. Anderson, 1 Dec 97 N VAR BYTE FREQ_DIV_10 VAR BYTE FREQ VAR WORD DIRS=$00FF TOP: ' DEBUG HEX? IND BRANCH (IND>>2), [SONG0, SONG1, SONG2, SONG3] TOP_1: PAUSE 1000 GOTO TOP ' Play another song SONG0: FOR N=0 TO 3 LOOKUP N, [44, 55, 66, 77], FREQ_DIV_10 GOSUB PLAY_NOTE NEXT GOTO TOP_1 SONG1: FOR N=0 TO 7 LOOKUP N, [44, 44, 66, 66, 44, 44, 44, 66], FREQ_DIV_10 GOSUB PLAY_NOTE NEXT GOTO TOP_1 SONG2: FOR N=0 TO 5 LOOKUP N, [44, 00, 44, 00, 44, 00], FREQ_DIV_10 GOSUB PLAY_NOTE NEXT GOTO TOP_1 SONG3: FOR N=0 TO 7 LOOKUP N, [44, 00, 00, 00, 66, 00, 00, 00], FREQ_DIV_10 GOSUB PLAY_NOTE NEXT GOTO TOP_1 PLAY_NOTE: 'DEBUG ?FREQ_DIV_10 FREQ = FREQ_DIV_10 * 10 FREQOUT 1, 200, FREQ RETURNThe D input nibble is read and the states of IN15 and IN14 are mapped into a number, 0, 1, 2 or 3. The BRANCH command is then used to direct the program flow to the appropriate "song". Note that the "songs" may be of varying number of "notes" depending on the setting of the upper limit of N.
The frequency 0 is no tone for the defined period.
It is important to note that the LOOKUP command maps an index into an element which is copied to a variable and this variable is limited to a byte. Thus, the elements must be limited to the range of 0 to 255. Thus, such notes as 440 and 660 are defined in the lookup table as the 44 and 66. In subroutine PLAY_NOTE, this value is multiplied by ten.
Note that this byte limitation of the LOOKUP command may be overcome by using two lookup tables. For example, assume the desired sequence is;
1024, 660, 4283, 1024The following snippet of code illustrates how this may be implemented.
FREQ_HI VAR BYTE FREQ_LO VAR BYTE FREQ VAR WORD FOR N=0 TO 3 ' 4 tones LOOKUP N, [10, 06, 42, 10], FREQ_HI ' the high 2 digits LOOKUP N, [24, 60, 83, 24], FREQ_LO ' low 2 digits FREQ = 100 * FREQ_HI + FREQ_LO ' put them together FREQOUT 1, 200, FREQ NEXT