ECE476 Final Project Report

Pump-It-Up Game

 

Hyunuk Kim, hk237

Hyung-Joo Park, hp47

Joon Young Kwak, jk252

 

Table of Contents

Introduction

High Level Design:  Rationale  |  Calculations  |  Hardware/Software Trade-offs  |  Standard Relations  |  Intellectual Properties/Trademarks

Program/Hardware Design:  Software  |  Hardware  |  Attempts that did not work

Results

Conclusion

Intellectual Property Considerations

Ethicical Considerations

Appendices:  Appendix A: Codes  |  Appendix B: Budget  |  Appendix C: Task Distribution | Appendix D: References  |  Appendix E: Pictures

 

Introduction

Our Project is a game that generates arrows which player needs to stroke corresponding keyboard button while background music is playing.

 

Computer-based Dancing games such as DDR and Pump-It-Up are very popular nowadays because they are equipped with both interactive user interface of computer games and dynamics of dance and music. Our version of the game also provides these yet is more affordable in terms of cost and space.

 

We implemented the game using Mega32 MCU and STK500 development board, LCD for display, TV-Audio type speaker for music, and PS/2 type keyboard for user input.

[Back to Top]

 

High level design

Rationale

The game is already commercially available. In fact, it is very popular among wide range of ages. We transplanted the game to Mega32 based platform, bringing down cost and changing user interface to more compact and affordable form.

 

We concentrated on limiting our project small and simple. However, the game requires several independent tasks running at the same time, such as input processing, sound generation, and display. These tasks need to be concurrent while not interfering with each other. Therefore, we sought ways to distribute the tasks evenly and assign tasks to independently running processes, so that the game runs smoothly with strong concurrency.

 

We originally planned to use TV as display interface. But we replaced TV with LCD to save cycles spent on TV display and also saved significant amount of timing budget spent for proper TV display. LCD also consumes less energy and is easier to control. Also using timers PMW capability made the music to have no noise or discontinuity problem. Processing ps/2 input using external interrupt made asynchronous sampling of ps/2 input possible. Moreover, all of these processes are handled by one MCU.

 

Calculations

Sound:

The minimum unit of music that our project provides is a note. It is generated by PMW in timer0, and it can change per one frame of LCD display, which is 100 milliseconds in minimum. We converted the frequency into counts per refresh rate based on the minimum refresh rate by using the following procedure (simplified). Because were free with the constraints by TV display, our maximum frequency is the same as the Crystals frequency, which is 16MHz

 

                  fmax = 1/16e-6;                            % 16MHz

                  rate = fmax/period of notes

                  Calculate frequency generated by calculated counts

                  Compare with desired frequency, use frequencies with small errors.

 

And in doing so, we found that the 18 notes that we planned to use in our project have almost no error: at max 0.03% of error from the desired frequency. The matlab code used for error calculation and its result is included in Appendix A.

 

PS/2:

PS/2 has 11 consecutive bits transmitted with clock. However, though clock itself is uniform, PS/2 doesnt generate clock signal when the line is idle. In order to handle PS/2 input properly, we verify the length between two consecutive clocks so that we dont misinterpret a packet. Since each clock has a period of about 70 micron (standard PS/2 Keyboard in the lab observed by oscilloscope), we run a timer that verifies if the period is much larger than the standard (about x3 of typical clock period length, 200 micron), and discard PS/2 input data if clock fails.

 

One packet of keyboard input takes about 11x70=770 micron. When we run the game, we empty key-stroke record at the minimum of 100 milliseconds. Therefore, theoretically, we can process at most 129 keystrokes, calculated as below

 

Hardware/software tradeoffs

We use mono single-tone sound using TV-audio type speaker. However, we could significantly improve the quality of music by using another MCU that generates higher quality sound. However, in order to keep our project simple, we limit our project to one MCU, trading off the quality of music and hardware budget.

 

Replacing TV display with LCD gave an advantage by making timing budget more flexible and also making display control easier. However, since we used TEXT LCD, we had to sacrifice the quality of graphics. We also planned to use graphic LCD. However, it is beyond the maximum budget of this project.

 

Standards Relations

PS/2 standard and Keyboard:

We use standard PS/2 keyboard to get user input. The PS/2 interface has 6 PINS: 1 Vdd, 1 Gnd, 1 Clock, 1 Data, and 2 N/C. When there is active transmission, clock is generated and data can be read on the falling edge of the clock. There are 11 bits in one packet of data, which consists of 1 starting bit, 8 data bits, 1 parity bit, and 1 ending bit. For keyboard, one key generates two types of scan codes: On-Press and On-Release scan code. In this project, only On-Press scan code is our interest, therefore we discard On-Release part of the scan code.

 

The keyboard operates on 5V Vdd. It drives about 60mA of currents typically (Keyboard specification, back of PS/2 Keyboard we used). Since one PIN of STK500 cant handle such an amount of current, we built another power supply for keyboard.

 

Intellectual Properties and Trade Marks

Pump-It-Up, the game, is created by Andamiro, Inc. The game is already commercialized. Therefore, we do not intend to produce the project commercially without the companys permission.

[Back to Top]

 

Program/hardware design

The Setup

 

Software

Overall Software Process Design

Sequential Process

-Main:

The main loop contains only initialization and idle infinite loop because all processes are triggered by interrupt.

-Initialization:

This process initializes LCD, PORTS, and few variables. It also enables some interrupts.

-Selection:

This is the process where user selects game mode: Single, VS, and Dual, and song to be played. Keyboard input taken by interrupt routine is processed to make choice. Once user starts the game, main game, [Next_Step] is executed. At this point, TIMER1 is enabled.

-Next_Step:

This process is the actual game. It reads song data file from FLASH memory. The LCD is refreshed per every call. This function is called by TIMER1 interrupt when TIMER1 counted delay period specified by song data file. This function actually draws steps and arrows on LCD, change the frequency in TIMER0 PMW so that the sound changes, and also records score. When the song is done, indicated by 0xff in data stream, it exits and executes [Score_Display].

-Score_Display:

This process simply displays the score and records the high score. Then the program is initialized again and game starts over from [Selection].

 

External Interrupt Process

-External Interrupt1:

This interrupt is called on every falling edge of clock by PS/2 keyboard. The PS/2 keyboard generates clock only when a button is pressed, held, or released. When an interrupt is called, the ISR reads data simultaneously. The ISR maintains a counter that counts the number of bits in one packet which consists of 11 bits. 8 data bits are stored in a queue and sent to [KeyInput]. TIMER2 tracks the time between two clocks. If the clock fails, i.e. takes too long, timer2 will clear the queue and re-initialize the packet counter.

 

-KeyInput:

The 8 bit data sent from External Interrupt 1 ISR is matched with scan code list and enables corresponding bit in input array.

 

-Data Structure and Variables

All songs, their names, and other static information are stored in FLASH memory and read by pointer to the address to avoid using SRAM. Only when the data needs to be processed, it is assigned to temporary variables in SRAM.

 

Each keyboard button is assigned a place in key stroke array for easier data process. The variable is cleared per every frame to make sure keystroke in previous frame is completely cleared. Also in doing so, the On-Release scan code became unnecessary.

 

The play data is made of 4 characters per frame.

The first character is note to be played, i.e. 0: Do, 17: Fa, one octave above.

The third character is player 1 play information.

The fourth character is player 2 play information.

The play information is:

0: no keystroke required

1~5: one key stroke required

6-15: two key stroke required

For example, data {7,5,1,7} yields:

In order to match scrolled step information and note, duration and steps are shifted by 2.

-Scoring System

One correct key stroke counts as one point. So two-button combination gives at most 2 points. There is no penalty for wrong stroke as in the original game. Total required key stroke is stored, and score is divided by total strokes required becomes the final score.

 

-Interrupt Control

Certain interrupts are not always enabled.

-TIMER0, the sound generator, is enabled only when [START] is true: when the game is actually running.

-TIMER2 and EXT INT1 is always enable since keyboard input comes asynchronously and always needs to be processed.

-TIMER1, the game controller, is enabled only when the game actually executes and is disabled after one game is done.

 

-Sound Generation

Frequency vs Notes

 

Sound is generated by timer0s PMW function by making the frequency to one that matches with actual frequency of a note as in the table above. Timer0 is enabled only when the game is started to prevent unnecessary noise in idle mode.

 

Hardware

Overall Hardware Design

 

PortA

PortA is connected to LED in STK500 for testing purposes, mainly testing the scan code from keyboard.

 

PortB

PortB.3 is the PMW of timer0, which is used in generating music. It is connected to TV-Audio type of speaker to generate sound. It should be connected in parallel with a 10K resistor.

Ref:

Video Control with AVR

 

PortC

PortC is connected to LCD, 4x20 DMW 20434 in our project, for display. The connection is the same as the LCD used in ECE476 Labs.

Ref:

Datasheet for general LCD

lcd.c, test code for LCD control

 

PortD

PortD is connected the PS/2 Keyboard. PortD.3 is clock, which is Ext Int1 in Mega32. PortD.7 is data, but it doesnt have to be port 7.

Refs:

 

PS/2 keyboard/mouse interface

[Wireless Keyboard] lab group homepage

 

Power Supply for Keyboard

PS/2 Keyboard requires 5V power supply and generally drains about 100mA of currents. (60mA according to data information on the back of keyboard in the lab). It is beyond the amount that a PIN can drive and it would actually drain the power in STK500 if connected directly to a Vdd in a Port. So we had to build a separate power supply for the Keyboard. It is done by using a 9V battery connected to a voltage regulator, LM340T5, a 5V regulator which can be found in the lab. Though voltage output from a battery is not always stable, it is always greater than 5V, so we have no problem with power in the keyboard.

 

Ref:

LM340 Datasheet

 

Note: If you plan to make one of these, make sure to have the right directions in your connection. In Top view, the Middle pin is ground, the Left is Original Voltage Input, and the Right is output voltage, at max 5V.

 

Attempts that did not work

-        Using the mat. We originally planned to use a dancing mat that came with pump-it-up game. It has PS/2 interface and is connected to keyboard slot in computer. However, it requires certain initialization process which we were unable to discover, since the company doesnt have datasheet, the part is obsolete, and we couldnt run the initialization software in the lab since it doesnt run on windows2000 machine.

 

-        UART connection of PS/2 Keyboard using PS/2 to Serial converter. We thought if we use null-modem connection using serial to PS2 converter, we might be able to convert the PS/2 signal to RS232 connection and process it using UART. Attempt failed. However, we were able to build our project based on hyper-terminal input and UART interrupt.

[Back to Top]

 

Results

We do not use TV display which limits the number of cycles available to other processes. Also the project doesnt contain any blocking process. The game itself is controlled by timer and tasks are distributed so that it is processed within the absolute minimum time available for the process. Therefore, the project runs at the right speed that we expected without any hesitation. Also external asynchronous input such as that of keyboard is processed by External Interrupt, which has highest priority among the interrupts that we use. Therefore, our project achieves almost perfect concurrency.

 

As shown from earlier notes calculation, at most we have 0.03% maximum error in frequency. The error is generally even lower. The error is absolutely not noticeable to normal human ears, and we verified it in our experiment. Therefore, we conclude that sound would not disturb the user.

 

Unlike the original plan to use dancing mat, PS/2 keyboard interface would not harm any normal user physically. Also the LCD display does not radiate as much UV radiation as TV. Therefore it is even better for the users eyes. Volume is adjustable so that the user can control it to the level that the music doesnt cause distraction.

 

We dont generate any RF signal or significant amount of radiation, therefore we expect that the project would not disturb or interfere with other electric devices.

 

Our project is a standalone machine and does not require PC presence.  It could be made portable as well. Therefore, it can be more readily accessible by the people in many places.

 

The PS/2 keyboard scan process, sound generation code, data structure in flash memory with pointers could be re-used in other applications.

[Back to Top]

 

Conclusion

We expected to build the machine based on TV display and Mat. So we cannot directly compare the goals that we set before we start the project.

 

However, we achieved very strong concurrency that we cant expect from TV based display. Also we didnt expect much dynamics from LCD display. However, the LCD display had much more capability of handling fast changing display than we expected.

 

We expected to have another MCU to process PS/2 input. However, we actually achieved it only by using one MCU with external interrupt. Also we didnt expect to process many keyboard inputs. However, the keyboard actually correctly processed 4 simultaneous key strokes without missing any of these.

 

The music that we generated has much better quality than we expected. We expected low-quality music so that we were planning to switch the sound to simply two notes with correct-incorrect user input. But the notes that we generated produced good sound for about 1.5 Octaves without noise or discontinuity with the length of notes frequently changing even when there existed extensive external interrupt.

 

We use flash memory extensively for storing music. When we need to use the memory, we load it into SRAM for speed. As a result, we could put large amount of game data with good performance speed.

 

Possible Improvements

Since our project reached our goal, to implement the machine using simple design, we could improve the quality of the game by using more than one MCU and assigning different tasks to other MCUs, such as making the sound to be MP3 quality with stereo type sound.

 

We also could use color LCD for better display, or even graphical LCD. However, we couldnt do it because of our budget limit. We would not recommend returning to TV display, considering the pros and cons of TV and LCD display.

 

We could easily implement more than 3-button combinations, however, it seems to be redundant.

[Back to Top]

 

Intellectual property considerations

-Sound: We re-used the code and design for generating sound in Video Generation with AVR in ECE476 Course Website,

Video Control with AVR

-LCD display:

lcdtest.c, a sample file for LCD control

In controlling the LCD, we re-used library files that have been used throughout the ECE476 labs.

-PS/2 Keyboard Input:

We could obtain the basic ideas of PS/2 input processing from [wireless keyboard] Project Group from 2003.

-Pump-It-Up:

For more information about the pump-it-up game,

http://www.pumpitup.co.kr

Though we used pump-it-up, we only imported the rules of the game and our project doesnt have direct relationship with the product. However, since commercialized version of pump exists, its unlikely that we will patent our project. However, our project is distinguished from original product since though the rules are the same, the game itself is far different in the way that it interacts with user, its portability, and its low-power consumption with standalone feature.

[Back to Top]

 

Ethical considerations

Refering to the IEEE Code of Ethics,

1.        to accept responsibility in making engineering decisions consistent with the safety, health and welfare of the public, and to disclose promptly factors that might endanger the public or the environment:

- Our project doesnt generate harmful effect to any person, since it is not designed to or generates significant heat, radiation, or other forms of pollusion.

2.        to avoid real or perceived conflicts of interest whenever possible, and to disclose them to affected parties when they do exist:

-We do not commercialize our project. Therefore there exists no conflict of interest with other parties.

3.        to be honest and realistic in stating claims or estimates based on available data:

-We are honest with all the observations, calculations, and derivations used in the project and there is no hidden or modified information of the project.

4.        to reject bribery in all its forms:

-There is no bribery regarding our project since there is no monetary interest involved.

5.        to improve the understanding of technology, its appropriate application, and potential consequences:

-While working on the project, we discovered more information and obtained greater understandings about standards and protocols we used in our project, such as PS/2 protocol.

6.        to maintain and improve our technical competence and to undertake technological tasks for others only if qualified by training or experience, or after full disclosure of pertinent limitations:

-This question seems to be irrelevant to the project.

7.        to seek, accept, and offer honest criticism of technical work, to acknowledge and correct errors, and to credit properly the contributions of others:

-We are willing to seek, accept, and offer any positive criticism, for it actually helped us in this project.

8.        to treat fairly all persons regardless of such factors as race, religion, gender, disability, age, or national origin:

-Sure.

9.        to avoid injuring others, their property, reputation, or employment by false or malicious action:

-Ok.

10.     to assist colleagues and co-workers in their professional development and to support them in following this code of ethics:

-We must.

[Back to Top]

 

Appendices

Appendix A: Source Code

Matlab Code for notes:

notes.m

%Generate counts for notes C0 to F1 in units of 10 milliseconds

fmax = 1/16e-6;

notes=[

16.35 %C0 do

17.32 %C#0/Db0

18.35 %D0 re

19.45 %D#0/Eb0

20.60 %E0 mi

21.83 %F0 fa

23.12 %F#0/Gb0

24.50 %G0 sol

25.96 %G#0/Ab0

27.50 %A0 ra

29.14 %A#0/Bb0

30.9  %B0 si

32.70 %C1 do

34.65 %C#1/Db1

36.71 %D1 re

38.89 %D#1/Eb1

41.20 %E1 mi

43.65 %F1 fa

];

r = (fmax./notes);

 

for i=1:length(r)

    fprintf(1,'%6.1f%6.1f%10.4f\n',notes(i),round(r(i)),(r(i)-round(r(i)))/r(i));

end

 

Result

16.43823.0   -0.0001

  17.33609.0   -0.0001

  18.43406.0   -0.0000

  19.43213.0    0.0001

  20.63034.0   -0.0000

  21.82863.0    0.0000

  23.12703.0    0.0001

  24.52551.0    0.0000

  26.02408.0   -0.0002

  27.52273.0   -0.0001

  29.12145.0   -0.0001

  30.92023.0   -0.0002

  32.71911.0    0.0002

  34.61804.0   -0.0001

  36.71703.0   -0.0003

  38.91607.0    0.0001

  41.21517.0   -0.0000

  43.61432.0   -0.0001

 

pump_t.c

void initialize();

void songSelect(char);

void selection();

void keyinput(char);

void next_step();

void step_clear();

void score_display();

 

#define LCDwidth 20

#asm

        .equ __lcd_port=0x15

#endasm

#include <lcd.h>

#include <Mega32.h>

#include <stdio.h>

#include <stdlib.h>

#include <delay.h>

#include <string.h>

 

unsigned char p1arr[6], p2arr[6];   // button step LCD lines

unsigned char onerow[20];

unsigned char got_step[2]={0,0};

unsigned char p1step[5], p2step[5]; // button step record and counter

unsigned char miss_step[2]={0,0};

unsigned char song;           // song number from database

unsigned char start;   // song started/stopped

unsigned char pressed=1;

unsigned char songmax=6;      // maximum number of songs

// for keyboard input, use interrupt 1

unsigned int line;

unsigned int next_delay;

unsigned char duration=0;

unsigned int time_count=0;

unsigned char sound;

unsigned char countIn;

unsigned char dataIn;

unsigned int score1=0;

unsigned int total1=0;

unsigned int score2=0;

unsigned int total2=0;

unsigned int ratio_u1=0;

unsigned int ratio_d1=0;

unsigned int ratio_u2=0;

unsigned int ratio_d2=0;

unsigned int dual_ratio_u=0;

unsigned int dual_ratio_d=0;

unsigned char mode=0; // 0=1p 1=2p comp 2=2p double

eeprom int highu[3][7]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

eeprom int highd[3][7]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

// we may increase the length of these for sensitivity. but its not scaled to this thing.

char p1[4]; // p1 data holder

char p2[4]; // p2 data holder

char i=0;

/* song is made of 4 chars * Length

   bit0 1 is sound

   bit1 is duration (delay_ms or timer when switched)

   bit2 is p1 arrow

   bit3 is p2 arrow

 */

 

/* proto types will have 25 length */

const flash int songindex[7]={0,72,220,340,660,788,1020};

char *song_names[13]={"TSTAR       \0","E and C     \0","B-FLY       \0","WYIY Maggie \0","Happy Bday  \0","Nabiya      \0","Jingle Bell \0"};

char *mode_string[3]={"Single\0","Versus\0","Double\0"};

const flash char songlist[1452]={

        20,5,1,3,

        20,5,1,3,

        0,5,3,1,

        0,5,3,1,

        7,5,5,2,

        7,5,5,2,

        9,10,3,3,

        9,5,2,2,

        7,5,2,2,

        5,5,1,4,

        5,5,1,4,

        4,5,2,2,

        4,5,2,2,

        2,10,1,1,

        2,10,0,0,

        0,10,0,0,

        20,10,0,0,

        20,20,0xff,0xff,

        //83-66+1=18 *4=72

        20,10,1,3,

        20,5,3,1,

        0,5,5,2,

        4,10,1,3,

        7,5,3,1,

        0,5,5,2,

        4,5,4,4,

        7,5,4,4,

        5,5,2,3,

        5,5,1,5,

        9,5,5,1,

        12,5,5,1,

        7,5,2,3,

        7,5,4,5,

        11,3,6,1,

        14,3,6,1,

        0,5,3,3,

        0,5,2,2,

        4,3,1,6,

        7,3,1,6,

        0,5,1,3,

        0,5,2,2,

        4,3,4,1,

        7,3,4,1,

        5,5,2,2,

        5,5,1,3,

        9,3,3,4,

        12,3,3,4,

        7,5,4,2,

        7,5,2,5,

        11,15,6,1,

        14,15,0,1,

        12,15,1,0,

        0,5,0,0,

        0,5,0,0,

        20,5,0,0,     

        20,5,0xff,0xff,

        //121-85+1=37 *4 = 148+72=220

        20,5,1,4,

        20,5,3,2,

        7,10,3,2,

        4,5,2,3,

        4,5,4,1,

        5,10,4,1,

        2,3,1,5,

        2,3,2,4,

        0,3,3,3,

        2,3,4,2,

        4,3,5,1,

        5,3,5,1,

        7,10,5,1,

        7,5,5,5,

        7,5,3,3,

        7,10,3,3,

        4,5,2,2,

        4,5,4,4,

        5,10,4,4,

        2,3,1,5,

        2,3,3,3,

        0,3,5,1,

        4,3,5,1,

        7,3,2,4,

        7,3,2,4,

        4,10,2,5,

        4,10,0,0,

        4,10,0,0,

        20,10,0,0,    

        20,10,0xff,0xff,

        //152-123+1=30 *4 =120+220=340

        20,5,10,5,

        20,5,10,5,

        12,4,9,4,

        12,2,2,2,

        9,5,3,5,

        7,3,2,2,

        5,3,3,1,

        7,10,2,1,

        5,3,1,2,

        5,5,14,4,

        2,3,5,2,

        5,5,4,1,

        2,4,5,5,

        0,2,5,5,

        5,5,6,6,

        5,4,10,10,

        9,2,10,10,

        12,10,7,7,

        12,10,0,0,

        7,5,10,10,

        20,5,10,10,

        12,4,5,5,

        12,2,4,4,

        9,5,3,3,

        7,3,2,7,

        5,3,5,2,

        7,10,4,5,

        5,3,3,2,

        5,5,2,5,

        2,3,4,2,

        5,5,2,1,

        2,4,1,2,

        0,2,10,3,

        5,5,11,4,

        8,4,12,5,

        12,2,11,4,

        7,10,12,10,

        8,10,0,0,

        5,5,10,11,

        20,5,5,12,

        5,4,5,12,

        14,2,5,12,

        14,5,2,10,

        14,4,5,12,

        10,2,5,12,

        10,10,2,5,

        14,3,10,4,

        12,5,13,4,

        8,3,1,3,

        12,5,2,2,

        8,4,5,1,

        7,2,5,1,

        12,3,5,1,

        12,3,6,6,

        12,3,7,5,

        10,3,3,3,

        16,10,10,4,

        14,10,0,0,

        12,5,10,4,

        20,5,10,4,

        12,4,3,3,

        12,2,2,2,

        8,5,1,1,

        7,4,9,9,

        5,2,10,11,

        7,10,10,11,

        5,3,1,4,

        5,5,5,3,

        2,3,1,4,

        5,5,10,13,

        2,4,11,12,

        0,2,12,5,

        5,6,15,4,

        8,4,15,3,

        12,2,14,5,

        7,15,5,5,

        8,10,0,0,

        5,10,0,0,

        20,10,0,0,    

        20,10,0xff,0xff,

        //233-154+1=80 *4=320+340=660

        20,3,1,5,

        20,3,1,5,

        2,5,3,3,

        2,5,1,5,

        4,3,5,1,

        2,3,5,1,

        7,10,4,2,

        7,3,3,1,

        6,3,3,1,

        2,5,4,2,

        2,5,3,1,

        4,3,5,3,

        2,3,5,3,

        9,10,10,6,

        9,3,5,3,

        7,3,5,3,

        2,5,11,4,

        2,5,5,3,

        14,5,2,1,

        11,5,4,2,

        7,10,3,3,

        6,3,10,15,

        4,3,10,15,

        12,5,4,2,

        12,5,3,3,

        11,3,4,2,

        7,3,4,2,

        9,10,5,10,

        9,10,0,0,

        7,10,0,0,

        20,10,0,0,    

        20,10,0xff,0xff,

        //266-235+1=32 *4=128 + 640 = 788

        20,3,1,5,

        20,3,3,3,

        12,3,3,3,

        9,3,2,4,

        9,3,4,2,

        10,5,4,2,

        7,3,1,3,

        7,3,2,2,

        5,3,3,1,

        7,3,4,5,

        9,3,5,4,

        10,3,5,4,

        12,5,5,4,

        12,3,5,4,

        12,3,3,2,

        12,3,3,2,

        9,3,3,2,

        9,3,4,5,

        10,3,2,1,

        7,5,2,1,

        7,3,2,1,

        5,3,1,3,

        9,3,3,4,

        9,3,5,6,

        12,3,5,6,

        12,3,3,2,

        9,5,3,2,

        9,3,8,10,

        9,3,2,4,

        7,3,2,4,

        7,3,2,4,

        7,3,2,4,

        7,3,3,2,

        9,5,4,3,

        10,3,3,2,

        10,3,3,2,

        9,3,3,2,

        9,3,3,2,

        9,3,3,2,

        9,3,4,4,

        9,5,5,5,

        10,3,5,1,

        12,3,3,3,

        12,5,3,3,

        9,3,4,2,

        9,3,2,4,

        10,5,2,4,

        7,3,1,1,

        7,3,3,3,

        5,3,5,6,

        9,3,5,6,

        12,3,3,3,

        12,3,3,3,

        9,5,10,11,

        9,10,0,0,

        9,10,0,0,

        20,10,0,0,    

        20,10,0xff,0xff,

        //325-268+1=58 *4=232 + 788 = 1020

        20,3,1,5,

        20,3,3,2,

        0,3,2,3,

        9,3,1,2,

        7,7,5,1,

        5,3,0,0,

        0,3,5,1,

        20,3,4,5,

        0,3,3,4,

        9,3,2,2,

        7,7,1,5,

        5,3,0,0,

        2,3,2,1,

        20,3,3,6,

        2,3,5,5,

        10,3,4,4,

        9,7,2,2,

        7,3,0,0,

        4,3,5,7,

        20,3,5,7,

        12,3,3,6,

        12,3,2,6,

        10,5,3,3,

        7,3,2,1,

        9,3,0,0,

        5,3,1,1,

        20,3,5,3,

        0,3,3,2,

        9,3,2,1,

        7,7,1,5,

        5,3,0,0,

        0,3,7,5,

        20,3,6,1,

        0,3,7,2,

        9,3,6,3,

        7,7,4,10,

        5,3,0,0,

        2,3,4,1,

        20,3,6,2,

        2,3,5,3,

        10,3,3,1,

        9,4,8,10,

        7,2,8,10,

        12,3,8,10,

        12,3,8,10,

        12,3,1,2,

        12,3,3,3,

        14,3,2,1,

        12,3,1,2,

        10,7,2,3,

        7,3,0,0,

        5,3,9,8,

        20,3,9,8,

        9,5,9,8,

        9,3,9,8,

        9,3,9,8,

        9,5,9,8,

        9,3,9,8,

        9,3,10,11,

        9,4,1,1,

        12,2,2,2,

        5,7,3,3,

        7,3,0,0,

        9,3,11,14,

        20,3,11,14,

        10,4,11,14,

        10,2,11,14,

        10,3,11,14,

        10,3,10,13,

        10,3,10,13,

        9,3,10,13,

        9,3,10,13,

        9,3,2,3,

        9,3,2,3,

        7,3,5,4,

        7,5,1,3,

        5,3,10,5,

        7,3,0,0,

        12,3,9,8,

        20,3,9,8,

        9,5,9,8,

        9,3,9,8,

        9,3,9,8,

        9,5,9,8,

        9,3,9,8,

        9,3,10,9,

        9,4,11,3,

        12,2,1,4,

        5,7,3,5,

        7,3,0,0,

        9,3,13,14,

        20,3,13,14,

        10,4,13,14,

        10,2,13,14,

        10,3,13,14,

        10,3,12,12,

        10,3,12,12,

        9,3,12,12,

        9,3,1,5,

        9,3,1,5,

        12,3,3,2,

        12,3,1,3,

        10,7,5,1,

        7,3,0,0,

        5,10,0,0,

        20,10,0,0,

        20,10,0,0,    

        20,10,0xff,0xff

        };

 

flash char *song_ptr=songlist;

flash char notes[]={61, 58, 54, 51, 49, 46, 43, 41, 39, 36, 34, 32, 31, 29, 27, 26, 24, 23};

 

interrupt [EXT_INT1] void external_int1(void){

        // falling edge of a clock. Detect corresponding data bit.

        // 1st-start, next 8-code. 3 more bits. (no need to store parity, etc)

        countIn++;     //count how many clock pulses we have seen

        /* countIn=1, start bit

           countIn=2 to 9,      data bits 0 to 7

           countIn=10,  parity bit

           countIn=11,  stop bit */

 

        if (countIn==1) //seeing start bit

        {

               dataIn=0;      // initialize new data

               //set up timer0 to check for no clock transition in 200uSec (100uSec by osciloscope)

               //since it must be continuous clock

               TCNT2=0;        //reset timer0

               TCCR2=0x0B;     //put timer0 into compare match mode, prescaler of 64

               TIMSK=(TIMSK&0x7F)|0x80;//make bit7=1 to enable compare match interrupt timer2

               TIFR=TIFR&0x7F;               //make bit1=0 to clear the timer2 comp match flag (just in case its set)

        }

        else if ((countIn>1)&&(countIn<10)) //data bits being sent

        {

               TCNT2=0;             //reset timer0 since saw a clock signal

               TIFR=TIFR&0x7F;               //make bit1=0 to clear the timer2 comp match flag (just in case its set)

               dataIn=dataIn>>1;             //shift data right by 1

               if (PIND.7) dataIn=dataIn|0x80;

               //shift in a received bit of 1. else 0 (automatic)

        }

        else if (countIn==10)          //parity bit being sent

        {

               TCNT2=0;                          //reset timer0 since saw a clock signal

               TIFR=TIFR&0x7F;                       //set bit1=0 to clear the timer0 comp match flag

               // we won't check parity

        }

        else if (countIn==11) {

               // a set of data is received.

               if (~dataIn==0b11110000) dataIn=0;

               keyinput(dataIn);

               // later, do manipulation of buttonpad here

        }

        // check LED light and reconfigure stuff.

        // now need to process release scan code

        GIFR=0;

}

 

 

/* Timer 1 compare-match A ISR

   counted 1 ms, Timer1 counter cleared (no need to reinitialize TCNT1) */

interrupt [TIM1_COMPA] void cmpA_match(void) {

        if (time_count<next_delay) time_count++;

        else {

               time_count=0;  // counted duration

               next_step();

        }

}

 

/* Timer 2 Compare Match for Keyboard Control: Catches clock failure */

interrupt [TIM2_COMP] timer2_comp(void)

{

        TIMSK=TIMSK&0x7F;  //set bit1=0 to turn off timer0 comp match interrupt

        TCCR2=0x00;        //turn off timer0

        TIFR=TIFR&0x7F;    //set bit1=0 to clear timer0 comp match flag (just in case its set)

        countIn=0;         //reset counters

        dataIn=0;

}

 

/* Matches keyboard input with scan code */

void keyinput(char newpress) {

        /*char p1step[5], p2step[5];*/

        switch (newpress) {

               /* p1 buttons (5) */

               /* do check through LED */

               // currently done to keyboard buttons

               // to track press time, p1/p2step will be set to a certain non-zero number.

               // it will be decreased over time.

               // scoring will be done with this thing.

               // previous press won't count towards score.

               // combo buttons can be handled this way.

              

        case (0b00010101): //q

               p1step[0]=pressed;

        break;

        case (0b00011010): //z

               p1step[1]=pressed;

        break;          

        case (0b00011011): //s

               p1step[2]=pressed;

        break;  

        case (0b00100100): //e

               p1step[3]=pressed;

        break;

        case (0b00100001): //c

               p1step[4]=pressed;

        break;

        /* p2 buttons (5) */

        case (0b01101100): //7

               p2step[0]=pressed;

         break;

        case (0b01101001): //1

               p2step[1]=pressed;

        break;

        case (0b01110011): //5

               p2step[2]=pressed;

        break;

        case (0b01111101): //9

               p2step[3]=pressed;

        break;

        case (0b01111010): //3

               p2step[4]=pressed;

        break;

        default:

               PORTA=0xff; // LED

        }

}

 

/* Song Selection & mode setup with [start] processing */

void songSelect(char choice) {

        /* song list rotation */

        /* add display to line 3 and line 4*/

        if (choice=='a' && (song>0)) song--;

        if (choice=='b' && (song<songmax)) song++;

        if (choice=='c') {

               line=songindex[song];

               start=1;

        }

        if (choice=='d' && (mode>0)) mode--;

        if (choice=='e' && (mode<songmax)) mode++;

        lcd_gotoxy(6,2);

        lcd_puts(song_names[song]);  

        lcd_gotoxy(6,3);

        lcd_puts(mode_string[mode]);

}

 

/* Song and Mode Selection */

void selection() {

        TIMSK = 0x00;                        // turn off timer1

        lcd_clear();

        while (!start) {

        p1step[2]=0;

        p1step[3]=0;

        p1step[4]=0;  

        lcd_gotoxy(0,0);

        lcd_putsf("Select  a  Song    ");

        delay_ms(1000);

        if ( p1step[1] ) songSelect('a');

        if ( p1step[4] ) songSelect('b');

        if ( p1step[0] ) songSelect('d');

        if ( p1step[3] ) songSelect('e');

 

        p1step[0]=0;

        p1step[1]=0;

        p1step[3]=0;

        p1step[4]=0;          

 

        lcd_gotoxy(0,1);

        lcd_putsf("Push Mid to Confirm");

        delay_ms(1000);                      

        if ( p1step[1] ) songSelect('a');

        if ( p1step[4] ) songSelect('b');

        if ( p1step[0] ) songSelect('d');

        if ( p1step[3] ) songSelect('e');

 

        p1step[0]=0;

        p1step[1]=0;

        p1step[3]=0;

        p1step[4]=0;          

 

        lcd_gotoxy(0,2);

        lcd_putsf("Song:");

        lcd_gotoxy(6,2);

        lcd_puts(song_names[song]);

        lcd_gotoxy(0,3);

        lcd_putsf("Mode:");   

        lcd_gotoxy(6,3);

        lcd_puts(mode_string[mode]);

 

        delay_ms(1000);

        if ( p1step[1] ) songSelect('a');

        if ( p1step[4] ) songSelect('b');

        if ( p1step[0] ) songSelect('d');

        if ( p1step[3] ) songSelect('e');

 

        p1step[0]=0;

        p1step[1]=0;

        p1step[3]=0;

        p1step[4]=0;          

        lcd_gotoxy(0,0);

 

        lcd_putsf("                   ");

        delay_ms(1000);

        if ( p1step[1] ) songSelect('a');

        if ( p1step[4] ) songSelect('b');

        if ( p1step[0] ) songSelect('d');

        if ( p1step[3] ) songSelect('e');

 

        p1step[0]=0;

        p1step[1]=0;

        p1step[3]=0;

        p1step[4]=0;          

        lcd_gotoxy(0,1);

        lcd_putsf("                   ");  

 

        delay_ms(1000);       

        if ( p1step[1] ) songSelect('a');

        if ( p1step[4] ) songSelect('b');

        if ( p1step[0] ) songSelect('d');

        if ( p1step[3] ) songSelect('e');

        p1step[0]=0;

        p1step[1]=0;

        p1step[3]=0;

        p1step[4]=0;          

 

        if ( p1step[2] ) {

               songSelect('c');

               lcd_clear();

               delay_ms(1000);

              

               TIMSK = 0x10;                 // turn on timer 1 compare match ISR

               TCNT1 = 0;                     // initialize timer 1 counter

               TCCR1B = 0b00001011; // turn on clear-on-match and setup count time to 1ms

               OCR1A = 249;                  // this is clk * 64, 250 count to count =1 ms=

               time_count=0;

               next_delay=0;

               score1=0;

               total1=0;

               score2=0;

               total2=0;

               ratio_u1=0;

               ratio_d1=0;

               ratio_u2=0;

               ratio_d2=0;

               dual_ratio_u=0;

               dual_ratio_d=0;

               step_clear();

               lcd_gotoxy(0,1);

               lcd_putsf(">     <\0");

               if (mode) {

                       lcd_gotoxy(13,1);

                       lcd_putsf(">");

                       lcd_gotoxy(19,1);

                       lcd_putsf("<");

                       }

               }

        }

 

}

 

/* Actual Game, called by Timer1 */

void next_step() {

        /* game play */

        TCCR0 = 0;

        if (start) {

               sound=*(&song_ptr[0]+line+0);

               duration=*(&song_ptr[0]+line+1);

               p1[3]=*(&song_ptr[0]+line+2);

               p2[3]=*(&song_ptr[0]+line+3);

               //  terminator

               if (p1[3]==0xff) start=0;

              

               /* sound */

               if (sound<18) {

                 if (notes[sound]>0) TCCR0 = 0b00011100;  //not a rest

         }

         OCR0 = notes[sound];

              

               lcd_gotoxy(0,0);

               lcd_putsf("                    ");

               i=1;          

               while (i<4) {

               /*

               step chars:

               0-no button

               1-left top

               2-left bottom

               3-middle

               4-right top

               5-right bottom

              

               extended step chars (2 buttons):

               6-LT+LB

               7-RT+RB

               8-LT+RT

               9-LB+RB

              

               10-mid+LT

               11-mid+LB

               12-mid+RT

               13-mid+RB

              

               14-LT+RB

               15-LB+RT

              

               no 3-buttons considered.*/

               /* p1 process */

                       switch (p1[i]) {

                       case (1):

                              sprintf(p1arr,"1oooo%c",0x00);

                       break;

                       case (2):

                              sprintf(p1arr,"o1ooo%c",0x00);

                       break;

                       case (3):

                              sprintf(p1arr,"oo1oo%c",0x00);

                       break;                

                       case (4):

                              sprintf(p1arr,"ooo1o%c",0x00);

                       break;

                       case (5):

                              sprintf(p1arr,"oooo1%c",0x00);

                       break;

                       // combos are to be added

                       case (6):

                              sprintf(p1arr,"11ooo%c",0x00);

                       break;

                       case (7):

                              sprintf(p1arr,"ooo11%c",0x00);

                       break;

                       case (8):

                              sprintf(p1arr,"1oo1o%c",0x00);

                       break;

                       case (9):

                              sprintf(p1arr,"o1oo1%c",0x00);

                       break;

                       case (10):

                              sprintf(p1arr,"1o1oo%c",0x00);

                       break;

                       case (11):

                              sprintf(p1arr,"o11oo%c",0x00);

                       break;

                       case (12):

                              sprintf(p1arr,"oo11o%c",0x00);

                       break;

                       case (13):

                              sprintf(p1arr,"oo1o1%c",0x00);

                       break;

                       case (14):

                              sprintf(p1arr,"1ooo1%c",0x00);

                       break;

                       case (15):

                              sprintf(p1arr,"o1o1o%c",0x00);

                       break;                                                                                    

                       default: // 0x00, no press

                              sprintf(p1arr,"ooooo%c",0x00);

                       }

                       /* p2 process, only iff p2 on*/

                       if (mode) {

                       switch (p2[i]) {

                       case (1):

                              sprintf(p2arr,"1oooo%c",0x00);

                       break;

                       case (2):

                              sprintf(p2arr,"o1ooo%c",0x00);

                       break;

                       case (3):

                              sprintf(p2arr,"oo1oo%c",0x00);

                       break;

                       case (4):

                              sprintf(p2arr,"ooo1o%c",0x00);

                       break;

                       case (5):

                              sprintf(p2arr,"oooo1%c",0x00);

                       break;

                       // combos are to be added

                       case (6):

                              sprintf(p1arr,"11ooo%c",0x00);

                       break;

                       case (7):

                              sprintf(p1arr,"ooo11%c",0x00);

                       break;

                       case (8):

                              sprintf(p1arr,"1oo1o%c",0x00);

                       break;

                       case (9):

                              sprintf(p1arr,"o1oo1%c",0x00);

                       break;

                       case (10):

                              sprintf(p1arr,"1o1oo%c",0x00);

                       break;

                       case (11):

                              sprintf(p1arr,"o11oo%c",0x00);

                       break;

                       case (12):

                              sprintf(p1arr,"oo11o%c",0x00);

                       break;

                       case (13):

                              sprintf(p1arr,"oo1o1%c",0x00);

                       break;

                       case (14):

                              sprintf(p1arr,"1ooo1%c",0x00);

                       break;

                       case (15):

                              sprintf(p1arr,"o1o1o%c",0x00);

                       break;                                                             

                       default: // 0x00, no press

                              sprintf(p2arr,"ooooo%c",0x00);

                       }

                       lcd_gotoxy(14,i);

                       lcd_puts(p2arr);

                              }

                       lcd_gotoxy(1,i);

                       lcd_puts(p1arr);

                       i++;

               }

               line=line+4;

 

               // at this point, doing line0, top line, work on p1[0], p2[0]

               // rough draft is drawn (non-press done)

 

               // left top p1: p1[3]=1,6,8,10,14

               if ((p1[0]==1) || (p1[0]==6) || (p1[0]==8) || (p1[0]==10) || (p1[0]==14)) {

                       lcd_gotoxy(1,0);

                       if (p1step[0]>0) {

                              lcd_putsf("G");

                              score1++;

                       }

                       else    lcd_putsf("B");

               }

 

               // left bot p1: p1[3]=2, 6, 9, 11, 15

               if ((p1[0]==2) || (p1[0]==6) || (p1[0]==9) || (p1[0]==11) || (p1[0]==15)) {

                       lcd_gotoxy(2,0);

                       if (p1step[1]>0) {

                              lcd_putsf("G");

                              score1++;

                       }

                       else lcd_putsf("B");

               }

              

               // mid p1: p1[3]=3, 10, 11, 12, 13

               if ((p1[0]==3) || (p1[0]==10) || (p1[0]==11) || (p1[0]==12) || (p1[0]==13)) {

                       lcd_gotoxy(3,0);

                       if (p1step[2]>0){

                              lcd_putsf("G");

                              score1++;

                       }

                       else lcd_putsf("B");

               }             

              

               // right top p1: p1[3]=4, 7, 8, 12, 15

               if ((p1[0]==4) || (p1[0]==7) || (p1[0]==8) || (p1[0]==12) || (p1[0]==15)) {

                       lcd_gotoxy(4,0);

                       if (p1step[3]>0) {

                              lcd_putsf("G");

                              score1++;

                       }

                       else lcd_putsf("B");

               }

 

               // right bot p1: p1[3]=5, 7, 9, 13, 14

               if ((p1[0]==5) || (p1[0]==7) || (p1[0]==9) || (p1[0]==13) || (p1[0]==14)) {

                       lcd_gotoxy(5,0);

                       if (p1step[4]>0) {

                              lcd_putsf("G");

                              score1++;

                       }

                       else lcd_putsf("B");

               }             

 

               if (p1[0]>0 && p1[0]<6) total1++;

               else if (p1[0]>5) total1=total1+2;

              

               if (mode) {

                       // left top p2: p2[3]=1,6,8,10,14

                       if ((p2[0]==1) || (p2[0]==6) || (p2[0]==8) || (p2[0]==10) || (p2[0]==14)) {

                       lcd_gotoxy(14,0);

                       if (p2step[0]) {

                              lcd_putsf("G");

                              score2++;

                       }

                       else lcd_putsf("B");

                       }

 

                       // left bot p2: p2[3]=2, 6, 9, 11, 15

                       if ((p2[0]==2) || (p2[0]==6) || (p2[0]==9) || (p2[0]==11) || (p2[0]==15)) {

                       lcd_gotoxy(15,0);

                       if (p2step[1]) {

                              lcd_putsf("G");

                              score2++;

                              }

                       else lcd_putsf("B");

                       }

              

                       // mid p2: p2[3]=3, 10, 11, 12, 13

                       if ((p2[0]==3) || (p2[0]==10) || (p2[0]==11) || (p2[0]==12) || (p2[0]==13)) {

                       lcd_gotoxy(16,0);

                       if (p2step[2]) {

                              lcd_putsf("G");

                              score2++;

                              }

                       else lcd_putsf("B");

                       }

              

                       // right top p2: p2[3]=4, 7, 8, 12, 15

                       if ((p2[0]==4) || (p2[0]==7) || (p2[0]==8) || (p2[0]==12) || (p2[0]==15)) {

                       lcd_gotoxy(17,0);

                       if (p2step[3]) {

                              lcd_putsf("G");

                              score2++;

                              }

                       else    lcd_putsf("B");

                       }

 

                       // right bot p2: p2[3]=5, 7, 9, 13, 14

                       if ((p2[0]==5) || (p2[0]==7) || (p2[0]==9) || (p2[0]==13) || (p2[0]==14)) {

                       lcd_gotoxy(18,0);

                       if (p2step[4]) {

                              lcd_putsf("G");

                              score2++;

                       }

                       else    lcd_putsf("B");

                       }

       

                       if (p2[0]>0 && p2[0]<6) total2++;

                       else if (p2[0]>5) total2=total2+2;

               }

               step_clear();

 

               /* scroll effect for arrows */

               p1[0]=p1[1];

               p1[1]=p1[2];

               p1[2]=p1[3];

 

               p2[0]=p2[1];

               p2[1]=p2[2];

               p2[2]=p2[3];

 

               /* delay control */

               next_delay=((int)duration)*100;

               }

               // start is false.

               else {

               score_display();

               initialize();

               }

}

 

/* one game is played. Display scores */

void score_display() {

        TCCR0 = 0;

        lcd_clear();

        ratio_u1=score1*100/total1;

        ratio_d1=(int)((double)score1*1000.0/(double)total1-10*ratio_u1);

       

        ratio_u2=score2*100/total2;

        ratio_d2=(int)((double)score2*1000.0/(double)total2-10*ratio_u2);

 

        dual_ratio_u=(score1+score2)*100/(total1+total2);

        dual_ratio_d=(int)((double)(score1+score2)*1000.0/(double)(total1+total2)-10*dual_ratio_u);

    

        if (mode<2) { // display 1p score for single/versus mode

               lcd_gotoxy(0,0);             

               sprintf(onerow,"1P:%2u.%1u percent\0",ratio_u1,ratio_d1);

               lcd_puts(onerow);

              

               if (score1 >= score2) {

                       if ( (ratio_u1>highu[mode][song]) || ( (ratio_d1>=highd[mode][song]) && (ratio_u1==highu[mode][song]) ) )

                       {

                              highu[mode][song]=ratio_u1;

                              highd[mode][song]=ratio_d1;

                              lcd_gotoxy(0,3);

                              lcd_putsf("1P New High Score!");

                       }

               }             

               // new HS, 1p single mode            

        }

        if (mode==1) { // display 2p score only for versus mode

               lcd_gotoxy(0,1);

               sprintf(onerow,"2P:%2u.%1u percent\0",ratio_u2,ratio_d2);

               lcd_puts(onerow);

 

               lcd_gotoxy(0,2);

               if (score1>=score2) lcd_putsf("P1 wins");

               else  {

                       lcd_putsf("P2 wins");

                       if ( (ratio_u2>highu[mode][song]) || ( (ratio_d2>=highd[mode][song]) && (ratio_u2==highu[mode][song]) ) )

                       {

                              highu[mode][song]=ratio_u2;

                              highd[mode][song]=ratio_d2;

                              lcd_gotoxy(0,3);

                              lcd_putsf("2P New High Score!");

                       }

               }

        }

        if (mode==2) { // display dual mode score for double mode

               lcd_gotoxy(0,0);

               sprintf(onerow,"Dual:%2u.%1u percent\0",dual_ratio_u,dual_ratio_d);

               lcd_puts(onerow);

               if ( (dual_ratio_u>highu[mode][song]) || ( (dual_ratio_d>=highd[mode][song]) && (dual_ratio_u==highu[mode][song]) ) )

                       {

                              highu[mode][song]=dual_ratio_u;

                              highd[mode][song]=dual_ratio_d;

                              lcd_gotoxy(0,3);

                              lcd_putsf("DBL New High Score!");

                       }

        }

        delay_ms(2000);

        lcd_clear();

        lcd_gotoxy(0,3);

        lcd_putsf("Restarting...");

        delay_ms(1500);

}

 

void main(void) {

        initialize();

        while(1);

} //dummy main

 

/* erases key stroke records */

void step_clear(){

        p1step[0]=0;

        p1step[1]=0;

        p1step[2]=0;

        p1step[3]=0;

        p1step[4]=0;

        p2step[0]=0;

        p2step[1]=0;

        p2step[2]=0;

        p2step[3]=0;

        p2step[4]=0;

}

 

void initialize() {

        lcd_init(LCDwidth);

        lcd_clear();

        sprintf(miss_step,"B\0");

        sprintf(got_step,"G\0");

        mode=0;

        song=0;

        start=0;

        sound = 0;

 

        //use OC0 (pin B.3) for music

        DDRB.3 = 1;

       

        TCCR2 = 0;

        OCR2 = 50; //Timer0 outoput compare when 50 (decimal).1/(16Mhz/64)*25=100uSec.

       

        DDRA=0xff;

        PORTA=0xff;

       

        DDRD=0x00;     // PORTD is input for keyboard(don't need to have output)

       

        /* p1 p2 init */

        step_clear();

        line=0;

 

        sprintf(p1arr,"ooooo%c",0x00);

        sprintf(p2arr,"     %c",0x00);

 

        /* make timer1 to decrease step*/

        /* Timer 1 setup, CompA_Match ISR called on every 1 millisec */

        // make external interrupt on every falling edge of clock. (about 70 us per clockfall)

 

        p1[0]=0;

        p1[1]=0;

        p1[2]=0;

        p1[3]=0;

        p2[0]=0;

        p2[1]=0;

        p2[2]=0;

        p2[3]=0;

        TIMSK = 0x00;  // turn off timer 1 compare match ISR

        MCUCR=0x08;    // int1 triggered on falling edge

        GICR=0x80;     // int1 enabled

        GIFR=0;        // flag off

        countIn=0;     // counter reset

        dataIn=0x00;   // empty data Input

        #asm ("sei");

        selection();

}

 

Appendix B: Budget Listing

 

Parts

Quantity

Price ($)

Mega32 MCU

1

8

STK500 Development BD

1

0

LCD (4x20, DMW 20434) –Optrex, AllCorps.com

1

21

10K resistor

1

0

LM340T5 V Regulator

1

0

PS/2 Keyboard

1

0

TV-Audio type Speaker

1

0 (TV)

9V battery

1

0

Wires/Clippers

-

0

Total

-

29

 

Appendix C: Task Distribution

Hyunuk Kim, hk237:

Coding, Data Structure, General Design

Software Debugging

 

Hyung-Joo Park, hp47:

Hardware Setup and Testing

Hardware Trouble-shooting

 

Joon Young Kwak, jk252:

Sound setup, Note calculation in Matlab

Data Generation for songs and games

Budget Calculation

 

Appendix D: References:

Video Control with AVR

lcd.c, test code for LCD control

PS/2 keyboard/mouse interface

[Wireless Keyboard] lab group homepage

Pump-it-up Web:

http://www.pumpitup.co.kr

Data sheets:

LM340 Datasheet

Datasheet for general LCD

Vendor sites:

Allcorps.com

Ethics:

IEEE Code of Ethics

 

Appendix E: Pictures

Clock and Data signal on PS/2 Port.

The captured signal is scan code for keyboard button s. The horizontal scale is 250 micron per square, and the vertical scale is 5V for both channels. Notice the 11 bits data packet on the falling edge contains 8 bit data 00011011 as the On-Press scan code for s.

Game Sequence 1, the initialized screen before starting the game.

Game Sequence 2, the game.

Game Sequence 3, the scores.

 

 

 

Sample MPEG video image for one entire game

[Back to Top]