Michael F. McCabe (mfm8)
ECE 476: Final Project
The P-P-P-Palm:
A Microcontroller Based Handheld Device
We have designed a handheld device using a graphical LCD, a touch
screen from an old Palm m125 and an Atmel Mega32 to play the game Simon for
The
combination of a touch screen mounted on an LCD creates a highly adaptable user
interface that can be used for just about anything. Our initial concept called for the use of
both the Palm m125 touch screen and LCD as this is the ideal combination as
they have been designed to work together and are professionally packaged. However, after much research, we were unable
to determine a way to control the LCD via an Atmel microcontroller. The touch screen, however, is an analog
device with a rather simple interface that we were able to discern with minimal
effort. Separating the two, we were able
to mount the touch screen on a Crystalfontz 128x64 pixel graphical LCD which we
would actually be able to control. The
game of Simon was chosen as our application because it allows us to utilize
both the LCD and the touch screen to make a game that is impossible to play on
a television alone.
When thinking of possible projects, we considered what hardware we
had available that we might be able to use to do something interesting. At the top of this list was an old Palm m125
that would no longer power on but still had a functional LCD and touch screen,
which Mike owned. Previous ECE 476
projects have incorporated graphical LCDs, however not with a touch screen
interface. At this point we needed to
determine if it would be possible to use either the Palm LCD or touch
screen. After a good deal of research we
were not able to find any drivers or documentation for the LCD or the touch
screen used by the Palm m125. This
removed the possibility of using the Palm LCD because it would be far to
complicated to reverse engineer the protocols.
The touch screen however, only has four leads so after a few simple
tests we determined how the device functions and devised a simple way to use
it.
At the advice of
Due to the flexibility of a handheld device with an LCD and touch
screen, we were free to determine our final application of this technology
midway through the project after we had the components working. We considered using aOS to create a very
simply operating system, however that would have required converting motions on
the touch screen into characters much like Palm’s Graffiti. We determined early
on that the touch screen’s analog output did not have a high enough resolution
or linear relationship to obtain precise and intricate motions. Therefore we decided that we would implement
a game that could be played with an interactive device such as a touch
screen. The natural choice based on our
LCD and touch screen resolution was Simon.
For those not familiar with Simon, it is a game originally designed by
Hasbro in 1978 in which the player is shown four tiles flashing in a particular
order. Each round the number of tiles
flashed increases and the speed at which they flash can also increase. The player must memorize the order and press
the tiles in the proper order. There is
also a time limit on pressing the buttons that we chose not to implement in our
version, due to the need for the user to hold down and press firmly on the
touch screen. This along with the low
linear resolution inevitably forced our game design to one incorporating fairly
large blocky areas. A game like Simon,
which uses 4 such blocks lends itself well to such design requirements.
A number of tradeoffs between the hardware and software were
apparent when designing the system. The
main tradeoff was the low linearity resulting from the analog-to-digital
conversion of the x and y positions on the touch screen. While for the most part the voltages
increased or decreased from one side of the touch screen to the other, the
incremental voltages jumps between arbitrary points would vary and sometimes
not change at all, thereby creating certain areas that were very difficult to
discern through conversions. This was
the main reason that Simon was chosen as the application, because Simon uses
fairly large boxes. The only other
tradeoff was between the LCD screen and touch screen. Because the touch screen is much larger than
the LCD screen, only a portion of the touch screen is usable. Therefore we used the portion of the touch
screen with the most linearity to offset the first tradeoff as much as
possible.
We are unaware of any patent infringements in designing our handheld
device, however we are aware of the original Simon patent (see the References
section). As far as trademarks, besides
using the Atmel chip, we used the touch screen from a Palm m125 and the
graphical LCD is from a company called Crystalfontz. Finally we attempted to use Luke Delaney’s
driver code for the graphical LCD, however we had to change and rewrite a large
portion of it in order to use the LCD at all.
While our project incorporates two pieces of hardware that were
not used in the lab section of the course, the actual design required to use
these components proved to be quite minimal.
The LCD requires power and ground connections along with 14 connections
to the microcontroller ports C and D.
The only additional circuitry required is a potentiometer, which
controls the contrast. The LCD we are
using has an EL backlight, but requires a $12 chip that did not fit in our
budget to control. As such pins 19 and
20 are not connected. A full listing of
the MCU to LCD connections is below:
Mega32 CFAG12864 Name
VCC Pin 1 VCC (+5V)
GND Pin 2 GND
-- Pin 3 Contrast
PORTD.0: Pin 4 Data Bit 0
PORTD.1: Pin 5 Data Bit 1
PORTD.2: Pin 6 Data Bit 2
PORTD.3: Pin 7 Data Bit 3
PORTD.4: Pin 8 Data Bit 4
PORTD.5: Pin 9 Data Bit 5
PORTD.6: Pin 10 Data Bit 6
PORTD.7: Pin 11 Data Bit 7
PORTC.0: Pin 12 Column Select 1
PORTC.1: Pin 13 Column Select 2
PORTC.2: Pin 14 Reset
PORTC.3: Pin 15 Read / Write
PORTC.4: Pin 16 Data
/ Instruction
PORTC.5: Pin 17 Enable
-- Pin 18 -VCC (-5V output)
-- Pin 19 Backlight Anode
-- Pin 20 Backlight Cathode
The touch screen, on the other hand, did require some circuitry to
use, albeit very minimal. The touch screen
has four leads (Up, Down, Left, Right) which connect to a metal strip on each
of the sides of the screen. Since the
touch screen functions by varying resistance between the leads based on
pressure, the bare minimum circuitry required would be a voltage divider in
which the touch screen took the place of one of the resistors. For our design we chose to fix Up and Right
as inputs to the touch screen (outputs from the MCU) and Down and Left as
inputs to our filter circuitry. Pull
down resistors were also added between both Down and Left to ground to complete
the voltage divider. Our filter
circuitry consisted of a very basic RC low-pass filter (R = 30kΩ, C =
.47μF) with a cutoff frequency of 11Hz followed by an op amp follower
circuit with a gain of 3. Schematics for
this circuit along with the entire LCD and MCU circuitry can be found in the
schematic appendix. The outputs of the
gain circuits are tied to ADC channels 0 and 1.
Though done entirely done in software, the timing required to
operate the graphical LCD was probably one of the most complex low level issues
in the project. Because of the low level
timing and bit-toggling requirements, we have decided to discuss this issue in
the hardware section. Below are the read
and write timing diagrams for the CFAG12864 model graphical LCD. This diagram is taken from the CFAG12864
datasheet.
The most important timing requirements are as follows: First, both
phases of the enable signal (E) cannot have a period of less than 500ns, thus
the highest frequency that it can be toggled is 1MHz. Second, all control lines must be changed
while enable is low and remain constant until enable transitions low
again. Third, all data lines must be set
for the falling edge of enable. All
setup and hold times are substantially less than 1μs and can be found in
the datasheet. Though it is not
specifically a timing concern, we strongly recommend that anyone who attempts
to use this LCD set the Read bit high when not actively writing. This will prevent artifacts from appearing on
the screen.
The software was designed in a bottom-up approach, where we first
wrote the low level driver controls for the touch screen and the LCD and then
used them in conjunction with the Simon top-level game.
As stated in the hardware design section, the microcontroller has
four connections to the touch screen, two control lines which apply voltage
across the screen in the x and y axis and two analog inputs representing the
position on the x and y axis. The two
control bits allow the touch screen to be run in one of three useable
modes. Voltage can be applied to the y
but not the x, the y but not the x, and both the x and the y. Theoretically both control bits can be set
low, but then the touch screen’s only possible function is to protect the LCD
from being scratched. In a perfect
world, the touch screen would behavior linearly and the x and y axis would not
be coupled. In the real world, we mapped
the ADC values to a grid that we touched for all three useable control
configurations. For our low resolution
purposes leaving the control lines such that there is always 5V applied to the
y axis and 0V applied to the x axis proved to give adequate grid. While we developed a more complex scheme in
which the control states were toggled and the compilation of all 3 was used to
determine the current position (function driveXY for bias switching), we
determined that there was not any real advantage in switching between voltage
while probing and debouncing the touch screen inputs.
In order to sample the x and y positions, we simply toggle the
analog-to-digital lines from A.0 to A.1 continuously (functions sampleY, sampleX and
getPlayerSample). To allocate enough
time for x and y conversions, we implemented a flag scheme that allows the
system to sample either the x position or the y position instead of simply
sampling both one after another. This
scheme allows enough time for the ADC values to settle as well as for the ADC
MUX to change input lines.
Once sampled, the ADC values are converted to positions on the
screen. There are two different cases
for inputs from the touch screen. Either
the player is choosing the difficulty level to play Simon in, or the player is
pressing the boxes on the screen (functions convertLines and convertBoxes, respectively). Both conversion
processes are separate and compare ADC values for both x and y differently to
obtain the proper choices.
Initially the CFAG12864 model LCD was chosen because software
drivers for the Atmel Mega32 were available on the ECE 476 website courtesy of
Luke Delaney. However, we quickly
realized when attempting to use these drivers that there were serious errors
with his code. While it appears that he
had the proper structure at a high level, many of his low level bit
manipulations were blatantly wrong and as a result, we could not even use it to
turn on the LCD. After attempting to
modify his code to make it work, we simply deleted the code in most of his functions
and rewrote it based on the timing diagrams given in the datasheet for the
CFAG12864 (see the hardware section above.
The most important things to be noted from that process is that most of
the control information is actually carried on the data lines when the control
bit for instruction/data is set to instruction and that whenever you are not
writing an instruction or data to the screen, the Read/Write line must be set
to read to prevent artifacts.
The LCD uses a data and control line where the data line is
interpreted in a variety of ways as specified by the control bus. The exact values for each line is specified
in the hardware section and specific functions are used to set, reset certain
bits in the control line (setbit and resetbit), write data and instructions
to the LCD (writedata and writeinstruction), and set the cursor positions on the LCD (setcursorpos). The writedata
function allows for the actual sending of an 8-bit value to be transmitted to
the LCD and interpreted on the LCD screen as a pixel set, where a logical ‘1’
sets a pixel and a ‘0’ resets a pixel.
The cursor positions on the LCD can range from 0 to 7 in the x direction
and 0 to 127 in the y direction. As
mentioned before, proper timing issues needed to be taken into account when
writing to the LCD; therefore delays are utilized to incorporate these needed
shifts.
Once these driver functions were written, all subsequent graphical
functions could then be implemented.
Functions such as clrscreen2, blkscreen2, makeblock and makeBigBlock
are all simple functions that are used for clearing the screen, blackening the
screen and making blocks of different sizes.
The only caveat with these functions is that the orientation of the
screen is different then the actual manufacture’s design:
Manufacture’s
Orientation |
Our
Orientation |
|
|
The setcursorpos function
was written to behave as if the LCD is oriented in how the LCD manufacturer
designed the screen (so that future users of these drivers can use the CLD as
designed). Therefore in order to use the
LCD how we wanted to, we incorporated the needed X coordinate inversion, and
changes were made to the higher level functions: printWord and makeblock. All other print functions stem from these two
functions. When data is written to the
LCD, the Y position is automatically incremented; therefore we used that to our
advantage by making all blocks, letters, numbers and spaces 8 rows deep,
thereby using a very simple for-loop without the need to keep changing the
overall position of the cursor with each iteration. This allows for much faster rendering.
The function printWord is used to write a word up to 8 characters in
length. The characters within the “word”
can be any capital letters, numbers, or spaces.
The actual bit representations of these characters are set in flash in
an 8x8 bit array for each character.
These letters allow for a blank line below the character and three blank
columns to the right of the character for easier readability. This representation is similar to the
character representation used within the Lunar
Lander lab assignment where a huge array is produced with all available
characters and is executed during execution.
The character arrays are separated every 8 indexes by each row
representing a portion of the character.
All of the higher print functions are self explanatory such as displayGrid (displays the 4 boxes for
Simon), splashscreen (initial startup
screen), displayDiffScreen (displays
all difficulty choices), displayGoodGame
(displays the win condition screen), pushbuttonChoice
(clears one of the boxes on the LCD) and finally showCorrectOrder (iterates through Simon’s List and “blinks” the
boxes off and on).
The functions getRandomNumber
takes Timer 0’s two lowest significant bits and uses that as a random number
generator from 0 to 3 and assigns the generated number to the end of Simon’s
list. Finally the lcdDebouncer debounces the values from the touch screen and is
called every 20 Hz. The debouncer works
very similar to the original debouncer, however the debouncing is used to
detect an area for a box press and a non-pres” where a non-pres” acts as the terminator for the debouncer after a valid
box has been pressed. This allows for
the removal of 2 of the states that was using in our original debouncer
function when using the keypad, because in the keypad case, the terminator was
another key being pressed, and therefore we do not need to poll for another key
when using the touch screen. Instead we
just poll for the player releasing stylus from the touch screen.
Using these touch screen and LCD print functions allowed us to
implement the game Simon. The logical
structure is fairly simple and is shown as a state diagram in Figure 1. Basically the game initializes and displays
the splash screen with our names. A
difficulty select screen is then displayed in which the player can select one
of three difficulty levels. The game
commences and the computer randomly chooses one of the 4 boxes (using good old
Timer0). The program then re-iterates
the complete Simon List starting from the first random number generated to the
most recent thus reminding the player the order needed to continue the
game. Now control is given to the player
in which the player must tap the boxes in the correct order to continue
playing. Because of the debouncing,
visual cues are given to the player with each successful box registration. If the player at anytime misses the correct
order, the game ends and the player can play again by simply tapping the touch
screen. However if the player makes it
through the entire set of boxes in Simon’s list (the maximum of boxes increases
with the difficulty), the game ends on a good note, and the player can still
play again by pressing the touch screen.
Figure 1
Our handheld Simon game behaves very
well. Most of the program runs within
the main while loop while only using a timing frequency of 20 Hz for the
debouncer. While the initial tests
produced some flickering, the final result is very well polished and even encapsulated
in its own casing allowing for portability while protecting the circuitry from
the outside environment. The touch
screen’s accuracy was tweaked and analyzed for a substantial amount of time and
after many careful calibrations behaves quite well in dealing with the Simon
game. Due to lack of linearity,
calibration was needed to be done to each of the input screens, therefore any
future addendums or other handheld programs needs to be calibrated. This proved to be the only pitfall in our
project. We would of liked to obtain a
general methodology to obtain x and y positions, however due to non-linearity
on the touch screen these generalizations were not possible.
Our system does not interfere with
any other designs because it is self contained and does not use any type of
wireless communication nor does it interface with any inherently noisy devices
such as motors. Finally, we spent a
great deal of time in the interfacing of the device with the player. We made sure that the debouncer worked very
well in capturing the inputs from the user and made sure the user knew that an
input was registered by the program by displaying the current player turn. When asking the TAs to play the game, most
learned the rules and needed pressure to apply for proper playability.
The following are some screenshots
of our Simon handheld:
|
|
Circuit
Board: Front Side |
Circuit
Board: Back Side |
|
|
|
|
Power
Off |
Initial
Startup Screen |
|
|
|
|
Difficulty
Select Screen |
Pressing
a Box |
|
|
|
|
Win
Screen |
Lose
Screen |
|
|
|
|
Back
of Packaging |
|
For the most part, our final design met
our expectations quite well. The one
fault it the resolution of our touch screen.
Due to the nonlinear nature of its behavior along with the fact that
changing the amount of pressure applied will change the resistance, the degree
of resolution that we were able to achieve was substantially less than the
screen is capable of. Since Palm does
not release any documentation of this sort of component, our entire
understanding of the behavior of the touch screen had to be learned through
experimentation and reverse engineering.
It is possible that we were simply operating the screen at improper
voltage ranges or with the wrong values of resistors in the voltage
dividers. While touch screen driver
chips are available from Analog Devices, we decided that such a chip would only
have added an extra level of complexity to our design and possibly thrown us
over budget. If we were to do this
again, more research would have gone into these driver chips. It is also possible that our initial removal
of the touch screen from the Palm LCD damaged the component.
The only time we used someone else’s code
or code available in the public domain is when we attempted to use Luke
Delaney’s LCD driver code. However as it
did not work and we were forced to rewrite it, only some of the high level
structure and variable declarations are his.
As this code was part of a MEng project for
The game of SIMON is a product of Hasbro
Inc though the name Simon is not trademarked, so we are free to use the
name. The original patent for the game
is linked in our references appendix, though it has long expired. Since we are not attempting to make a profit
or sell this device, we are not violating any copyright, though we could not
find one for this game.
In order to prevent injury to either human
or the handheld, we have packaged our handheld device in protective
cardboard. However with our limited
resource we had to tape the packaging shut which requires cutting the tape when
the battery needs to be replaced. It is
possible that a person could injure himself with the blunt plastic stylus, but
such a person would likely have done massive amounts of damage to themselves
with a standard pen or pencil.
Ethical
Considerations:
2. To
avoid real or perceived conflicts of interest whenever possible, and to
disclose them to affected parties when they do exist;
When considering applications for our handheld, we considered something
that we might also be able to use for RoboCup, but decided it might be viewed
as a conflict of interest so we decided to stick to a video game.
3. To be honest and realistic in stating claims
or estimates based on available data;
When proposing our project we made sure to explain that it might not be
possible to interface with a graphical LCD and make a meaningful application
and not claim that we could do it with absolute certainty.
4. To reject bribery in all its forms;
We rejected all bribes in the making of this project.
5. To improve the understanding of technology, its
appropriate application, and potential consequences;
We feel that we have improved the understanding of technology for
future ECE 476 classes by providing a working set of drivers for an
economically feasible graphical LCD.
8. To treat fairly all persons regardless of such factors
as race, religion, gender, disability, age, or national origin;
Our handheld device will be useable by people of any race, sex or creed.
/*
ECE 476 Final Project: PPP Palm
Jeff Johnson (JAJ37)
Mike McCabe
(MFM8)
PDA device
incorporating a touch screen and graphical LCD to play the game SIMON.
Gameplay:
The game SIMON is a memory game in which
the player must tap one of
the 4 boxes on the
screen in the random order generated by the program.
The program
randomly selects one of the four boxes and the user must press
that box. The program then selects another random box
and then reiterates
the order back to
the player. This continues until the
maximum number of
iterations has occurred
(set by the difficulty level).
The user can select one of three
difficulty levels. Each difficulty level
increases the
number of boxes to memorize as well as the delay time between each
box for which the
program reiterates the order after every successful pass.
Whether the player wins or losses the
player may reset the game by simply
tapping the
screen at the win or lose screen.
Hardware
Interface:
Their are two hardware interfaces with
the MCU. The first is the touchscreen
which must be set
to PORT A due to ADC usage. The second
is the graphical LCD
For this we use
ports C and D, for control and data busses respectively.
PORT A (ADC enabled): Touchscreen
Pin 0: Y Position
Pin 1: X Position
Pin
2-7: NOT USED
PORT B: NOT USED
PORT C: Graphical LCD Control Bus,
Touchscreen Voltage Driver
Pin 0: Column Select 1
Pin 1: Column Select 2
Pin 2: Reset
Pin 3: Read / Write
Pin 4: Data / Instruction
Pin 5: Enable
Pin 6: Touchscreen X Voltage Driver
Pin 7: Touchscreen Y Voltage Driver
PORT D: Graphical
LCD Data Bus
Pin 0: Data Bit 0
Pin 1: Data Bit 1
Pin 2: Data Bit 2
Pin 3: Data Bit 3
Pin 4: Data Bit 4
Pin 5: Data Bit 5
Pin 6: Data Bit 6
Pin 7: Data Bit 7
*/
//--------------------------------------------INCLUDES
#include <Mega32.h>
#include <delay.h>
//#include
<math.h>
#include <stdio.h>
//#include
<string.h>
//--------------------------------------------DEFINES
#define t1 50 //Timer
for Debouncing (20Hz)
#define DISPLAY_ON 0x3f //0011 1111, LCD
Turn on initialization
#define DISPLAY_OFF 0x3e //0011 1110, LCD
Turn off initialization
#define easySize 5 //Simon
List size set to 5
#define medSize 10 //Simon List size
set to 10
#define hardSize 15 //Simon
List size set to 15
#define easyDelay 250 //Reiteration
delay set to 250 ms
#define medDelay 200 //Reiteration
delay set to 200 ms
#define hardDelay 150 //Reiteration
delay set to 150 ms
//--------------------------------------------TYPES
//Control States:
typedef enum{
DisplayDifficulty, //Display on LCD the difficulty choices
SelectDifficulty, //Player chooses difficulty (input debounced)
CompTurn, //Program randomly chooses a box and reiterates the order
PlayerTurn, //Player chooses box (input debounced)
GoodEndGame, //Display on LCD that player won game. Tapping resets game
BadEndGame //Display on LCD that player lost game. Tapping resets game
} control_states;
//Debounce States
for Touchscreen input
typedef enum
{
RESET, //Reset
state
RELEASE, //Probe
Touchpad until a valid box (0-3)
DEBOUNCE, //2x check
of same box #
DETECT_ENTER, //If touchpad
release occurred continue with finalizing debouncing
DEBOUNCE_RELEASE //Release and
signal debounced
} debouce_states;
//--------------------------------------------CONSTANTS
//For Writing to
the LCD - Bit Definitions
const unsigned
char E =
0b00100000; //Enable
const unsigned
char DI = 0b00010000; //Data /
Instruction
const unsigned
char RW = 0b00001000; //Read / Write
const unsigned
char C2 = 0b00000010; //Column 2
const unsigned
char C1 = 0b00000001; //Column 1
const unsigned
char D7 = 0b10000000; //Data Bit 7
const unsigned
char D6 = 0b01000000; //Data Bit 6
const unsigned
char D5 = 0b00100000; //Data Bit 5
const unsigned
char D4 = 0b00010000; //Data Bit 4
const unsigned
char D3 = 0b00001000; //Data Bit 3
const unsigned
char D2 = 0b00000100; //Data Bit 2
const unsigned
char D1 = 0b00000010; //Data Bit 1
const unsigned
char D0 = 0b00000001; //Data Bit 0
//Space
Definition for LCD
flash unsigned char space[8] ={
//SPACE
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
//Letter
Definitions for LCD
flash unsigned char Letters[208] = {
//A
0b01110000,
0b10001000,
0b10001000,
0b11111000,
0b10001000,
0b10001000,
0b10001000,
0b00000000,
//B
0b11110000,
0b10001000,
0b10001000,
0b11110000,
0b10001000,
0b10001000,
0b11110000,
0b00000000,
//C
0b11111000,
0b10000000,
0b10000000,
0b10000000,
0b10000000,
0b10000000,
0b11111000,
0b00000000,
//D
0b11100000,
0b10010000,
0b10001000,
0b10001000,
0b10001000,
0b10010000,
0b11100000,
0b00000000,
//E
0b11111000,
0b10000000,
0b10000000,
0b11111000,
0b10000000,
0b10000000,
0b11111000,
0b00000000,
//F
0b11111000,
0b10000000,
0b10000000,
0b11111000,
0b10000000,
0b10000000,
0b10000000,
0b00000000,
//G
0b11111000,
0b10000000,
0b10000000,
0b10111000,
0b10001000,
0b10001000,
0b11111000,
0b00000000,
//H
0b10001000,
0b10001000,
0b10001000,
0b11111000,
0b10001000,
0b10001000,
0b10001000,
0b00000000,
//I
0b11111000,
0b00100000,
0b00100000,
0b00100000,
0b00100000,
0b00100000,
0b11111000,
0b00000000,
//J
0b11111000,
0b00100000,
0b00100000,
0b00100000,
0b00100000,
0b10100000,
0b11100000,
0b00000000,
//K
0b10001000,
0b10010000,
0b10100000,
0b11000000,
0b10100000,
0b10010000,
0b10001000,
0b00000000,
//L
0b10000000,
0b10000000,
0b10000000,
0b10000000,
0b10000000,
0b10000000,
0b11111000,
0b00000000,
//M
0b10001000,
0b11011000,
0b11011000,
0b10101000,
0b10001000,
0b10001000,
0b10001000,
0b00000000,
//N
0b10001000,
0b11001000,
0b11001000,
0b10101000,
0b10101000,
0b10011000,
0b10001000,
0b00000000,
//O
0b11111000,
0b10001000,
0b10001000,
0b10001000,
0b10001000,
0b10001000,
0b11111000,
0b00000000,
//P
0b11111000,
0b10001000,
0b10001000,
0b11111000,
0b10000000,
0b10000000,
0b10000000,
0b00000000,
//Q
0b11111000,
0b10001000,
0b10001000,
0b10001000,
0b10101000,
0b10011000,
0b11111000,
0b00000000,
//R
0b11111000,
0b10001000,
0b10001000,
0b11111000,
0b11000000,
0b10110000,
0b10011000,
0b00000000,
//S
0b11111000,
0b10001000,
0b10000000,
0b11111000,
0b00001000,
0b10001000,
0b11111000,
0b00000000,
//T
0b11111000,
0b00100000,
0b00100000,
0b00100000,
0b00100000,
0b00100000,
0b00100000,
0b00000000,
//U
0b10001000,
0b10001000,
0b10001000,
0b10001000,
0b10001000,
0b10001000,
0b01110000,
0b00000000,
//V
0b10001000,
0b10001000,
0b10001000,
0b10001000,
0b10001000,
0b01010000,
0b00100000,
0b00000000,
//W
0b10001000,
0b10001000,
0b10001000,
0b10101000,
0b10101000,
0b11011000,
0b11011000,
0b00000000,
//X
0b10001000,
0b10001000,
0b01010000,
0b00100000,
0b01010000,
0b10001000,
0b10001000,
0b00000000,
//Y
0b10001000,
0b10001000,
0b01110000,
0b00100000,
0b00100000,
0b00100000,
0b00100000,
0b00000000,
//Z
0b11111000,
0b00001000,
0b00010000,
0b00100000,
0b01000000,
0b10000000,
0b11111000,
0b00000000
};
//Number
Definitions for LCD
flash unsigned char Numbers[80] = {
//0
0b11111000,
0b11001000,
0b10101000,
0b10101000,
0b10101000,
0b10011000,
0b11111000,
0b00000000,
//1
0b00100000,
0b01100000,
0b10100000,
0b00100000,
0b00100000,
0b00100000,
0b11111000,
0b00000000,
//2
0b11111000,
0b00001000,
0b00001000,
0b11111000,
0b10000000,
0b10000000,
0b11111000,
0b00000000,
//3
0b11111000,
0b00001000,
0b00001000,
0b11111000,
0b00001000,
0b00001000,
0b11111000,
0b00000000,
//4
0b10001000,
0b10001000,
0b10001000,
0b11111000,
0b00001000,
0b00001000,
0b00001000,
0b00000000,
//5
0b11111000,
0b10000000,
0b10000000,
0b11110000,
0b00001000,
0b00001000,
0b11110000,
0b00000000,
//6
0b11110000,
0b10000000,
0b10000000,
0b11111000,
0b10001000,
0b10001000,
0b11111000,
0b00000000,
//7
0b11111000,
0b10001000,
0b00001000,
0b00001000,
0b00001000,
0b00001000,
0b00001000,
0b00000000,
//8
0b11111000,
0b10001000,
0b10001000,
0b11111000,
0b10001000,
0b10001000,
0b11111000,
0b00000000,
//9
0b11111000,
0b10001000,
0b10001000,
0b11111000,
0b00001000,
0b00001000,
0b00001000,
0b00000000
};
//--------------------------------------------FUNCTIONS
//MCU Functions
void initialize(void);
//LCD Functions
// LCD Driver Functions
unsigned char
setbit(unsigned char
whichbit, unsigned char
I);
//Set bit of control or data variable
unsigned char
resetbit(unsigned char
whichbit, unsigned char
I);
//Reset bit of control or data variable
void writedata(unsigned char
data1); //Write data to LCD
void writeinstruction(unsigned char
instruct); //Write
instruction to LCD
void setcursorpos(unsigned char x, unsigned char y); //Set cursor position
// LCD Print Functions
void clrscreen2(void); //Clear Screen
void blkscreen2(void); //Blacken Screen
void displayGrid(void); //Displays All 4 Boxes
void splashscreen(void); //Displays Initial Screen
void displayDiffScreen(void); //Displays Difficulty Screen
void displayGoodGame(void); //Displays WIN Screen
void displayBadGame(void); //Displays LOSE Screen
void showCorrectOrder(void); /*Iterates through SIMON's List by "blinking" the
correct box
order delayed by the given difficulty*/
void makeblock(unsigned char x, unsigned char y, unsigned char value);
/*Makes a block @ x,y where value := 0xFF = Filled Block
and 0x00 = Empty Block*/
void makeBigBlock(unsigned char x, unsigned char y, unsigned char value, unsigned char delay);
//Makes a 3x3 block with a delay in ms
void printWord(unsigned char x, unsigned char y, unsigned char * word,
unsigned char
invert);
/*Prints 1-8 letter words.
Words can be any capital letter,
number combinations. Spaces accepted as well*/
void pushButtonChoice(void); /*Produces an Empty Block specified by which Box pressed*/
//Touchscreen
Functions
void sampleY(void);
//Samples Y Position of Touchscreen
void sampleX(void);
//Samples X Position of Touchscreen
void getPlayerSample(void); //Obtains both X and Y Samples
void convertBoxes(void); //Convert X,Y ADC
values to the 4 boxes on screen
void convertLines(void); /*Convert X,Y ADC values to the difficulty rows on screen*/
void driveXY(unsigned char Xvalue,
unsigned char
Yvalue);
//Drive C.0 and
C.1 with 5V ('1') or GND ('0')
//SIMON Functions
void getRandomNumber(void); //Obtain a random number (0-3) and assign to Simon List
void lcdDeBouncer(void); //Debounces taps on the Touchscreen
//--------------------------------------------VARIABLES
unsigned char
Simon_List[hardSize];
//Simon's List 0
position is first box in memory list
unsigned char
time1; //timer
for debouncer
unsigned char
data; //Data
Bus output
unsigned char
control; //Control
Bus output
//For Simon List
unsigned char
maxSize; //max # of memory
pieces (based on difficulty chosen)
unsigned char
currentSize; /*current
# of memory pieces (grows with each turn. currentSize <= maxSize*/
//For Player
unsigned char
currentPos; //current position
of player in Simon's List
bit flagx; //Used
to differentiate either X or Y to read
bit doneflag; //Set
when debouncing finished
control_states
Current_Control_State; //current Control State
debouce_states
debounce_state; //current debounce state
unsigned char
XADC; //X
ADC value from Touchpad
unsigned char
YADC; //Y
ADC value from Touchpad
unsigned char
randomNum; //random
number 0-3 (polled from Timer0)
unsigned char
Box; //Box
numbed chosen 0-3 (4 is "no-box-chosen")
unsigned char
SaveBox; //Save
of Box
unsigned char
delayTime; /*Delay
time between "blinks" when program reiterates Simon's List to
player*/
/*
Timer 0 compare ISR
*/
interrupt [TIM0_COMP] void timer0_compare(void){
if (time1>0) --time1;
}
/*
*/
void main(void){
unsigned char simon1[]="ABCDEFGH"; //Array used for
all string conversions
initialize();
clrscreen2();
splashscreen();
clrscreen2();
driveXY(0,1); //X
= GND, Y = 5V
while(1){
switch(Current_Control_State){
case DisplayDifficulty:
//Display
Difficulty choices
displayDiffScreen();
Current_Control_State
= SelectDifficulty;
break;
case
SelectDifficulty:
lcdDeBouncer();
if (doneflag == 1){
//Wait and debounce touchscreen
doneflag = 0;
convertLines();
/*convert X and Y
positions to choices on difficulty
menu*/
Current_Control_State
= CompTurn;
}
break;
case CompTurn: //Computer's
Turn
sprintf(simon1,"COMPUTER");
printWord(0,73,simon1,0);
delay_ms(250);
if(currentSize == maxSize){
//If former turn
was last turn, player wins
Current_Control_State
= GoodEndGame;
clrscreen2();
}
else{
getRandomNumber();
/*Get random #
(0-3) and place number in Simon's List*/
displayGrid(); //Show
complete grid
showCorrectOrder(); //re-iterate
Simon's List
currentPos =
0; //player's
current position reset
Box = 4; //Box choice
reset to default
Current_Control_State
= PlayerTurn;
}
break;
case
PlayerTurn:
sprintf(simon1,"PLAYER ");
//Clear
‘Computer’ and replace with ‘Player’
printWord(0,73,simon1,0);
sprintf(simon1,"TURN");
printWord(0,82,simon1,0);
sprintf(simon1,"%d
OF %d",currentPos,currentSize);
printWord(0,91,simon1,0);
/*Shows player's
current turn and how many needed until next round*/
if(time1==0){
//Debounce box #
time1=t1;
lcdDeBouncer();
}
if (doneflag == 1){
doneflag = 0; //Debouncing finished
Box = SaveBox;
//Get saved debounced box #
if (Box == Simon_List[currentPos]){
/*If box number
is correct # in Simon's List, advance to player's next turn to chose next # in
Simon's List*/
currentPos++;
if(currentPos == currentSize){
/*If player's
turn is @ the last entry in Simon's List, Simon needs to choose another random
box*/
Current_Control_State
= CompTurn;
}
sprintf(simon1,"%d
OF %d",currentPos,currentSize);
printWord(0,91,simon1,0);
}
else{ //If player misses box order, game over
Current_Control_State
= BadEndGame;
clrscreen2();
}
}
break;
case
GoodEndGame:
displayGoodGame(); //Good Game Ending
lcdDeBouncer();
if (doneflag == 1){
//Debounce for replay condition
doneflag = 0;
currentSize =
0;
maxSize = 0;
Box = 4;
SaveBox = 4;
clrscreen2();
Current_Control_State
= DisplayDifficulty; //Reset
}
break;
case
BadEndGame:
displayBadGame(); //Bad Game
Ending
lcdDeBouncer();
if (doneflag == 1){
//Debounce for replay condition
doneflag = 0;
currentSize =
0;
maxSize = 0;
Box = 4;
SaveBox = 4;
clrscreen2();
Current_Control_State
= DisplayDifficulty; //Reset
}
break;
}
}
}
//--------------------------------MCU
FUNCTIONS-----------------------------
/*
Initialize everything
*/
void initialize(void){
//set up the ports
DDRD = 0xff; //PORT D is an output
DDRC = 0xff; //PORT C is an output
ADCSR = 0b11000111; //Enable ADC
//initialize LCD
data = DISPLAY_OFF;
control = 0b00100100;
delay_ms(30);
writeinstruction(0x3E); // Display
OFF
writeinstruction(0xC0);
writeinstruction(0xB8);
writeinstruction(0x40);
writeinstruction(0x3F); //
resetbit(C1, control);
setbit(C2,control);
PORTC
= control;
writeinstruction(0x3E); // Display
OFF
writeinstruction(0xC0);
writeinstruction(0xB8);
writeinstruction(0x40);
writeinstruction(0x3F); //
writeinstruction(0b01010101);
writeinstruction(0b10111001);
//set up timer 0
TIMSK=2; //turn on timer 0 cmp match ISR
OCR0 = 250; //set the compare re to 250 time ticks
TCCR0=0b00001011; //prescalar to 64 and turn on clear-on-match
time1=t1;
//init program variables
currentSize = 0; //sizes of Simon's List set to 0
maxSize = 0;
flagx = 1; //initialize X as value to convert (through ADC) first
before Y
doneflag = 0; //nothing debounced
Box = 4; //no box chosen
Current_Control_State = DisplayDifficulty; //reset Simon game
debounce_state = RESET;
#asm
sei
#endasm
}
//--------------------------------LCD
DRIVER FUNCTIONS----------------------
/*
Sets bit in I (Instruction) specified by
whichbit. Used in communication with LCD
*/
unsigned char
setbit(unsigned char
whichbit, unsigned char
I)
{
unsigned char A;
switch (whichbit){
case 'D7':
A = I | D7;
break;
case 'D6':
A = I | D6;
break;
case 'D5':
case 'E':
A = I | D5;
break;
case 'D4':
case 'DI':
A = I | D4;
break;
case 'D3':
case 'RW':
A = I | D3;
break;
case 'D2':
case 'RS':
A = I | D2;
break;
case 'D1':
case 'C2':
A = I | D1;
break;
case 'D0':
case 'C1':
A = I | D0;
break;
}
return A;
}
/*
Resets bit in I (Instruction) specified by
whichbit. Used in communication with LCD
*/
unsigned char
resetbit(unsigned char
whichbit, unsigned char
I){
unsigned char A;
switch (whichbit){
case 'D7':
A = I & ~D7;
break;
case 'D6':
A = I & ~D6;
break;
case 'D5':
case 'E':
A = I & ~D5;
break;
case 'D4':
case 'DI':
A = I & ~D4;
break;
case 'D3':
case 'RW':
A = I & ~D3;
break;
case 'D2':
case 'RS':
A = I & ~D2;
break;
case 'D1':
case 'C2':
A = I & ~D1;
break;
case 'D0':
case 'C1':
A = I & ~D0;
break;
}
return A;
}
/*
Writes Data specified by data1 to the LCD
*/
void writedata(unsigned char data1){
control = control | DI;
//set data
control = control & ~RW;
//set write
PORTC = control;
delay_us(1);
control = control | E;
//Toggle enable high
PORTC = control;
delay_us(1);
PORTD = data1;
//output data
delay_us(1);
control = control & ~E;
//toggle enable low
PORTC = control;
delay_us(1);
control = control | RW;
//set read
PORTC = control;
delay_us(1);
}
/*
Writes Instruction specified by dinstruct1 to
the LCD
*/
void writeinstruction(unsigned char instruct){
control = control & ~DI;
//set instruction
control = control & ~RW;
//set write
PORTC = control;
delay_us(1);
control = control | E;
//toggle enable high
PORTC = control;
delay_us(1);
PORTD = instruct;
//output instruction
delay_us(1);
control = control & ~E;
//toggle enable low
PORTC = control;
delay_us(1);
control = control | RW;
//set read
PORTC = control;
delay_us(1);
}
/*
Set cursor position on LCD to x,y
*/
void setcursorpos(unsigned char x, unsigned char y)
{
writeinstruction(0b01000000); //set
y address to zero
//if y falls on the left side of the
screen
if (y < 64)
{
control = control | C2; //choose
side
control = control & ~C1;
PORTC = control;
writeinstruction(0b10111000 + x); //X position
writeinstruction(0b01000000 + y); //Y position
delay_ms(1);
}
else
//if y is greater than 64 and falls
on the right side of the screen
{
control = control | C1; //choose
side
control = control & ~C2;
PORTC = control;
writeinstruction(0b10111000 + x); //X position
writeinstruction(0b01000000 + y - 64); //Y position
delay_ms(1);
}
}
//--------------------------------LCD
PRINT FUNCTIONS-----------------------
/*
Clear Screen
*/
void clrscreen2(void){
unsigned char page;
unsigned char col;
for (page=0; page < 8;
page++){
for (col=0; col <
128; col++){
setcursorpos(page,col);
writedata(0x00);
}
}
}
/*
Blacken Screen
*/
void blkscreen2(void){
unsigned char page;
unsigned char col;
for (page=0; page < 8; page++){
for (col=0; col <
128; col++){
setcursorpos(page,col);
writedata(0xff);
}
}
}
/*
Displays all boxes
*/
void displayGrid(){
makeBigBlock(0,0,0xFF,10);
makeBigBlock(5,0,0xFF,10);
makeBigBlock(0,41,0xFF,10);
makeBigBlock(5,41,0xFF,10);
}
/*
Displays Initial screen, Course name, our
names, and name of game for 3 seconds
*/
void splashscreen(void){
unsigned char temp[] = "";
sprintf(temp,"ECE
476");
printWord(0,0,temp,0);
sprintf(temp,"JEFF");
printWord(2,19,temp,0);
sprintf(temp,"JOHNSON");
printWord(1,28,temp,0);
sprintf(temp,"MIKE");
printWord(2,46,temp,0);
sprintf(temp,"MCCABE");
printWord(1,55,temp,0);
sprintf(temp,"PPP PALM");
printWord(0,73,temp,0);
sprintf(temp,"SIMON");
printWord(2,91,temp,0);
delay_ms(3000);
}
/*
Displays Difficulty Screen
*/
void displayDiffScreen(){
unsigned char temp[] = "";
sprintf(temp,"EASY");
printWord(0,0,temp,0);
sprintf(temp,"MEDIUM");
printWord(0,32,temp,0);
sprintf(temp,"HARD");
printWord(0,64,temp,0);
}
/*
Display message if player wins
*/
void displayGoodGame(){
unsigned char temp[] = "";
sprintf(temp,"YOU
WIN");
printWord(0,14,temp,0);
if(maxSize < 15){
sprintf(temp,"TRY A");
printWord(1,35,temp,0);
sprintf(temp,"HARDER");
printWord(1,45,temp,0);
sprintf(temp,"LEVEL");
printWord(1,55,temp,0);
}
else{
sprintf(temp,"ALL
HAIL");
printWord(0,35,temp,0);
sprintf(temp,"THE");
printWord(3,45,temp,0);
sprintf(temp,"CHAMPION");
printWord(10,55,temp,0);
}
sprintf(temp,"PRESS TO");
printWord(0,75,temp,0);
sprintf(temp,"RESET");
printWord(1,85,temp,0);
}
/*
Display message if player loses
*/
void displayBadGame(){
unsigned char temp[] = "";
sprintf(temp,"YOU LOSE");
printWord(0,14,temp,0);
if(maxSize == 5){
sprintf(temp,"TRY");
printWord(3,35,temp,0);
sprintf(temp,"AGAIN");
printWord(2,45,temp,0);
}
else {
sprintf(temp,"TRY
AN");
printWord(1,35,temp,0);
sprintf(temp,"EASIER");
printWord(1,45,temp,0);
sprintf(temp,"LEVEL");
printWord(1,55,temp,0);
}
sprintf(temp,"PRESS TO");
printWord(0,75,temp,0);
sprintf(temp,"RESET");
printWord(1,85,temp,0);
}
/*
Re-iterates Simon's List by
"blinking" the order on the LCD.
Delay between blinks specified by difficulty chosen
*/
void showCorrectOrder(){
unsigned char lc;
unsigned char currentSimonBox;
for(lc = 0; lc <
currentSize; lc++){
currentSimonBox =
Simon_List[lc];
if (currentSimonBox ==
0){
makeBigBlock(0,0,0x00,10); //Empty Box
delay_ms(delayTime);
makeBigBlock(0,0,0xFF,10); //Full Box
}
else if (currentSimonBox == 1){
makeBigBlock(5,0,0x00,10);
delay_ms(delayTime);
makeBigBlock(5,0,0xFF,10);
}
else if (currentSimonBox == 2){
makeBigBlock(0,41,0x00,10);
delay_ms(delayTime);
makeBigBlock(0,41,0xFF,10);
}
else if (currentSimonBox == 3){
makeBigBlock(5,41,0x00,10);
delay_ms(delayTime);
makeBigBlock(5,41,0xFF,10);
}
delay_ms(delayTime); //Delay
between each blink
}
}
/*
Makes a block on LCD @ x,y. Value of 0xFF is filled in box
and 0x00 is an empty box (can do strange
combinations if desired)
*/
void makeblock(unsigned char x, unsigned char y, unsigned char value){
unsigned char lc;
unsigned char max;
unsigned char realx;
realx = 7-x; /*Because of orientation of
LCD is not exactly as datasheet specified, this allows programmer to use X of 0
as left side and 7 as right side*/
setcursorpos(realx,y);
max = 128-y; /*Another sanity check
as before for easier programming. Y of 0 is top and y of 128 is bottom*/
if(max
>= 8){ /*Bounds
check for y s.t. y isn’t too high to cause partial blocks on bottom and top or
screen due to overflow */
max = 8;
}
for (lc=0; lc < max; lc++){
writedata(value);
/*Writes data
to LCD. Takes advantage of
auto-incrementing of y position built into the LCD*/
}
}
/*
Creates 3x3 block on Screen at specified x,y
coordinates. Value of 0xFF is filled in
box and 0x00 is an empty box (can do strange combinations if desired). Delay specifies delay between box drawing in
ms
*/
void makeBigBlock(unsigned char x, unsigned char y, unsigned char value,unsigned char delay){
makeblock(x,y,value); makeblock(x+1,y,value); makeblock(x+2,y,value);
makeblock(x,y+8,value); makeblock(x+1,y+8,value); makeblock(x+2,y+8,value);
makeblock(x,y+16,value); makeblock(x+1,y+16,value);
makeblock(x+2,y+16,value);
delay_ms(delay);
}
/*
Prints word to LCD @ x,y. Word can be any capital letter, number or
space character. Invert allows the colors that make up a letter to be inverted
(0 is normal, 1 is inverted. Assumes words are < 8 characters
*/
void printWord(unsigned char x, unsigned char y, unsigned char * word,
unsigned char
invert){
unsigned char ylc; /*Current Y Position on LCD. Also acts as a counter through the current
character being rendered*/
unsigned char xlc;
//Current X Position on LCD
unsigned char wordlc;
//Current position in word array
unsigned char realx;
//X Orientation change
unsigned char startpoint; /*Start
point in Letter or Number arrays. Each letter is a multiple of 8*/
realx = 7-x; /*Because of orientation
of LCD is not exactly as datasheet specified, this allows programmer to use X
of 0 as left side and 7 as right side*/
wordlc = 0;
for (xlc = realx; xlc >= 0;
xlc--){
if (word[wordlc] == 0){
break; //End
at NULL character
}
else{
if ((word[wordlc] >=
0x41) && (word[wordlc] <= 0x5A)) {
//Captital Letter
startpoint = (word[wordlc] - 0x41) << 3;
//Startpoint is at multiple of 8
}
else if((word[wordlc]
>= 0x30) && (word[wordlc] <= 0x39)) { //Number
startpoint = (word[wordlc] - 0x30) << 3;
//Startpoint is at multiple of 8
}
}
setcursorpos(xlc,y); //Set position
for (ylc = 0; ylc < 8;
ylc++){
//Print to LCD current line of a given character, where each
character is made up of 8 lines
if ((word[wordlc] >= 0x41) &&
(word[wordlc] <= 0x5A)){
if (invert == 0)
writedata(Letters[startpoint+ylc]);
else writedata(~(Letters[startpoint+ylc]));
}
else if(word[wordlc]
== 0x20){
if (invert == 0) writedata(space[ylc]);
else writedata(~(space[ylc]));
}
else{
if (invert == 0) writedata(Numbers[startpoint+ylc]);
else writedata(~(Numbers[startpoint+ylc]));
}
}
wordlc++; //Next Letter
}
}
/*
Blanks box depending on value of Box. If Box = 4, simply display all 4 boxes
*/
void pushButtonChoice(){
if (Box == 0) makeBigBlock(0,0,0x00,10);
else if
(Box == 1) makeBigBlock(5,0,0x00,10);
else if (Box ==
2) makeBigBlock(0,41,0x00,10);
else if (Box ==
3) makeBigBlock(5,41,0x00,10);
else
displayGrid();
}
//--------------------------------TOUCHSCREEN
FUNCTIONS---------------------
/*
Obtain Y's ADC value
*/
void sampleY(void){
if (ADCSR.4 == 1){ //Wait until conversion
finished
ADMUX = 0b01100000; //Change
ADC input MUX to A.0, internal AREF
ADCSR.6=1; //Start
another conversion
YADC = ADCH;
//Get value
flagx = 1;
//Set to get X's ADC value next
}
}
/*
Obtain X's ADC value
*/
void sampleX(void){
if(ADCSR.4 == 1){ //Wait until
conversion finished
ADMUX = 0b01100001; //Change
ADC input MUX to A.1, internal AREF
ADCSR.6=1; //Start
another conversion
XADC = ADCH;
//Get value
flagx = 0;
//Set to get Y's ADC value next
}
}
/*
Obtain both X and Y samples and converts to
the corresponding box
*/
void getPlayerSample(){
if (flagx == 0){
sampleY();
}
if (flagx == 1){
sampleX();
}
convertBoxes();
}
/*
Convert boxes from ADC values of Touchscreen
*/
void convertBoxes(){
if( ( (XADC < 115)
&& (XADC > 100) ) && ( (YADC < 68) && (YADC >
44) ) ){
Box = 0;
}
else
if( ( (XADC < 115) && (XADC >=
100) ) && ( (YADC <= 43) && (YADC > 31) ) ){
Box = 1;
}
else if(
( ( (XADC < 99) && (XADC > 90) ) && ( (YADC < 44)
&& (YADC > 31) ) )
|| ( (XADC < 104) && (XADC > 99)
&& (YADC < 30) ) ){
Box = 2;
}
else if(
( (XADC < 97) && (XADC > 85) ) && ( (YADC < 31)
&& (YADC > 15) ) ){
Box = 3;
}
else{
Box = 4;
//None of the above, therefore not a valid box (default
"no-box" state)
}
}
/*
Convert difficulty choice from ADC values of
Touchscreen
*/
void convertLines(){
unsigned char temp[]="";
if (XADC >= 109){
maxSize = easySize;
delayTime = easyDelay;
sprintf(temp,"EASY");
printWord(0,0,temp,1);
delay_ms(1000);
printWord(0,0,temp,0);
}
else if(XADC
> 99){
maxSize = medSize;
delayTime = medDelay;
sprintf(temp,"MEDIUM");
printWord(0,32,temp,1);
delay_ms(1000);
printWord(0,32,temp,0);
}
else if(XADC
<= 99){
maxSize = hardSize;
delayTime = hardDelay;
sprintf(temp,"HARD");
printWord(0,64,temp,1);
delay_ms(1000);
printWord(0,64,temp,0);
}
delay_ms(500);
clrscreen2();
}
/*
Drive X and Y lines to Touchscreen to a
variety of voltages
*/
void driveXY(unsigned char Xvalue,
unsigned char
Yvalue){
if ((Xvalue == 1) &&
(Yvalue == 0)){
control = control | 0x40;
}
else if((Xvalue
== 0) && (Yvalue == 1)){
control = control | 0x80;
}
else if((Xvalue
== 1) && (Yvalue == 1)){
control = control | 0xC0;
}
else if((Xvalue
== 0) && (Yvalue == 0)){
control = control | 0x00;
}
}
//--------------------------------SIMON
FUNCTIONS---------------------------
/*
Obtains random # between 0-3
*/
void getRandomNumber(){
randomNum = TCNT0 & 0x03; //Get
lowest 2 bits from TCNT0 (random # 0-3)
randomNum = ((randomNum & TCNT0) &
(0x03));
if (currentSize <
maxSize){
Simon_List[currentSize] = randomNum;
/*Place random # at end of Simon's List and increment number of items
in Simon's List*/
currentSize++;
}
}
/*
Debounces Box # on LCD running at 20Hz
*/
void lcdDeBouncer(void){
switch (debounce_state){
case RESET:
getPlayerSample(); //Probe
Touchpad
debounce_state = RELEASE;
break;
case
RELEASE:
if (Box != 4){ //Probe
Touchpad until a valid box (0-3)
SaveBox = Box; //Save
Box value
getPlayerSample(); //Probe
again
debounce_state
= DEBOUNCE;
}
else{
getPlayerSample();
}
break;
case DEBOUNCE:
if
(Box == SaveBox){ /*If 2 of same box occurs probe again and detect a touchpad
release*/
getPlayerSample();
debounce_state = DETECT_ENTER;
}
else{
getPlayerSample(); /*Otherwise
keep probing, waiting for 2 of same box in a row*/
debounce_state = RELEASE;
}
break;
case DETECT_ENTER:
if (Box == 4){
debounce_state = DEBOUNCE_RELEASE;
//If touchpad release occurred continue with finalizing debouncing
}
else{
if(Box == SaveBox){
if (Current_Control_State == PlayerTurn)
pushButtonChoice();
}
getPlayerSample();
debounce_state = DETECT_ENTER;
//Otherwise continue probing for a release
}
break;
case
DEBOUNCE_RELEASE:
if (Box !=
SaveBox){
//Touchpad debounced (doneflag = 1) if most recent probe != saved
value
getPlayerSample();
if (Current_Control_State ==
PlayerTurn)displayGrid();
debounce_state = RELEASE;
doneflag = 1;
}
else{
debounce_state
= DETECT_ENTER;
}
break;
}//end switch
}
Item # |
Part |
Manufacturer |
Part # |
Cost |
|
1 |
Crystalfontz Graphical LCD |
Crystalfontz |
CFAG12864B-WGH-V |
$26 |
|
2 |
Palm m125 Touchscreen |
Palm |
|
$0 |
Pre-owned |
3 |
Palm m125 Stylus |
Palm |
|
$0 |
Pre-owned |
4 |
Mega 32 |
Atmel |
|
$8 |
|
5 |
Prototype Board |
Prof. Land |
|
$5 |
|
6 |
Dual Op Amp |
Analog Devices |
AD823AN |
$0 |
Sampled |
7 |
9V |
|
|
$3 |
|
8 |
Touch Screen Connector |
Molex |
Molex 05210891110 |
$0 |
Sampled |
9 |
SWITCH SLIDE MINI |
ITT Industries |
CKN5001-ND |
$4 |
|
|
|
|
TOTAL COST: |
$46 |
|
Task: |
Developed By: |
Simon Code and
General Code Structure |
Jeff |
Debouncing Code |
Jeff |
LCD Driver
Development |
Jeff & Mike |
Touch Screen Calibration |
Mike |
Circuitry,
Soldering and Packaging |
Mike |
Crystalfontz: http://www.crystalfontz.com/products/12864b/index.html#CFAG12864BWGHV
http://www.crystalfontz.com/products/12864b/CFAG12864BWGHV.pdf
Luke Delaney - Graphical LCD Driver and Educational LCD Primer:
http://instruct1.cit.cornell.edu//courses/eceprojectsland/STUDENTPROJ/2003to2004/lld6/index.html
Palm Inc. (Now Palm One) for
the touch screen and stylus from a Palm m125
Inspiration for the
P-P-P-Palm: http://www.p-p-p-powerbook.com/
The
IEEE Code of Ethics: http://www.ieee.org/portal/site/mainsite/menuitem.818c0c39e85ef176fb2275875bac26c8/index.jsp?&pName=corp_level1&path=about/whatis&file=code.xml&xsl=generic.xsl