Build a Custom Controller with a Color LCDPeter built a custom controller that enables him to remotely
control his animatronic systems. Each piece of hardware is
controlled by a separate computer program. The remote polls his
laptop and builds menus that show and control the state of each
program.
Every year, I put on an elaborate Halloween show in my front yard
(see Photo 1)。 Being electronically minded,my fully automated show
includes a talking skeleton and crow, sound effects, and more. (In
Circuit Cellar Issue 188, 2006, I described the animatronic
controller I built for operating and controlling the props.) My
system uses a laptop to coordinate the show,and it talks to several
distributed microcontrollers via an RS-485 serial link. A custom
packet format and messages enable PC programs to control the
distributed hardware. It works great once it‘s dialed in, but
getting it dialed in can be difficult.

Last Halloween, I experienced some problems. The show wasn't
working properly and I was going nuts trying to fix it. I found
myself running maniacally back and forth from my house to the yard.
Why? The computer used to control the show was inside and the
hardware was outside. Plus, because I had darkened and covered my
windows to make the house look spooky,I couldn‘t see or hear what
was going on outside. Thus, trying to set the appropriate levels
for sound and lighting was a nightmare.
Prior to last year's show, I had been thinking about building a
remote control that would enable me to modify the running show from
outside by plugging into the same RS-485 network that controls
everything. However, I knew building such a system would be tricky.
One of the hallmarks of the Halloween control system is that there
is not one monolithic program running on the computer that controls
everything. Instead, individual programs run independently that
conform to the rules of my Halloween serial network. This enables
them to send and receive packets,control hardware nodes, and play
sound files as needed. Thus, while considering my options, it
became obvious that building a "hard-wired" remote control to
handle the show wouldn't work. I knew I needed to be able to add
and subtract programs at any time, so designing a remote dedicated
to a specific program(or programs) would mean I‘d have to
constantly modify the firmware to keep it in sync with the
ever-changing computer software.
I recently designed a dynamic remote control that meets all of my
requirements (see Photo 2)。 The remote can connect to the
network,control programs on the computer,and handle new programs.
It can poll the computer, find running programs,poll the PC again
after program selection,and then build menus on the fly to show
program status and enable modifications.
In this article, I'll describe how I designed the custom controller
with its color LCD. Next month, I‘ll cover the software and menu
code.
DYNAMIC SYSTEM
I wanted to design a dynamic system. Years ago, Apple created a
specification called Publish/Subscribe. I always liked the sound of
that because it seemed clear what was going on just by the name. I
co-opted the name and created a Publish/Subscribe system that
integrates into my Halloween serial network.
When I started this project, I figured that I could bang out the
design in a few weeks, especially because I was leveraging so much
software that was already written. Right. It took me more like
three months. It was trickier than I thought for a number of
reasons.
My original plan was to support only a few GUI elements on the
PC,such as the scrollbar, checkbox, and combo box. I also decided
at the beginning that the menu system displayed on the remote would
have a limited depth and hierarchy. My initial plan was to have a
top-level menu that enables me to tell the remote to find programs
running on the PC and then click down a level to see them. It would
look something like what you see in Figure 1a.

That changed. Once I got the initial system up and running, I
realized that I needed to support a few more GUI elements. I also
realized that I wanted to have a submenu of parameters. This way, I
figured, I would be able to group things more logically. I decided
that a single submenu down would be sufficient to let me group
together various elements. I thought this would be relatively
simple to implement because the specifications were limited (see
Figure 1b)。That also changed. Again, once I got the basic two-level
system up and running, I quickly realized how useful it would be to
have a much deeper and more flexible menu system. I wanted the
flexibility to lay out any menu system I pictured in my head. Tests
with some fake prototype PC programs showed me that I would need to
expand the number of GUI elements supported. So, I plunged into the
third rewrite of the menu system.
Some engineers would see this as"feature creep." I disagree with
this assessment because the original problem was that I thought I
could get away with something that was simple to program, when in
reality, I needed something that was simple to use. Forcing all of
the controls onto a single scrolling menu page would mean a lot of
scrolling up and down when looking for parameters to modify. There
is often an inverse relationship between ease of use and ease of
programming. This was just another example of this paradox.
DESIGNING THE REMOTEOne of the first tangible things I did was mock-up the remote using
CodeGear‘s Delphi (see Photo 3)。 The interface builder in Delphi is
simple to use. (There are others, but I prefer Delphi.) It enables
me to play "whatif"games quickly. My goal was to figure out what
the remote‘s front panel was going to look like. I knew that it
would have an LCD. I also knew it would have buttons. The questions
were: How many buttons, and what would they do? Would I need a full
10- key keypad? What about an Enter key notifying the remote about
a chosen value?

After some experimentation, I came up with the design shown in
Photo 2. The remote has an LCD at the top and three buttons
arranged vertically below it. The buttons are labeled Back, Menu,
and Value (from top to bottom)。 What isn‘t shown is that the actual
remote also features a scroll wheel on the side. It's implemented
as a knob attached to a rotary encoder. Ironically, some time after
I finalized this design, my wife gave me an Apple iPod nano. I
realized after playing with it that the Apple designers used a
similar concept. It‘s always nice to know you're in good company.
No aspect of the interface was random. I put the scroll wheel on
one side and the buttons on the other. So, I don‘t have to choose
between the buttons or the scroll wheel. I can work both at the
same time. The buttons are arranged vertically so I can reach them
by simply moving my thumb without shifting my grip. As for moving
through the menu, I descend down and ascend out of it. Thus, the
Back button is at the top so I"ascend" to return. The middle button
is the Menu button, which lets me descend down to deeper menus. The
physical relationship between these two buttons suggests the
up/down nature of traversing the menu hierarchy.
The Value button at the bottom enables me to modify parameter
values. The button is implemented as a shift style key because it
modifies the behavior of the scroll wheel. If the key is up, the
scroll wheel moves a highlight up and down the menu to let you know
which line is active. If you hold the Value key when you're located
on a parameter, moving the scroll wheel modifies the parameter‘s
value. To keep the remote simple, I didn't include Enter and Cancel
keys. This isn‘t a fighting video game, so elaborate key
combinations are not the order of the day. I wanted a an
easy-touse,clean, simple, elegant design. I succeeded.
THE DISPLAY
I have been using LCDs in my projects for years; however, they've
always been black and white character displays. For this project, I
upped the ante. I used a graphical color LCD.
Prior to starting this project, I‘d seen some reasonably priced
LCDs advertised in magazines and on the Internet. How hard could it
be to find the right one? It was hard-well,at least harder than I
thought it would be. The problem with many advertisements is that
the fine print tells you that the great price is available only if
you're buying 1,000 or more units. There are a lot of
interesting,inexpensive surplus LCDs for sale on the Internet. The
problem,however, is that you get only an LCD. In some cases, they
come with PCBs with LCD driver chipsets. That‘s a move in the right
direction,but it still requires you to locate the chipset's
datasheet, figure out how to program it, and then write code from
scratch just to do things like draw a straight line. You can see
why black and white character LCDs are so appealing.
Fortunately, I discovered Display3000,an Internet LCD vendor
located in Germany. While the name may sound like something from an
infomercial,the web site promised a good product at a good price.
Specifically, I got a 2.1″ diagonal, 16-bit color LCD with a
backlight. The display came with a small carrier board that did all
of the required level shifting, enabling me to send data signals
from 2.5 to 15 V and power the backlight with anything from 5 to 18
V. It also came with source code in both BASIC and C,which
implemented a driver that included support for lines, circles,
rectangles,bitmaps, and fonts. It was driven via a SPI, so it
didn‘t take too many I/O lines. It cost me about $100 with
shipping.
I was pleased when the LCD arrived. In addition to the full driver,
I got a super-simple driver that implements the SPI as a few
bit-banged I/O lines and displays only a yellow background with a
blue line in the center. It really helps to have something dead
easy to help get the display up and running on your platform. In my
case, I was using a Zilog Z8 Encore. The C code from Display3000
was specifically written for the Atmel processor line. After using
Google to figure out what some of the Atmelspecific macros were
doing, I was able to get the simple driver up and running in a
short amount of time.
The display was kind of slow due to the bit banging, but it enabled
me to have a framework that I knew worked. From there, I switched
it over to using the Z8 hardware SPI. When that was working, I took
the SPI-specific code (software and hardware versions) and swapped
them into the full driver code. I then got the software SPI version
of the full driver working and finally switched it over to the
hardware SPI. It was a nice, logical progression that took me from
simple to full-blown over a couple of sessions of work without
getting me too frustrated in the process.
Once I knew how to control the Display3000 LCD, I decided to create
a serial backpack for it (see Figure 2)。Rather than have the LCD
attached directly to the project via the SPI lines, I wanted a
separate processor to run it via high-level commands sent over a
UART. A big part of my reason for doing this was that I knew the
menu system of the remote was going to require a lot of RAM, and
the display system for the LCD would require the same. By splitting
it into two separate projects, I got the full complement of RAM for
each project because each had its own Z8 running it.

Before I got the color LCD, I borrowed an old Scott Edwards
Electronics serial black-and-white graphical LCD from my friend Jon
Williams. I used it for early prototyping. It was a 128 × 64 pixel
display that also implemented a 4 × 16 text font and ran at 9,600
bps. It didn‘t take long to get it up and running. I decided early
on to isolate the details of the LCD commands from the overall
remote project by creating an LCD abstraction library. The idea was
to have the remote call the library for doing things like clearing
the display,setting a cursor position, writing text, and more. The
library would take care of the LCD-specific commands needed to
implement numerous functions. It would enable me to swap in a
different LCD by simply taking the existing library and modifying
it to speak whatever native commands the new LCD required.
This abstraction layer turned out to work beautifully. Once I had
the Display3000 serial backpack code working, I took the LCD
abstraction library for the Scott Edwards LCD and, in literally 10
min., converted it to use the commands needed for my Display3000
LCD serial backpack. There was more work required after that to add
features (such as setting colors, something the black and white
display didn't need), but it was cool to have the color LCD showing
the menus for the remote in such a short amount of time.
THE MAIN BOARD
While I was waiting for the LCD to arrive from Germany, I used the
Scott Edwards display and forged ahead with my main project board.
A month earlier,I had created a simple demonstration PCB for the
64K series of Zilog Z8 Encore chips. (The chips are a perfect fit
for most of my projects because they have a lot of RAM by embedded
standards.) I used a Z8F421, which has 48 KB of flash EEPROM and 4
KB of RAM (see Photos 4a and 4b)。 Most similar controllers from
other companies tend to have only 2 KB of RAM. Because this project
involved a lot of serial communication (multiple RAM ring buffers)
and a dynamic menu system (the menus were created in RAM), I needed
as much RAM as possible.

It‘s a bonus that Zilog offers development kits at amazing prices
($50)。 The development kit I used comes with a serial or USB
programmer/debugger,along with a full-blown IDE and C compiler.
Unlike many other companies,the Zilog compiler doesn't become
feature-limited after a certain number of days. It offers free
upgrades,and Zilog has upgraded the IDE and compiler multiple times
over the years. This is not a dead-end product.
After getting the code working and stable on my demonstration
board, I created a new hardware design just for the remote. I found
an extremely cool-looking case from OKW
Enclosures(www.okwenclosures.com), and I wanted a board that was
custom fit to it. I decided to go for broke and use the
surface-mount version of the Z8, even though it also comes in PLCC
and DIP packages. The Z8 runs on 3.3 V, so there is a simple 3.3-V
linear regulator, along with the Z8F421, an 18.432-MHz oscillator,
a Maxim Integrated Products MAX3491 RS-485 transceiver, various I/O
connectors,and the push buttons for the interface. The main
schematic for the remote is shown in Figure 3. The RS- 485 circuit
for the remote is shown in Figure 4.
Figure 3-This is the top-level schematic for the remote.
Like most of the boards I lay out, I put in some "future proofing."
Even though I needed only a single column of three buttons, I put a
matching column on the other side of the PCB in case I want more
buttons. I also added a 2 × 8 0.100″ center header that carries the
I/O pins for port E. It takes a little extra time to route these
devices on the PCB, but they come in extremely handy after the PCB
is fabricated and you want to add a new feature.
One element of this PCB made it slightly tricky. I checked and
found out that there wasn‘t a lot of room between the PCB and the
top of the OKW case. While there was plenty of space for the
switches and ICs, things like jumpers or bulky connectors could get
dicey. So, I decided to lay out the board with the switches and
power LED on top and all of the other components on the bottom.
Routing got a little weird. I had to keep reminding myself that
even though two package outlines crossed each other, it wasn't a
problem because they were on opposite sides of the board.
I/O CODE
I wrote my own serial library to run on the Z8. It understood how
to send and receive the packets used in my Halloween network long
ago. With some basic modification, I also created a text-specific
serial library. The first bit of truly new code was written to
support the scroll wheel. I perform quadrature decoding of the
encoder using two I/O lines and a hardware timer running at 30 kHz.
Whenever the timer generated an interrupt, the interrupt handler
reads the state of the encoder, merges it with the state of the
encoder from the previous interrupt shifted to the left two bit
positions, and feeds that into a look-up table. The look-up table
and code to use it look like Listing 1.

The look-up table and the timer effectively oversample the encoder
output. They also determine not only which way the encoder is
turning,but also if the transition from the previous state to the
current state is legal or bogus. This eliminates any problems that
occur if the encoder stops with the disk partially covering the
optical sensor. This can create a condition where the clock toggles
high/low, making it seem as though the encoder is moving when it‘s
simply the electronics being unable to settle on a logic state.
Similar problems occur with contact bounce on a mechanical encoder.
Any time this happens, the look-up table will simply return zero.
Thus,the encoder position variable doesn't show a change in
position. A nice plus is that every clock edge generates a pulse,
multiplying the resolution of the encoder four times.
After that was working, I wrote the code to handle the debouncing
of the three button inputs. With the input side of the hardware and
software working, I started tackling the remote code-specifically,
the menu system needed for this project. I did some research on the
Internet and in Circuit Cellar. Aubrey Kagan wrote an excellent
article about implementing a menu system for projects using
embedded processors and LCDs ("Hierarchical Menus in Embedded
Systems," Circuit Cellar 160, 2003)。 His system was designed to be
a general-purpose menu system where the menus were hard-coded into
the source code. While I needed some menus embedded in the source,I
knew most of my menus would be generated on the fly from
information sent by the PC to the remote. I gleaned a number of
useful points from his article. But ultimately, I implemented a
different system written from scratch that had different goals in
mind.
Finally, the foundation for this project is finished. My hardware
is up and running, and I can read the scroll wheel and buttons. I
also have a basic strategy for my menu code. Next month, we‘ll walk
through the land of software. I will tie everything together and
explain how the menu code actually works. I'll also describe the
design decisions I made while I was trying to create a flexible and
dynamic menu system.
Author's note: For videos and additional photos of the show in
action, go to my
web site: www.socalhalloween.com
Peter Montgomery (
servoanimation@socalhalloween.com) spent 12 years working as a visual effects supervisor on films
such as Mortal Kombat and Ace Ventura: When Nature Calls before
becoming a director. He has directed dozens of commercials and
made the transition to episodic television with The Disney
Channel's Lizzie McGuire. Self-taught in both programming and
digital hardware design, Peter uses his super powers only for good,
not evil.
PROJECT FILESTo download code, go to
ftp://ftp.circuitcellar.com/pub/Circuit_Cellar/2008/218.
SOURCESDelphi IDE
CodeGear
www.codegear.com
D012 Display module
Display3000
www.display3000.com/html/english.html
Custom panel
Front Panel Express
www.frontpanelexpress.com
Z8F4821 Microcontroller
Zilog, Inc.
www.zilog.com