Basic Starter Package - Tutorial #1

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

Note.

The Basic Starter Package includes a number of tutorials. The intent is to teach the user how to effectively use the Stamp in the context of various applications.

Some may find this first tutorial rather trivial. However, what is trivial to an experienced user may well be quite useful to a newcomer. The tutorials become increasingly advanced.

Routines were verified and corrected on Dec 2, '97.

Initial Ouput Routines.

At this point you have assembled the power supply, made the necessary connections from the serial port cable to the Stamp and have assembled and tested the logic probe.

Lets forge ahead and write some simple programs to flash a a single LED. In doing so, I hope to get across many of the PBASIC commands in a simple context which is understandable.

Please refer to Figure #1. Note that this consists of the addition of a single LED from P0 (Terminal 5) on the Stamp to ground. Note that the LEDs supplied with the Basic Starter package have an integrated 330 Ohm resistor to limit the LED current to nominally 10 mA.

The idea is to force a logic one on an ouput for a period of time, thus turning the LED on. And then, output a zero for a period of time, causing the LED to turn off.

Program LED_1.BS2

' LED_1.BS2
'
' Flashes an LED on Output 0 on and off
'
' Peter H. Anderson, MSU, 25 November, '97
'

TOP:

	DIR0=1		' make P0 an output
	
	OUT0=1		' turn on the LED
	PAUSE 500	' pause for 500 msecs
	
	OUT0=0		' turn off the LED
	PAUSE 500

	GOTO TOP

Note that an "'" indicates that all that follows on the line is a comment. Although not required, good programmers spend a bit of effort briefly describing the overall operation of the program and include annotations within the code to give the reader a clear idea of what the statements are doing.

The word TOP is a label, in this case, a place in the program. Labels can be virtually anything other than specific key words.

Each of the 16 I/O pins on the Basic Stamp may be configured as an input or as an output. The Stamp reserves a 16-bit variable DIRS with the state of each bit being used to confgure that pin as either as an input or an output.

Specific bits, may be selectively configured using the DIRp nomenclature. That is, DIR0 or DIR7 or DIR15. A one configures the bit as an output. Thus;

	DIR0=1	' make pin 0 an output
	DIR7=0	' make pin 7 an input
The Stamp reserves another 16-bit variable termed OUTS and here again, each of the specific pins may be addressed using OUTp; e.g., OUT0.

In this case;

	OUT0=1 	' copy a one into bit OUT0
	OUT0=0	' copy a zero into bit OUT0
Note that the pin will only assume the designated state if the associated DIR bit is defined to be an output.

The PAUSE command is pretty obvious. Note that the time is in milliseconds. The maximum value is 2^16-1 or 65,535. Thus, using the PAUSE, the largest delay one could achieve is nominally 60.5 seconds.

The GOTO redirects the program flow to the designated label. Thus, in this case, the program simply loops, continually flashing the LED.

Program LED_2.BS2

' LED_2.BS2
'
' Flashes an LED on Output 0 on and off.  Simply another implementation of
' LED_1.BS2.
'
' Peter H. Anderson, MSU, 25 November, '97
'

	OUT CON 1	' define the word OUT to be the same as 1
	DELAY_TIME CON 500

	DIR0=OUT
TOP:

	HIGH 0		' turn on the LED
	
	PAUSE DELAY_TIME' pause for 500 msecs
	
	LOW 0		' turn off the LED
	PAUSE DELAY_TIME

	GOTO TOP

Note that a number of changes have been made. However, the program does the same thing.

The concept of constants has been introduced using the keyword CON. These are nothing more than constants which are substituted into your code.

In the first program;

	DIR0=1
forced pin 0 to be an output. However, I always tend to forget whether it is a zero or a one and thus I use a standard set of constants that I cut and paste from one program to another. Thus;
	OUT CON 1
simply means, to substitute a "1" where the word OUT appears in the program.

Similarly, substitute 500 wherever the the word DELAY_TIME appears.

Note that the DIR0=1 has been pulled out of the loop, and is now executed only one time when the program begins. Once the direction of a bit has been defined, there is no need to continually do so as was done in the first program.

The commands HIGH and LOW followed by the pin number are simply alternative representations of the OUT command;

	HIGH 0		' same as OUT0 = 1
	LOW 0		' same as OUT0 = 0
Program LED_3.BS2.
' LED_3.BS2
'
' Flashes an LED on Output 0 on and off 50 times
'
' Peter H. Anderson, MSU, 25 November, '97
'

TIMES 	VAR BYTE

	OUT     CON 1	' define the word OUT to be the same as 1
	LED	CON 0	' LED is on pin 0
	DELAY_TIME CON 500

	DIR0=OUT

TOP:

	FOR TIMES = 1 TO 50
	   HIGH LED		' turn on the LED
	   PAUSE DELAY_TIME	' pause for 500 msecs
	
	   LOW LED		' turn off the LED
	   PAUSE DELAY_TIME
	   DEBUG ?TIMES
	NEXT   

	DEBUG "Done!"

DONE:
	GOTO DONE

In this program, the variable TIMES has been declared as a byte (8 bits). Note that a byte may accommodate the numbers 0 through 255 and in this application where the highest value is 50, a byte is sufficient. If I desired to flash the LED a 1000 times, the variable would have been declared as a "word" which is two bytes. A word can accommodate values from 0 to 65,535.

Note that an additional constant has been defined; LED. Rather than burdening one's mind with the fact that the LED is on pin 0, this simple idea of a constant permits you to make that connection just once and then refer to the pin as simply "LED". As we only are using one lead at this point, the advantage may not be obvious, but it will when we begin to use many of the 16 inputs and outputs.

Program LED_3 introduces the use of the FOR - NEXT command. In this context, the commands between the FOR and the NEXT are executed with TIMES equal to 1, and then with TIMES equal to 2, etc until TIMES is equal to 50. TIMES is then incremented to 51, which is beyond the upper bound (50) and the program thus breaks from the FOR loop.

Note that on each pass through the loop, the LED is flashed and, in addition the value of TIMES is displayed on the terminal using the DEBUG command.

The DEBUG command allows you to print values and text to the terminal. Future programs will treat this in much greater detail. For the moment;

	DEBUG "Hello", CR	' prints Hello followed by a new line

	DEBUG DEC TIMES		' prints the value of TIMES is decimal
				' not there is no new line

	DEBUG "N=", DEC TIMES CR
		' prints TIMES=value.  For example TIMES=33

	DEBUG ?N	' this is a much simpler shorthand for the above
After breaking from the FOR - NEXT loop, the program displays a "Done" message and then continually loops doing nothing.

Program LED_4.BS2.

' LED_4.BS2
'
' Flashes an LED on Output 0 on and off 50 times.  Uses a subroutine
'
' Peter H. Anderson, MSU, 25 November, '97
'
	
TIMES 	VAR BYTE

	OUT     CON 1	' define the word OUT to be the same as 1
	LED	CON 0	' LED is on pin 0
	DELAY_TIME CON 500

	DIR0=OUT

TOP:

	FOR TIMES = 1 TO 50
	   GOSUB FLASH
	NEXT   

	DEBUG "Done!"

DONE:
	GOTO DONE


FLASH:		' winks LED on and off one time

	HIGH LED		' turn on the LED
	PAUSE DELAY_TIME	' pause for 500 msecs
	
	TOGGLE LED		' turn off the LED
	PAUSE DELAY_TIME
	DEBUG ?TIMES
	RETURN
Note that the FOR loop is now reduced to simply a "call" or GOSUB to subroutine FLASH. In the subroutine, the LED is turned on, there is a pause, and then the LED lead is toggled. That is, as the current state of the LED lead is high, the TOGGLE results in bringing it low. If it were low, TOGGLE would bring the lead high.

The RETURN statement then causes the program to return to the statement after the GOSUB.

In calling (GOSUB) a subroutine, the return address is pushed on to a stack. When the RETURN is executed this return address is pulled from the top of the stack. Fortunately, this is all hidden from the Stamp user, but the general mechanics are important in appreciating the following limitations.

A subroutine must be called (GOSUB). You cannot GOTO a subroutine, as with a GOTO, the return address is not pushed on to the stack. Thus, in executing the RETURN, whatever junk happens to be on the top of the stack will be pulled and the program will, in theory, continue at that junk address and your program will not work properly.

Along the same line, your subroutine must not be in the program flow of other routines. An example is illustrated in LED_4A.

' LED_4A.BS2 (This routine illustrates a common error.  It will not work).
'
' Flashes an LED on Output 0 on and off 50 times.  Uses a subroutine
'
' Peter H. Anderson, MSU, 25 November, '97
'
	
TIMES 	VAR BYTE

	OUT     CON 1	' define the word OUT to be the same as 1
	LED	CON 0	' LED is on pin 0
	DELAY_TIME CON 500

	DIR0=OUT

TOP:

	FOR TIMES = 1 TO 50
	   GOSUB FLASH
	NEXT   

FLASH:		' winks LED on and off one time

	HIGH LED		' turn on the LED
	PAUSE DELAY_TIME	' pause for 500 msecs
	
	TOGGLE LED		' turn off the LED
	PAUSE DELAY_TIME
	DEBUG ?TIMES
	RETURN

	DEBUG "Done!"

DONE:
	GOTO DONE
Note that this program is wrong. The LED will indeed flash the 50 times. However, on exiting the FOR - NEXT loop, the program will enter the subroutine. Note that there has been no call (GOSUB). The LED will again flash (for the 51st time). However, on executing the RETURN, the top of the stack does not contain a valid return address and your program will go to off to "never never land".

Finally, you must RETURN from a subroutine. Consider the following very incorrect routine.

' LED_4B.BS2  (This routine illustrates another common error.  It will not
' work.)
'
' Flashes an LED on Output 0 on and off 50 times.  Uses a subroutine
'
' Peter H. Anderson, MSU, 25 November, '97
'
	
TIMES 	VAR BYTE

	OUT     CON 1	' define the word OUT to be the same as 1
	LED	CON 0	' LED is on pin 0
	DELAY_TIME CON 500

	DIR0=OUT

TOP:
	FOR TIMES = 1 TO 50
	   GOSUB FLASH
AGAIN:
	NEXT   

	DEBUG "Done!"

DONE:
	GOTO DONE


FLASH:		' winks LED on and off one time

	HIGH LED		' turn on the LED
	PAUSE DELAY_TIME	' pause for 500 msecs
	
	TOGGLE LED		' turn off the LED
	PAUSE DELAY_TIME
	DEBUG ?TIMES
	GOTO AGAIN		' !!!!!!!!!! wrong!

In ths incorrect routine, the FLASH routine is called with a GOSUB and the return address is pushed on to the top of the stack. However, at the conclusion of the FLASH routine, I have erroneously used a GOTO. Thus, the return address is not pulled off the top of the stack. The routine is again called, but there is no corresponding pull in the subroutine. Thus, the stack is growing and growing and eventually, your program will stop working.

In summary, when using subroutines, be certain that the only way the program enters the subroutine is with a GOSUB. No GOTOs and no "walk-ins" as illustrated in routine LED_4B. Be certain to use a RETURN to go back to the calling program.

Note that in program LED_4, the DEBUG ?TIMES was included in the subroutine to make a point. All variables in PBASIC are global. That is, the variables are known to all subroutines.

Program LED_5.BS2.

Consider rolling a die. This generates a random number in the range of 1 to 6. Roll a second die, generating a second number. Sum them and wink the LED that number of times. This might be used as a rather expensive and inferior replacement for rolling dice as in playing Monopoly, Parchesi and other less redeeming games of chance. I say all of this with tongue in cheek, but the routine helps to make a number of points.

' LED_5.BS2
'
' Flashes an LED on Output 0 on and off the number of times "rolled" by
' two dice.
'
' Peter H. Anderson, MSU, 25 November, '97
'

DIE_1	VAR BYTE	' first DIE
DIE_2	VAR BYTE	' second DIE
DICE	VAR BYTE	' total

R 	VAR WORD	' random number in range 0-65,535

TIMES 	VAR BYTE	' flash counter	

	OUT     CON 1	' define the word OUT to be the same as 1
	LED	CON 0	' LED is on pin 0
	DELAY_TIME CON 500

	DIR0=OUT

TOP:
			
	LOW LED		' be sure the LED is off

	RANDOM R	' R is now 0 - 65,535
	DIE_1 = (R // 6) + 1	' roll first die
	RANDOM R
	DIE_2 = (R // 6) + 1	' roll the second

	DICE = DIE_1 + DIE_2
	
	GOSUB WINK	   ' wink LED DICE times

	DEBUG "Done!"

DONE:
	GOTO DONE

WINK:	' flashes LED DICE times

	FOR TIMES=1 TO DICE
    	   GOSUB FLASH
	NEXT
	RETURN

FLASH:	' winks LED on and off one time

	HIGH LED		' turn on the LED
	PAUSE DELAY_TIME	' pause for 500 msecs
	
	TOGGLE LED		' turn off the LED
	PAUSE DELAY_TIME

	RETURN
The RANDOM command generates a number in the range of 0 - 65,535 and places the result in variable R. Note that R has been declared as a word to accommodate this.

The "//" is the mod operator. Somewhere back in junior high, you probably had such exercises as 12323 divided by 6 = 2053 with a remainder of 5. The mod operation is simply the remainder. Thus R // 6 generates a number in the range of 0 to 5. Adding one gives a random number in the range of 1 to 6.

This operation is performed twice to provide values for DIE_1 and DIE_2. The results are summed (DICE) and subroutine WINK is called which in turn calls subroutine FLASH, DICE times.

Note that in this example, the FOR loop takes a variable.

There is a flaw in this program in that it will always produce the same "random" numbers. The command RANDOM takes the arguement, in this case variable R and operates on it so as to produce a pseudo random number. In this program, the initial value of R is 0 and thus the RANDOM command will always produce the same random R, and thus DIE_1 will always be the same. This value of R is then used to calculate another value of R, but it will also always be the same and thus DIE_2 will always be the same. None too practical, but I like the program as it shows the use of the RANDOM function, the mod operator, nested subroutines and the use of a variable in a FOR-NEXT loop.

This problem of lack of randomness can be corrected by intializing R to some random value. A common technique is to use time and this will be presented in a future tutorial.

Summary.

All of this has used only one LED which is none too interesting.

However, I am hopeful you have an appreciation for the direction control DIRS, and controlling the direction of a specific bit (DIR0). You know how to define a constant using CON, how to declare a variable using VAR and the difference between a byte and a word. You should know what a label is. All outputs are referred to as OUTS, but a specific bit may be referenced as OUT0. The commands GOTO, FOR-NEXT, HIGH, LOW, TOGGLE and PAUSE have been treated. The commands GOSUB and RETURN have been discussed and hopefully you appreciate the mechanics of subroutines.