FIGURE 1.
Schematic with
optional ICSP
connector.
Design and Prototyping
In the first pass of design, I chose the microcontroller.
During the initial analysis, I found that I would need at
least 10 I/O pins and 33 to 52 bytes of data memory,
depending on how many temporary variables could be
reused, and how many variables smaller than one byte I
would pack into each memory location. I also needed a
timer to generate random numbers. I do not yet have
enough experience to estimate how much program
memory I will need, so once I gather a list of chips that fit
the other requirements, I’ll make my best guess favoring on
the high side.
The PIC16F505 fits the requirements, because it has 11
general-purpose I/O pins, 72 bytes of data memory, and
one timer. It also has optional internal pull-ups on some of
the pins which I did not originally plan to use. This later
saved me some extra components. When choosing a
microcontroller, it is best to check out its datasheet which
can typically be downloaded from the manufacturer’s
website. I use PICs because I already have an inexpensive
USB programmer, and some of the simpler chips can be
purchased for less than a dollar each. PICs take more effort
to program compared to Arduinos and the like, but once
you get used to them, their datasheets can help you
choose the best chip for your project. (See the sidebar
More About Choosing a Microcontroller for more details.)
At this point, I usually start a simple prototype by
drawing a schematic (Figure 1), placing components on a
solderless breadboard, and writing some code for the most
basic operations to verify that the initial design works. This
validates the basic assumptions made during the first pass
of analysis, and it is also helps to bring some life to the
50 SERVO 06.2010
project. I started with just enough code to test the display,
making sure that the LEDs could fade in and out to create
interesting effects instead of just turning them fully on or
off. This worked well, so I moved on to lighting the LEDs
based on which button was pressed.
Remember when I said one assumption was wrong in
my initial analysis? I wired the switches so they would
share the pulled-up columns with the array of LEDs, but I
hadn’t noticed that if the user was holding a switch, it
would tie that column to ground or to other columns if the
user held multiple switches. Holding a switch affected the
LEDs in the same column, so I decided to swap the rows
and columns, giving the switches their own columns with
internal pull-ups and shared rows instead. I also added the
diodes (shown in the schematic) to keep the switches from
tying two rows of LEDs together if the user pressed two at
the same time. Since I hadn’t written a lot of code yet
while testing out my assumptions, I only had to make
minor changes. Even if I had to change the requirements to
include more I/O pins and choose another microcontroller,
I would not have wasted much time at this point, since the
issue was caught early.
After modifying the layout of the circuit, I tested a
method for debouncing. I didn’t want the program to
pause to check each individual switch sequentially, so
instead I repeatedly took samples from all of the switches
at once and placed them in temporary variables together. I
then processed those variables to see if any switch changed
since the last stable reading. Even with the cheap switches
in my prototype, it seemed to work well enough. For the
first prototype, I only tested eight of the nine switches —
since the variables are eight-bits wide — to avoid writing
too much extra code this early.