Basic Starter Package - Tutorial #4

Generating Frequencies

copyright, Peter H. Anderson, Dept of EE,
Morgan State University, Baltimore, MD, Dec 2, '97

Introduction.

This tutorial focuses on using the Stamp to generate frequencies.

Wiring Configuration.

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.

Program FREQ_1.BS2.

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 end
might 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
	RETURN
The "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
  etc
Why 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 0011
Thus, 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 0000
it 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;

	
	$5390
But, 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 = 4053
The 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 0
the 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.

Note.

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

	RETURN
I 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 440Hz
The 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.

Program FREQ_2.BS2.

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 TOP
Program 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
 	RETURN
The 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, 1024
The 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