#include <stdio.h> #include <delay.h> #include <90s8515.h> #include <stdlib.h> #include <math.h> //Maximum coordinates for x and y direction #define ymax 127 #define xmax 255 //Initial settings for options #define initspeed 4 #define initsize 3 #define initscore 10 //The states used in the state machine #define menu 1 //menu screen #define option 2 //options screen #define play1 4 //1 player mode #define play2 6 //2 player mode #define paused 8 //Pause game during game #define gamedone 9 //Game done screen once game is over // LCD Control lines (PORTC) #define LCDreset 0x00 // Reset the Display #define LCDnop 0x47 // No operation #define CmdSetup 0x47 // Set A0 high #define CmdWrite 0x43 // Set WR low #define DataSetup 0x07 // Set A0 low #define DataWrite 0x03 // Set WR low #define StatusRead 0x05 // Set RD low, A0 low #define DataRead 0x45 // Set RD low, A0 high // LCD Commands (PORTD) #define SystemSet 0x40 // Initialize system #define SleepIn 0x53 // Enter standby mode #define DispOFF 0x58 // Display Off #define DispON 0x59 // Display On #define Scroll 0x44 // Initialize Address & Regions #define CSRForm 0x5D // Set cursor type #define CharAddr 0x5C // Set address of character RAM #define CSRRight 0x4C // Cursor direction = right #define CSRLeft 0x4D // Cursor direction = left #define CSRUp 0x4E // Cursor direction = up #define CSRDown 0x4F // Cursor direction = down #define HorzScroll 0x5A // Set horz scroll position #define Overlay 0x5B // Set Display Format #define CSRW 0x46 // Set cursor address #define CSRR 0x47 // Read cursor address #define MWRITE 0x42 // Write to display memory #define MREAD 0x43 // Read from display memory #define TextAddress 0x0000 // Character layer base address #define GraphicsAddress 0x03E8 // Graphics layer base address = 1000 // LCD Subroutines void WriteCMD(unsigned char CommandCode); //write command void WriteDATA(unsigned char CommandCode); //write command parameters void clearLCD(void); //clear LCD void clearText(void); void butcheck(void); //Checks which button has been pushed void initialize(void); void mainmenu(void); //sets up menu screen void options(void); //sets up options screen void gamescreen(void); //sets up game screen void game(void); //does game checks during game play void pausescreen(void); //sets up the paused screen void drawball(); //draws ball according to ballx,bally void eraseball(); //erases ball according to ballx,bally void drawline(int, int); //draws a line on either side of the screen void textPos(int, int); //col, row //sets up position of cursor to write text void letterWrite(char); //prints out a letter to the LCD void wordWrite(char, char, char, char); //prints out 4 letters to the LCD void disInt(char); //prints out an integer or character to the LCD void eraseline(int, int); //erases a line on either side of the screen void donescreen(); //The game over screen indicating the winning player char clkon; //indicates whether clock signal to controller is on or off char clkcnt; //keeps count of how many times the clk signal has been inverted char str; //keeps count of how many times the strobe signal has been inverted int i; int pos; //keeps position on the LCD screen of where to print unsigned char pos_lo; //keeps low byte of pos unsigned char pos_hi; //keeps high byte of pos unsigned char nint; //keeps the current reading of control 1's button during the clock signal unsigned char nint2; //keeps the current reading of control 2's button during the clock signal unsigned char state; //keeps the current state of the state machine unsigned char tstate; //temporary storage of the current state of the state machine int but; //keeps current button push of control 1 int but2; //keeps current button push of control 2 int eitherbut; //tells whether a button on either control was pushed int oldbut, oldbut2, butbak, butbak2; //These were used to debounce the controllers int beep; //makes the speaker beep if there is a paddle hit by turning on timer 1 int showscore; //will make the program display the current score for a certain period of time char random; //used to generate random numbers int players; //indicates the number of players int score1, score2; //Keeps the score for the respective player char size; //size of the paddle char winscore; //score needed to win the game float ballx, bally //current coordinates of ball float oldballx, oldbally, newballx, newbally; //These variables are used to minimize the flicker on the LCD int speed, speedx, speedy; //speed of the ball, and in the specified directions int dirx, diry; //direction the ball is currently going int paddle1, paddle2; //position of both paddles int tpaddle1, tpaddle2, tballx, tbally, tdirx, tdiry; //storage variables used during the pause option int mainoptionselected; //tells which option is currently selected in the menu int optionselected; //tells which option is currently selected in the options screen int pauseoption; //tells which option is currently selected in the pause screen int waitcont; //makes program wait for button push char butready; //indicates if button is fully read from the controller char ballmove; //flag indicating program to move the ball char ball; //counter to set up the ball speed /*Timer0 overflow interrupt is used to set up a 1 msec time base for the program. It is also used to invert the appropriate clock and strobe signals going to both controllers and then reading the data pins from both of the controllers. It also sets a flag high when it is time for the ball to make its next move. The button pushes can be read every 125 msec which is enough time in between. */ //Strobe = PORTB.0 //CLOCK = PORTB.7 //Data for 1st controller = PINA.0 //Data for 2nd controller = PINA.7 interrupt [TIM0_OVF] void timer0_overflow(void) { TCNT0=256-62; if (++ball == 25) ballmove = 1; if (butready == 0) { if (clkon == 0) { if (PORTB.0 == 1) PORTB.0 = 0; else PORTB.0 = 1; if (++str == 2) { //reads in first bit of the controllers after strobe is done str = 0; clkon = 1; but = (!PINA.0); but2 = (!PINA.7); but = but << 6; but2 = but2 << 7; nint = (nint >> 1) | but; nint2 = (nint2 >> 1) | but2; } } else { //reads in rest of the bits when clock has gone high if (PORTB.7 == 1) PORTB.7 = 0; else PORTB.7 = 1; if (PORTB.7 == 1) { but = (!PINA.0); but2 = (!PINA.7); but = but << 6; but2 = but2 << 7; nint = (nint >> 1) | but; nint2 = (nint2 >> 1) | but2; } if (++clkcnt == 14) { clkcnt = 0; clkon = 0; but = nint; but2 = nint2; butbak = but; butbak2 = but2; if ((state==menu || state==option || state==paused || state==gamedone) && but == oldbut) but = 0; if ((state==menu || state==option || state==paused || state==gamedone) && but2 == oldbut2) but2 = 0; eitherbut = but | but2; oldbut = butbak; oldbut2 = butbak2; nint = 0; nint2 = 0; butready = 1; } } } } /* Timer 1 compare-match A ISR was used solely to send sound to the speaker by toggling a port pin at a certain frequency. */ interrupt [TIM1_COMPA] void cmpA_overflow(void) { if (PORTB.5 == 1) PORTB.5 = 0; else PORTB.5 = 1; //toggle the port to make a sound } //These next 3 procedures were used from the a final project from last //year, the Tilt Maze. The source code can be see at //http://instruct1.cit.cornell.edu/courses/ee476/FinalProjects/s2001/kmo15/m1dc.c /*********************************************************************/ /* WriteCMD() : Sends Command to LCD controller */ /*********************************************************************/ void WriteCMD(unsigned char CommandCode) { PORTD = CommandCode; PORTC = CmdSetup; PORTC = CmdWrite; PORTC = CmdSetup; return; } // end WriteCMD /*********************************************************************/ /* WriteDATA() : Sends parameters or data to LCD controller */ /*********************************************************************/ void WriteDATA(unsigned char CommandCode) { PORTD = CommandCode; PORTC = DataSetup; PORTC = DataWrite; PORTC = DataSetup; return; } // end WriteDATA /*********************************************************************/ /* clearLCD() : Clears the LCD display memory */ /*********************************************************************/ void clearLCD(void) { unsigned short i; WriteCMD(CSRRight); WriteCMD(CSRW); WriteDATA(0x00); WriteDATA(0x00); WriteCMD(MWRITE); for (i=0; i<1000; i++) { WriteDATA(0x20); // write " " to character memory } WriteCMD(CSRW); WriteDATA(0xE8); WriteDATA(0x03); WriteCMD(MWRITE); for (i=0; i<8000; i++) { WriteDATA(0x00); // erase graphics memory } return; } // end clearLCD /* This procedure is used to clear any text that is being currently displayed on the LCD. It clears the character memory. */ void clearText(void) { unsigned short i; WriteCMD(CSRRight); WriteCMD(CSRW); WriteDATA(0x00); WriteDATA(0x00); WriteCMD(MWRITE); for (i=0; i<1000; i++) { WriteDATA(0x20); // write " " to character memory } /* This procedure is used to test any button pushes. It checks which state the statemachine is currently in and then chooses the appropriate actions according to the button push. */ void butcheck(void) { if (eitherbut != 0) { //Only if either control 1 or 2 has had a button push if (state == menu) { //menu options screen if (eitherbut & 32) { //if down was pushed, move cursor down mainoptionselected++; if (mainoptionselected == 3) mainoptionselected=0; eraseball(); ballx = 112; bally = 50 + 16*mainoptionselected; drawball(); } if (eitherbut & 16) { //if up was pushed, move cursor up mainoptionselected--; if (mainoptionselected == -1) mainoptionselected=2; eraseball(); ballx = 112; bally = 50 + 16*mainoptionselected; drawball(); } if (eitherbut & 1) { //if button A was pushed if (mainoptionselected == 0) { //go to 1 player mode players = 1; state = play1; gamescreen(); } if (mainoptionselected == 1) { //go to 2 player mode players = 2; state = play2; gamescreen(); } if (mainoptionselected == 2) { //go to options screen state = option; options(); } } } if (state == option) { //options screen switch (eitherbut) { case 128: //if right was pushed, increase the current option selected by 1 unless option is at //maximum in which case decrease option to the minimum number. if (optionselected == 0) { speed+=1; if (speed == 11) speed = 1; textPos(6, 25); disInt(speed); } if (optionselected == 1) { size++; if (size == 6) size = 1; textPos(8, 25); disInt(size); } if (optionselected == 2) { winscore++; textPos(10, 25); disInt(winscore); } break; case 64: //if left was pushed, decrease the current option selected by 1 unless option is at //minimum in which case increase option to the maximum number. if (optionselected == 0) { speed-=1; if (speed == 0) speed = 10; textPos(6, 25); disInt(speed); } if (optionselected == 1) { size--; if (size == 0) size = 5; textPos(8, 25); disInt(size); } if (optionselected == 2) { winscore--; if (winscore == 0) winscore = 1; textPos(10, 25); disInt(winscore); } break; case 16: //if up is pushed, move cursor up 1, unless it's all the way up //in which case move cursor to the bottom option. optionselected--; if (optionselected == -1) optionselected=3; eraseball(); ballx = 70; bally = 50 + 16*optionselected; drawball(); break; case 32: //if down is pushed, move cursor down 1, unless it's all the way down //in which case move cursor to the top option. optionselected++; if (optionselected == 4) optionselected=0; eraseball(); ballx = 70; bally = 50 + 16*optionselected; drawball(); break; case 2: //if button b is pushed, return to the main menu. state = menu; optionselected = 0; clearLCD(); mainmenu(); break; case 1: //if button a is pushed and the cursor is on the default option //reset all the options to the initial settings. if (optionselected == 3) { speed = initspeed; size = initsize; winscore = initscore; textPos(6, 25); disInt(speed); textPos(8, 25); disInt(size); textPos(10, 25); disInt(winscore); } break; } } if (state == play1) { //1 player game mode if (eitherbut & 16) { //if up is pushed, move paddles 1 and 2 up 2 pixels unless it's already at the top paddle1 -= 2; if (paddle1 < 0) paddle1 = 0; paddle2 = paddle1; drawline(0, paddle1); drawline(1, paddle1); } if (eitherbut & 32) { //if down is pushed, move paddles 1 and 2 down 2 pixels unless it's already at //the bottom paddle1 += 2; if ((paddle1 + size * 8) > 127) paddle1 = 127 - size * 8; paddle2 = paddle1; drawline(0, paddle1); drawline(1, paddle1); } if (eitherbut & 8) { //if start is pushed, save current state of game and go to the pause screen. tstate = state; state = paused; tpaddle1 = paddle1; tpaddle2 = paddle2; tballx = ballx; tbally = bally; tdirx = dirx; tdiry = diry; pausescreen(); } } if (state == play2) { //2 player game mode switch (but) { case 16: //if up is pressed on control 1, move paddle1 up 2 pixels unless already at top of LCD paddle1 -= 2; if (paddle1 < 0) paddle1 = 0; drawline(0, paddle1); break; case 32: //if down is pressed on control 1, move paddle1 down 2 pixels unless already at bottom paddle1 += 2; if ((paddle1 + size * 8) > 127) paddle1 = 127 - size * 8; drawline(0, paddle1); break; } if (eitherbut & 8) { //if either controller presses start, save current game state, and go to pause screen. tstate = state; state = paused; tpaddle1 = paddle1; tpaddle2 = paddle2; tballx = ballx; tbally = bally; tdirx = dirx; tdiry = diry; pausescreen(); } } if (state == paused) { //paused state switch (eitherbut) { case 16: //if either control presses up, move cursor up 1 pauseoption--; if (pauseoption == -1) pauseoption=1; //used to see if cursor is on the top option eraseball(); ballx = 70; bally = 50 + 16*pauseoption; drawball(); break; case 32: //if either control presses down, move cursor down 1 pauseoption++; if (pauseoption == 2) pauseoption=0; //used to see if cursor is on the bottom option eraseball(); ballx = 70; bally = 50 + 16*pauseoption; drawball(); break; case 1: //if either control presses A if (pauseoption == 0) { //if the option is resume, then load up saved state, and continue game eraseball(); state = tstate; paddle1 = tpaddle1; paddle2 = tpaddle2; ballx = tballx; bally = tbally; dirx = tdirx; diry = tdiry; clearLCD(); drawline(0, tpaddle1); drawline(1, tpaddle2); drawball(); } if (pauseoption == 1) { //if the option is exit, then clear screen, and go to the menu clearLCD(); state = menu; mainmenu(); } break; } } } if (but2 != 0) { //check if button 2 is pressed if (state==play2) { //2 player game mode switch (but2) { case 16: //if control 2 presses up, move paddle2 up by 2 pixels unless already at top of LCD if ((paddle2-2)>=0) {eraseline(1,paddle2);} paddle2 -= 2; if (paddle2 < 0) paddle2 = 0; drawline(1, paddle2); break; case 32: //if control 2 presses down, move paddle2 down by 2 pixels unless already at bottom if ((paddle2+2)<=127) {eraseline(1,paddle2);} paddle2 += 2; if ((paddle2 + size * 8) > 127) paddle2 = 127 - size * 8; drawline(1, paddle2); break; } } } if (eitherbut && state == gamedone) {state = menu; clearText(); mainmenu();} //used to get out of gameover screen if (eitherbut && waitcont) {waitcont = 0; clearText();} //used to get out of 'push any button' screen } //The main procedure just has an endless while loop which will call button checking function and the //ball moving and checking function at the appropriate times which are given by flags set by timer0 int. void main(void) { initialize(); //initialize all the proper variables mainmenu(); //start with the menu screen while(1) { random++; //generate some random number if (butready == 1) { //call button check function if button is ready to be checked butcheck(); butready = 0; } if ((ballmove == 1) && ((state == play1) || (state == play2))) { //move and check ball ball = 0; ballmove = 0; game(); } } } //This procedure will draw out the main menu screen on to the LCD. void mainmenu(void) { tpaddle1 = tpaddle2 = 45; score1 = 0; score2 = 0; textPos(2, 14); wordWrite('P','O','N','G'); textPos(6,15); wordWrite('1',' ','P','l'); wordWrite('a','y','e','r'); wordWrite(' ','G','a','m'); letterWrite('e'); textPos(8,15); wordWrite('2',' ','P','l'); wordWrite('a','y','e','r'); wordWrite(' ','G','a','m'); letterWrite('e'); textPos(10,15); wordWrite('O','p','t','i'); wordWrite('o','n','s',' '); eraseball(); ballx = 112; bally = 50 + 16*mainoptionselected; drawball(); } //This procecure is used to display a variable onto the screen. void disInt(char num) { char temp[7]; temp[0] = 0; temp[1] = 0; temp[2] = 0; temp[3] = 0; temp[4] = 0; itoa(num, temp); WriteCMD(MWRITE); WriteDATA(temp[0]); WriteDATA(temp[1]); WriteDATA(temp[2]); WriteDATA(temp[3]); WriteDATA(temp[4]); } //This procedure is used to draw the options menu onto the LCD. void options(void) { /* Display Options Ball speed 1 option 0 Paddle size 3 option 1 Winning score 10 option 2 Reset defaults option 3 */ clearLCD(); textPos(2, 12); wordWrite('O','P','T','I'); wordWrite('O', 'N', 'S', ' '); textPos(6, 10); wordWrite('B','a','l','l'); wordWrite(' ','S','p','e'); wordWrite('e','d',' ',' '); textPos(6, 25); disInt(speed); textPos(8,10); wordWrite('P','a','d','d'); wordWrite('l','e',' ','S'); wordWrite('i','z','e',' '); textPos(8, 25); disInt(size); textPos(10,10); wordWrite('W','i','n','n'); wordWrite('i','n','g',' '); wordWrite('S','c','o','r'); letterWrite('e'); textPos(10, 25); disInt(winscore); textPos(12,10); wordWrite('R','e','s','e'); wordWrite('t',' ','D','e'); wordWrite('f','a','u','l'); letterWrite('t');letterWrite('s'); ballx = 70; bally = 50 + 16*optionselected; drawball(); } //This procedure will draw out the initial game screen onto the screen. //It will also choose a random spot for where the ball will initially start. void gamescreen(void) { clearLCD(); // if (players == 1) display (One Player Game) // if (players == 2) display (Two Player Game) // display (Player 1 press Start to begin) ballx = (xmax - 1) * (random & 1); bally = (ymax - 1) * (random & 1); if (ballx == 0) dirx = 1; //0 - left, 1 - right else dirx = 0; if (bally == 0) diry = 1; //0 - down, 1 - up else diry = 0; paddle1 = tpaddle1; paddle2 = tpaddle2; drawline(0, paddle1); drawline(1, paddle2); drawball(); waitcont = 0; TCCR0 = 4; speedx = speed; speedy = speed; //press any button to continue } /* This procedure will figure whether the ball has hit a paddle if the ball is going off the screen. If there is no paddle in the way of the ball, then according to the game, the appropriate scoring will take place. If the ball is not going off the screen, then the next coordinates of the ball will be figured out and then the new ball will be drawn onto the screen. */ void game(void) { if (waitcont) { textPos(9, 2); wordWrite('P','r','e','s'); wordWrite('s',' ','a','n'); wordWrite('y',' ','b','u'); wordWrite('t','t','o','n'); wordWrite(' ','t','o',' '); wordWrite('c','o','n','t'); wordWrite('i','n','u','e'); textPos(16,0); return; } oldballx = ballx; oldbally = bally; if ((showscore == 0) | (players == 1)) { if (ballx <= (speedx) && dirx == 0) { //Checks if ball is going off the left side of the screen if ((paddle1 <= bally) && (paddle1 + 8 * size) >= bally) { //Checks if paddle1 is in the way beep = 2; //beep if there is a paddle hit dirx = 1; //change direction of the ball if (players == 1) {score1++; showscore = 10;} //increase score if in 1 player mode, display score if (score1 == winscore) state = gamedone; //end game if winscore has been reached in 1 players } else { if (players == 1) state = gamedone; //end game if in 1 player mode else { dirx = 1; //change direction of ball score2++; //increase score for player 2 showscore = 10; //set up screen so score is showing if (score2 == winscore) state = gamedone; //end game if winscore has been reached in 2 players } } } if (ballx >= (xmax - speedx) && dirx == 1) { //Checks if ball is going off the right side of the screen if ((paddle2 <= bally) && (paddle2 + 8 * size) >= bally) { //checks if paddle2 is in the way beep = 2; //beep if there is a paddle hit dirx = 0; //change direction if (players == 1) { score1++; showscore = 10;} //increase score if in 1 player mode, display score if (score1 == winscore) state = gamedone; //end game if winscore has been reached in 1 players } else { if (players == 1) state = gamedone; //end game if in 1 players else { dirx = 0; //change direction showscore = 10; //set up screen so score is showing score1++; //increase score for player 1 if (score1 == winscore) state = gamedone; //end game if winscore has been reached in 2 players } } } } //These next 2 if statements are used to calculate the next x coordinate of the ball if (ballx > (speedx) && dirx == 0) ballx = ballx - speed; //- (speed * ((random & 7) + 1) / 80); if (ballx < (xmax - speedx) && dirx == 1) ballx = ballx + speed; // + (speed * ((random & 7) + 1) / 80); //This if statement are used to calculate the y component of the speed of the ball if (bally < (speedy + 1) && diry == 0) { diry = 1; if (speedy == speed && (random & 1)) speedy+=1; if (speedy == (speed + 1) && !(random & 1)) speedy-=1; } //This if statement is to see if the ball has hit the sides of the screen if (bally > (ymax - speedy - 1) && diry == 1){ diry = 0; } //These next 2 if statements calculate the next y coordinate of the ball if (bally >= (speedy + 1) && diry == 0) bally = bally - speedy; //- (speed * ((random & 7) + 1) / 80); if (bally <= (ymax - speedy - 1) && diry == 1) bally = bally + speedy; //+ (speed * ((random & 7) + 1) / 80); if ((showscore == 0) | (players == 1)) drawball(); //only draws the ball if the ball is still in play newballx = ballx; newbally = bally; ballx = oldballx; bally = oldbally; if ((showscore == 0) | (players == 1)) eraseball(); //only erases the ball if the ball is still in play drawline(0, paddle1); //draw paddle1 drawline(1, paddle2); //draw paddle2 ballx = newballx; bally = newbally; beep--; if (beep == -1) beep = 0; if ((--showscore == 0) & (players==2)) { //stop showing the score, and show 'hit any button' screen waitcont=1; gamescreen(); } if (showscore == -1) showscore = 0; if (beep) { //If there's a paddle hit, turn on timer 1 to give sound TCNT1=0; TCCR1B = 9; //start timer 1 } else {TCCR1B=0; PORTB.5 = 0;} //turn off timer 1 if (showscore) { //Show the score of the current game for any game mode if (state == gamedone) clearLCD(); textPos(0, 2); wordWrite('P', 'l', 'a', 'y'); wordWrite('e', 'r', ' ', '1'); letterWrite(':'); letterWrite(' '); disInt(score1); if (players == 2) { //show 2nd player score if in 2 player game mode textPos(0, 20); wordWrite('P', 'l', 'a', 'y'); wordWrite('e', 'r', ' ', '2'); letterWrite(':'); letterWrite(' '); disInt(score2); } textPos(16,0); } else { clearText(); } if (state == gamedone) {TCCR1B=0; PORTB.5 = 0; donescreen();} //turn off timer1 and go to game over screen } //This procedure draws out the the game over screen onto the LCD. void donescreen(void) { clearLCD(); textPos(2, 12); wordWrite('G','A','M','E'); wordWrite(' ', 'O', 'V', 'E'); letterWrite('R'); if (players == 1) { if (score1 == winscore) { textPos(6,13); wordWrite('Y', 'o', 'u', ' '); wordWrite('W', 'i', 'n', '!'); } else { textPos(6,13); wordWrite('Y','o','u',' '); wordWrite('L','o','s','t'); textPos(7,7); wordWrite('P','l','e','a'); wordWrite('s','e',' ','T'); wordWrite('r','y',' ','A'); wordWrite('g','a','i','n'); wordWrite('.','.','.',' '); } } if (players == 2) { textPos(6, 5); wordWrite(' ', 'P','l','a'); wordWrite('y', 'e','r',' '); if (score1 == winscore) letterWrite('1'); else letterWrite('2'); letterWrite(' '); wordWrite('i','s',' ','t'); wordWrite('h','e',' ','W'); wordWrite('i','n','n','e'); letterWrite('r'); letterWrite('!'); } /* Press any button to return to the Main Menu */ textPos(9, 3); wordWrite('P','r','e','s'); wordWrite('s',' ','a','n'); wordWrite('y',' ','b','u'); wordWrite('t','t','o','n'); wordWrite(' ','t','o',' '); textPos(10, 3); wordWrite('r','e','t','u'); wordWrite('r','n',' ','t'); wordWrite('o',' ','t','h'); wordWrite('e',' ','M','a'); wordWrite('i','n',' ','M'); wordWrite('e','n','u','.'); textPos(16,0); delay_ms(500); } //This procedure draws out the pause screen onto the LCD. void pausescreen(void) { textPos(2, 12); wordWrite('G','A','M','E'); wordWrite(' ', 'P', 'A', 'U'); wordWrite('S','E','D',' '); textPos(6, 10); wordWrite('R','e','s','u'); wordWrite('m','e',' ',' '); textPos(8,10); wordWrite('E','x','i','t'); ballx = 70; bally = 50 + 16*pauseoption; drawball(); } //This function draws the ball according to the current ball coordinates (ballx,bally). void drawball() { int bx, by, ball4; bx = ballx; by = bally; ball4 = (bx >> 2) & 1; pos = bx >> 3; pos += (by - 1) * 40; pos = pos + GraphicsAddress; WriteCMD(CSRRight); pos_lo = pos; pos_hi = pos >> 8; WriteCMD(CSRW); WriteDATA(pos_lo); WriteDATA(pos_hi); WriteCMD(MWRITE); if (ball4) WriteDATA(0b00000110); else WriteDATA(0b01100000); for (i=0; i<2; i++) { pos +=40; pos_lo = pos; pos_hi = pos >> 8; WriteCMD(CSRW); WriteDATA(pos_lo); WriteDATA(pos_hi); WriteCMD(MWRITE); if (ball4) WriteDATA(0b00001111); else WriteDATA(0b11110000); } pos += 40; pos_lo = pos; pos_hi = pos >> 8; WriteCMD(CSRW); WriteDATA(pos_lo); WriteDATA(pos_hi); WriteCMD(MWRITE); if (ball4) WriteDATA(0b00000110); else WriteDATA(0b01100000); } //This function erases the ball according to the current coordinates of the ball. void eraseball() { int bx, by; bx = ballx; by = bally; pos = bx >> 3; pos += (by - 1) * 40; pos = pos + GraphicsAddress; for (i=0; i<4; i++) { WriteCMD(CSRRight); pos_lo = pos; pos_hi = pos >> 8; WriteCMD(CSRW); WriteDATA(pos_lo); WriteDATA(pos_hi); WriteCMD(MWRITE); WriteDATA(0b00000000); pos += 40; } } //This function draws a paddle according to which paddle it is, and the size of the paddle and where the top of the //paddle is currently. void drawline(int side, int top) { int ln; if (side==0) pos = 0; else pos = 31; pos += (top-2) * 40; pos = pos + GraphicsAddress; //add GraphicsAddreess offset WriteCMD(CSRRight); for (ln=0; ln < 2; ln++) { pos_lo = pos; //lo byte pos_hi = pos >> 8; //hi byte WriteCMD(CSRW); WriteDATA(pos_lo); WriteDATA(pos_hi); WriteCMD(MWRITE); WriteDATA(0b00000000); pos += 40; } for (ln=0; ln < size*8; ln++) { pos_lo = pos; //lo byte pos_hi = pos >> 8; //hi byte WriteCMD(CSRW); WriteDATA(pos_lo); WriteDATA(pos_hi); WriteCMD(MWRITE); if (side == 0) WriteDATA(0b11100000); else WriteDATA(0b00000111); pos = pos+40; } for (ln=0; ln < 2; ln++) { pos_lo = pos; //lo byte pos_hi = pos >> 8; //hi byte WriteCMD(CSRW); WriteDATA(pos_lo); WriteDATA(pos_hi); WriteCMD(MWRITE); WriteDATA(0b00000000); pos += 40; } } //This function will erase a paddle according to which paddle it is and the size and where the top of the paddle //is located. void eraseline(int side, int top) { int ln; if (side==0) pos = 0; else pos = 31; pos += top * 40; pos = pos + GraphicsAddress; //add GraphicsAddreess offset WriteCMD(CSRRight); pos_lo = pos; //lo byte pos_hi = pos >> 8; //hi byte WriteCMD(CSRW); WriteDATA(pos_lo); WriteDATA(pos_hi); WriteCMD(MWRITE); WriteDATA(0b00000000); pos += 40; for (ln=0; ln < size*8; ln++) { pos_lo = pos; //lo byte pos_hi = pos >> 8; //hi byte WriteCMD(CSRW); WriteDATA(pos_lo); WriteDATA(pos_hi); WriteCMD(MWRITE); if (side == 0) WriteDATA(0b00000000); else WriteDATA(0b00000000); pos = pos+40; } WriteCMD(MWRITE); WriteDATA(0b00000000); } //This function will set up a cursor to write text according to the row and column that is given. void textPos(int row, int col) { int loc; unsigned char loc_lo, loc_hi; loc = col + 40*row; loc_lo = loc; loc_hi = loc>>8; WriteCMD(CSRRight); WriteCMD(CSRW); WriteDATA(loc_lo); WriteDATA(loc_hi); } //This function will write a letter to the LCD. void letterWrite(char letter) { WriteCMD(MWRITE); WriteDATA(letter); } //This function will write 4 letters to the LCD. void wordWrite(char let1, char let2, char let3, char let4) { letterWrite(let1); letterWrite(let2); letterWrite(let3); letterWrite(let4); } void initialize(void) { DDRA=0x00; // PORT A - controller input DDRB=0xff; // PORT B - controller output DDRD=0xff; // PORT D - LCD DDRC=0xff; // PORT C - LCD PORTD=0; //set up timer 0 TCNT0=256-62; TIMSK=2; //turn on timer 0 overflow ISR TCCR0=4; //prescalar to 64 TIMSK=TIMSK | 0x40; //turn on timer 1 compare match interrupt TCCR1B = 0; //disable timer 1 until song starts TCNT1 = 0; //and zero the timer OCR1A=7648/2; //and load the correct time out for timer 1 str = clkon = clkcnt = 0; players = 1; score1 = 0; score2 = 0; speed = initspeed; speedx = speedy = speed; size = initsize; winscore = initscore; ballx = 0; bally = 0; dirx = 0; diry = 0; paddle1 = 0; paddle2 = 0; mainoptionselected = 0; pauseoption = optionselected = 0; gamestate = 0; random = 0; but = but2 = oldbut = oldbut2 = butbak = butbak2 = butready = eitherbut = 0; nint = nint2 = ball = ballmove = 0; tballx = tbally = tdirx = tdiry = 0; tpaddle1 = 45; tpaddle2 = 45; //These next lines will initialize the LCD screen for proper use PORTC = LCDnop; PORTC = LCDreset; PORTC = LCDnop; WriteCMD(SystemSet); WriteDATA(0x30); WriteDATA(0x87); WriteDATA(0x07); WriteDATA(0x27); WriteDATA(0x2F); WriteDATA(0xC7); WriteDATA(0x28); WriteDATA(0x00); WriteCMD(Overlay); WriteDATA(0x00); WriteCMD(Scroll); WriteDATA(0x00); WriteDATA(0x00); WriteDATA(0xC8); WriteDATA(0xE8); WriteDATA(0x03); WriteDATA(0xC8); WriteCMD(CSRForm); WriteDATA(0x04); WriteDATA(0x86); WriteCMD(CSRRight); WriteCMD(HorzScroll); WriteDATA(0x00); WriteCMD(DispON); WriteDATA(0x16); clearLCD(); state = tstate = menu; //crank up the ISRs #asm sei #endasm }