Products Support Sales Company Scott Edwards Electronics, Inc.

Fun with the G12032 Serial Graphics LCD

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.

Software

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.

Details

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!

More Fun

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.

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

AWC
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