| Products | Support | Sales | Company | |
by Al Williams alw@al-williams.com
This is a reprint from AWC's Stamp Project of the Month column. You can find a different project each month on the Web at AWC's home page: http://www.al-williams.com/awce.htm. This article is copyright 1999 by Al Williams. All Rights Reserved.
This month, I want to show you the G12032 serial LCD from Scott Edwards Electronics (http://www.seetron.com). This LCD runs about $100 but it offers a wide array of text and graphics options. That's right; graphics on the Basic Stamp. The LCD can display 4x20, 4x10, 2x20, or 2x10 in text mode. You can also treat the LCD as a 120x32 pixel graphics array. You can even mix graphics and text on the same screen.
Everybody seems to enjoy the games, so this month's project is a Pong-style game. All you need is the LCD, a BS2, and two buttons wired to ground with pull up resistors.
When you start the game, it shifts the LCD into a large font and displays a "splash screen". When you press one of the buttons, you'll see your paddle appear. A little later, the puck starts coming towards you. You have to bounce it between the walls, the far wall and your paddle. When you hit the ball, your score will increase (indicated in the far right corner). When you miss, the game is over.
If you have the high score, you'll get to put your initials in (stored in EEPROM of course). Either way you'll see the high score before the game restarts.

Figure 1. The LCD mounted on a breadboard with our ASP-II adapter. The breadboard is from Elenco. You can see other projects here including the PocketWatch project from January, a serial EEPROM, and a PAK-I math coprocessor to the left. The only parts in use here are the LCD, the Stamp, and the two buttons to the right of the Stamp. The button above the Stamp is a reset switch and is semi-permanent. So is the 5V supply at the top left corner.
Figure 2. Close up of the splash screen
Figure 3. The game in play. The puck is the small dot slightly to the left of the score.
Programming the LCD for text is very simple. You just use SEROUT to write to it like a terminal. It recognizes several commands to display reverse text, change fonts, etc.
The fun part is when you start using graphics. The LCD can store several predefined graphics in its EEPROM. You can also define custom fonts. For the game, it is simple to just plot points. The LCD can also graph lines.
The display normally just writes out ASCII
text. It also recognizes the usual control characters like
carriage-return, line feed, etc.
[NOTE: A complete list of control characters and graphics instructions
appears on the G12032 description page. We've edited out Al's summary of the instruction set to save space. --Seetron]
There is one point that took me awhile to
figure out. Sometimes when I would start the program, the
player's paddle would be missing until you started moving it. It
turns out that when the Stamp restarts, it might have been in the
middle of doing something with the LCD. If that something had the
ink set to white, the paddle wouldn't show up initially. The same
problem can keep the screen from clearing if the ^L occurs when
the LCD is expecting other input. Since there is no arbitrary reset for the
LCD, I found it useful to clear the screen 3 times and set the
ink to black at the start of the program. While this probably
isn't foolproof, for this program it did prevent the LCD from
getting confused. Update: Scott Edwards has pointed
out to me that a more efficient way to do this is to send the
byte 64 ("@") 4 times followed by a clear screen. My
way works, but takes more execution time (not a problem in this
case so I left it alone). Thanks Scott! If you have one of these nifty displays,
you might consider adding some features to the game. Sound would
be nice. It would be really interesting to make the ball speed up
with time or allow the user to select the starting speed. You
might even want to make the puck bounce around the score instead
of eating away at it. One thing I want to do is to interface a
Sega controller to the Stamp and use it instead of buttons. The
Sega controller uses a DB9 connector and there have been several
articles in Nuts & Volts that reveal its pin out. AWC
More Fun
The Code
' Pong - push button version
' Al Williams
leftkey var in8
rightkey var in9
lbutton con 8
rbutton con 9
baudrate con 16468
lcdport con 6
misses con 1 ' # of misses before game is over
player var word ' player's position (X)
tick var byte ' tick count through the loop
puckx var word ' puck x and y position
pucky var word
deltax var word ' deltax and deltay
deltay var word
accx var word ' error accumulators for x & y
accy var word
lastx var word ' last drawn position for erase
lasty var word
rword var word ' random word
sign var word ' direction of delta
hitct var byte ' number of hits
miss var byte ' number of misses
' The high score stuff needs
' variables but not at the same time
' so we will reuse them
hiscore var player.lowbyte
init1 var rword.lowbyte
init2 var rword.highbyte
init3 var miss
letter var player.highbyte
begin:
tick=0
pause 100 ' wait for LCD to catch up
' repeat in case we reset in the mid of graphics
serout lcdport,baudrate,[12,12,12,14] ' clear screen & backlite on
' Should select black ink just in case
serout lcdport,baudrate,[27,"I",65]
serout lcdport,baudrate,[27,"F",66] ' big font
serout lcdport,baudrate,[2," Pong by AWC! ",3," Press a key"]
gosub keywait
hitct=0
miss=0
gosub clslcd
for player=0 to 9
serout lcdport,baudrate,[27,"P",player+64,31+64]
next
player=0 ' initial pos
top:
pause 20
tick=tick+1
if tick<>150 then noinit
gosub puckinit
noinit:
if tick<150 then nopuck
tick=150 ' no use letting it roll over
gosub advpuck
gosub drawpuck
gosub hittest
nopuck:
if leftkey=0 then left
rword=rword+1 ' randomize
if rightkey=0 then right
rword=rword+2
goto top
' move player right 2 spaces
' this makes player move faster than puck
' this is in 2 steps so we are sure we
' don't roll over the edge
' if you want a more challenging game
' remove one move below
right:
gosub rightmove
gosub rightmove
goto top
' move player left 2 spaces
' this makes player move faster than puck
' this is in 2 steps so we are sure we
' don't roll over the edge
' if you want a more challenging game
' remove one move below
left:
gosub leftmove
gosub leftmove
goto top
' Actual right move logic
rightmove:
if player>=108 then rightret
serout lcdport,baudrate,[27,"I",64]
serout lcdport,baudrate,[27,"P",player+64,31+64]
serout lcdport,baudrate,[27,"I",65]
serout lcdport,baudrate,[27,"P",player+10+64,31+64]
player=player+1
rightret:
return
' Actual left move logic
leftmove:
if player=0 then leftret
serout lcdport,baudrate,[27,"I",64]
serout lcdport,baudrate,[27,"P",player+9+64,31+64]
serout lcdport,baudrate,[27,"I",65]
serout lcdport,baudrate,[27,"P",player-1+64,31+64]
player=player-1
leftret:
return
' Initialize puck parameters
puckinit:
puckx=1
pucky=1
deltax=1
deltay=1
accx=0
accy=0
return
drawpuck:
' Don't erase player!
if lasty=31 and lastx>=player and lastx<player+10 then noclear
' Set ink to white and erase puck
serout lcdport,baudrate,[27,"I",64]
serout lcdport,baudrate,[27,"P",lastx+64,lasty+64] ' clear old puck
' Set ink to black again
serout lcdport,baudrate,[27,"I",65]
noclear:
' Draw puck
serout lcdport,baudrate,[27,"P",puckx+64,pucky+64]
' Remember where
lastx=puckx
lasty=pucky
return
' Advance puck
' Since X and Y may not increase each time
' the puck's speed depends on its angle
' To make the speed constant, you'd need
' to know which was changing more rapidly: X or Y?
advpuck:
accx=accx+1
accy=accy+1
if accx<>abs(deltax) then noxadv
sign=1
' Note: can't say deltax<0 because compare is unsigned
if deltax<$8000 then xsgn
sign=-1
xsgn:
puckx=puckx+sign // 120
accx=0
noxadv:
if accy<>abs(deltay) then noyadv
sign=1
if deltay<$8000 then ysgn
sign=-1
ysgn:
pucky=pucky+sign // 32
accy=0
noyadv:
return
hittest:
if pucky=0 then hit ' bounce off top
' Hey the player hit it!
if pucky=31 and puckx>=player and puckx<=player+10 then hit
' bounce off sides
if puckx=0 or puckx>=119 then bounce
' Not close to player yet
if pucky<>31 then nohit
' missed!
miss=miss+1
if miss=misses then gover ' end game?
pucky=0 ' wrap around
return
bounce: ' bounce off sides by reflection
deltax=-deltax
if puckx=0 then x1
puckx=118
goto x118
x1:
puckx=1
x118:
accx=0
return
' Player hit or hit top
hit:
' need to reflect puck
deltay=-deltay
if pucky=0 then y1 ' top hit
pucky=30
' player hit it so count it
hitct=hitct+1
' Show score
' Note -- the puck erases this score as it
' moves through it -- could make a bounce
' around the score, or omit completely
serout lcdport,baudrate,[16,64+20-3,dec3 hitct]
' Add some random english to the puck
random rword
deltay=deltay ^ (rword & 3)
' If you make deltax a constant at 1
' (remove next 2 lines) the game is faster
random rword
deltax=deltax ^ (rword>>2 & 3)
' Disallow x=0 y=0 so we don't get caught
if deltax<>0 then dxnz
deltax=1
dxnz:
if deltay<>0 then dynz
deltay=1
dynz:
goto y31
y1:
pucky=1
y31:
accy=0
nohit:
return
' GAME OVER!
gover:
gosub clslcd
serout lcdport,baudrate,["Game over",13,"Score=",dec hitct]
' check saved hiscore
read 0,hiscore
gosub keywait
serout lcdport,baudrate,[27,"F",64] ' norm font
' This guy is not king of the hill so say who is
if hiscore>=hitct then showhs ' no high score
' Big winner -- get his name
serout lcdport,baudrate,[12,"High score!",13,"<- change -> accept",13]
' reuse variables (see top of code)
init1="A"
init2="A"
init3="A"
' Don't clear the button workspace
' inside GetLet or the 2nd and 3rd calls will not work
' right
accx=0 ' used as button workspace
letter=init1 ' Get all 3 letters (could use an array)
gosub getlet
init1=letter
letter=init2
gosub getlet
init2=letter
letter=init3
gosub getlet
init3=letter
' Write high score info
write 0,hitct
write 1,init1
write 2,init2
write 3,init3
' Show high score
showhs:
read 0,hiscore
read 1,init1
read 2,init2
read 3,init3
serout lcdport,baudrate,[12,"High score: ",dec hiscore,13," by ",init1,init2,init3]
gosub keywait
goto begin ' start over
' Wait for a key
keywait:
if leftkey=0 or rightkey=0 then keywait
kw22:
if leftkey=1 and rightkey=1 then kw22
kwait3:
if leftkey=0 or rightkey=0 then kwait3
return
' Get a letter arcade style
getlet:
serout lcdport,baudrate,[letter]
getletl:
pause 5 ' some time for button loop
button lbutton,0,100,50,accx.highbyte,1,nxtlet
button rbutton,0,255,0,accx.lowbyte,1,nxtslot
goto getletl
nxtlet:
letter=letter+1
if letter=$21 then LetA ' A follows Space
if letter<="Z" then letdisp ' Space follows Z
letter=" "
goto letdisp
letA:
letter="A"
letdisp:
serout lcdport,baudrate,[8,letter]
goto getletl
nxtslot:
return
clslcd:
serout lcdport,baudrate,[12] ' clear game
return
310 Ivy Glen Ct.
League City, TX 77573
Scott Edwards Electronics Inc.
1939 S. Frontage Rd. #F, Sierra Vista, AZ 85635
phone 520-459-4802; fax 520-459-0623
e-mail info@seetron.com