Jeffrey A. Johnson (jaj37)

Michael F. McCabe (mfm8)

ECE 476: Final Project

The P-P-P-Palm:

A Microcontroller Based Handheld Device

 

I.          Introduction. 1

II.         High Level Design. 1

III.        Hardware Design. 2

IV.        Software Design. 4

V.         Results. 8

VI.        Conclusions. 11

VII.       Appendixes: 12

Final Code. 12

Schematic. 35

Budget 36

Task Division. 36

References. 36

 

I.       Introduction

 

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 Cornell University’s ECE 476.

 

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.

 

II.      High Level Design

 

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 Professor Land, we looked into the Crystalfontz CFAG12864 line of graphical LCDs for which Luke Delaney, MEng 2004, had written drivers for an Atmel microcontroller.  As it happens, this line of graphical displays physically fit within the touch screen which allowed us to make a useful handheld device.

 

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.      

 

III.    Hardware Design

 

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.

 

IV.     Software Design

           

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

 

V.      Results

 

            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

 

 

 

VI.     Conclusions

 

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 Professor Land and was a link from the ECE 476 website, we are not infringing on his intellectual property and it is not patented or trademarked code.

 

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. 

 

VII.   Appendixes

 

Final Code:

 

/*

  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: Basic SIMON 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;

}

 

/*

  Main: inifinite loop

*/

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); // Display ON

       resetbit(C1, control);

       setbit(C2,control);

       PORTC = control;

       writeinstruction(0x3E); // Display OFF

       writeinstruction(0xC0);

       writeinstruction(0xB8);

       writeinstruction(0x40);

       writeinstruction(0x3F); // Display ON

       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       

}

 

Schematic:

Budget:

 

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 Battery

 

 

$3

 

8

Touch Screen Connector

Molex

Molex 05210891110

$0

Sampled

9

SWITCH SLIDE MINI

ITT Industries

CKN5001-ND

$4

 

 

 

 

TOTAL COST:

$46

 

 

Task Division:

 

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

 

References:

 

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 US Patent of SIMON: http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL&p=1&u=/netahtml/srchnum.htm&r=1&f=G&l=50&s1=4,207,087.WKU.&OS=PN/4,207,087&RS=PN/4,207,087

 

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