/* SIMON!! */ // Jorel Luyando - 391959 // Senaida San Miguel - 392059 #asm .equ __lcd_port=0x15 ;port c #endasm #include lcd.h // LCD driver routines #include 90s8515.h #include Stdio.h #include delay.h #define prescale1 1 #define clear_on_match 8 #define OffT 2000 #define OnT 2000 #define userOnT 1000 #define LCDwidth 16 //number of characters across length of LCD #define mask 0b00011000 //mask for random number generator #define t1 50 //task 1 timeout value #define t2 50 //task 2 timeout value // state, mode, level, and color variables enum gameStates {ModeStart, ModeSelect, LevelStart, LevelSelect, Playback, ButtonPress, Check, EndGame, RoundCheck, GameCont} gameState; enum debounceStates {Released, MaybePressed, ButtonPressed, Pressed, MaybeReleased} debounceState; enum modes {Simon, FFA} mode; enum levels {easy, medium, hard} level; enum colors {red, blue, yellow, green, grey} color; //various variables for FSM and button debounce unsigned char noteArray[99]; unsigned char reload, time1, time2; unsigned char index, round, userNoteCount, noteCount; unsigned char OffTimer, OnTimer, userOnTimer, timertemp; unsigned char butnum, maybe; unsigned char num, gameLength, speedup; //flags needed unsigned char bttnpressFlag, playbackFlag, userplaybackFlag, startFlag, selectFlag; char lcd_buffer[17]; // LCD display buffer flash int noteTable[8]={15267/2, 12121/2, 10204/2, 8097/2, 30534/2, 3824/2, 2000/2, 9090/2}; // must have first 4 values be red, blue, yellow, and green note values //********************************************************** /* Use an 1x16 alphanumeric LCD connected to PORTA as follows: [LCD pin] [8515] 1 GND - GND 2 +5V - Vcc 3 VLC 10k trimpot wiper (trimpot ends go to +Vcc and GND) 4 RS - PA0 5 RD - PA1 6 EN - PA2 11 D4 - PA4 12 D5 - PA5 13 D6 - PA6 14 D7 - PA7 */ //********************************************************** void soundOn(void); //turn speaker on void soundOff(void); //turn speaker off void ledsOn(void); //turn specified color leds on void ledsOff(void); //turn all leds off void wingame(void); //game is won, blink "win" light/sound pattern void wrong(void); //game is lost, blink "lose" light/sound pattern void modeLCD(void); //initializes LCD to display mode void levelLCD(void); //initializes LCD to display level void gameLCD(void); //initializes LCD to display game info void updateLCD(void); //updates the number of rounds the user has won on LCD void endgameLCD(void); //display losing msg, mode, level, rounds to user void wingameLCD(void); //display winning msg, mode, level, rounds to user void toggleMode(void); //toggles mode and updates LCD when select is pressed void toggleLevel(void); //toggles level and updates LCD when select is pressed void init(void); //initializes needed game variables void randNote(void); //creates random note, inc(noteCount), stores note in noteArray void playback(void); //runs through noteArray, turning on sound and led for a period of time void userPush(void); //inc(userNoteCount), turns on sound and led of button pressed void initialize(void); //initialize ports and timers void task1(void); //FSM void task2(void); //debounce buttons //********************************************************** //timer 0 overflow ISR interrupt [TIM0_OVF] void timer0_overflow(void) { //reload to force 1 mSec overflow TCNT0=reload; //num is running for the randnum generator num++; //Decrement the three times if they are not already zero if (time1>0) --time1; //task1 timer if (time2>0) --time2; //task2 timer if (OnTimer>0) --OnTimer; //time that LED/sound is on for playback if (OffTimer>0) --OffTimer; //time that LED/sound is off for playback if (userOnTimer>0) --userOnTimer; //time that LED/sound is on for user } //********************************************************** //timer 1 compare-match A ISR interrupt [TIM1_COMPA] void cmpA_overflow(void) { PORTA = ~PORTA ; //toggle the port to make a sound } //********************************************************** void init(void) { //initialize needed game variables noteCount = 0; userNoteCount = 0; index = 0; round = 0; bttnpressFlag = 0; playbackFlag = 0; userplaybackFlag=0; startFlag = 0; selectFlag = 0; gameLength = 99; num = 0; color = grey; mode = Simon; level = easy; gameState = ModeStart; debounceState = Released; OnTimer = 0; OffTimer = 0; userOnTimer = 0; timertemp = OnT; modeLCD(); } //------------------------------------------------------------ void soundOn(void) { //zero the T1 counter TCNT1 = 0; //begin timer TCCR1B = prescale1 + clear_on_match; } void soundOff(void) { //turn off timer TCCR1B = 0; } void ledsOn(void) { if (color == red) //light up red PORTB = 0x01; else if (color == blue) //light up blue PORTB = 0x02; else if (color == yellow) //light up yellow PORTB = 0x04; else if (color == green) //light up green PORTB = 0x08; } void ledsOff(void) { //turn off all leds PORTB = 0x00; } //------------------------------------------------------------ void wrong(void) { //turn all the leds on PORTB = 0xff; //load the "wrong" note into OCR1A OCR1A = noteTable[4]; //turn speaker "on" - turn on T1 soundOn(); //keep sound on a little longer delay_ms(300); } void wingame(void) { //flash lights and play tune //red PORTB = 0x01; OCR1A = noteTable[0]; soundOn(); //turn sound on delay_ms(200); //hold sound out //blue PORTB = 0x02; OCR1A = noteTable[1]; delay_ms(200); //hold sound/LED out //yellow PORTB = 0x04; OCR1A = noteTable[2]; delay_ms(200); //hold sound/LED out //green PORTB = 0x08; OCR1A = noteTable[3]; delay_ms(200); //hold sound/LED out soundOff(); //turn sound off PORTB = 0x00; //turn LEDS off } //------------------------------------------------------------ void modeLCD(void) { //clear the display lcd_clear(); //display current mode to user lcd_gotoxy(0,0); lcd_putsf("Simon FFA " ); lcd_gotoxy(0,1); lcd_putsf(" ^ "); } void levelLCD(void) { //clear the display lcd_clear(); //display current level to user lcd_gotoxy(0,0); lcd_putsf("Easy Med Hard " ); lcd_gotoxy(0,1); lcd_putsf(" ^ "); } void toggleMode(void) { //toggle modes if (mode == Simon) mode = FFA; else mode = Simon; //display new mode lcd_gotoxy(0,1); if (mode==Simon) lcd_putsf(" ^ "); else lcd_putsf(" ^ "); //load start/select "beep" OCR1A = noteTable[6]; soundOn(); } void toggleLevel(void) { //toggle levels if (level == easy) level = medium; else if (level == medium) level = hard; else if (level == hard) level = easy; //display new level lcd_gotoxy(0,1); if (level == easy) lcd_putsf(" ^ "); else if (level == medium) lcd_putsf(" ^ "); else lcd_putsf(" ^ "); //load start/select "beep" OCR1A = noteTable[6]; soundOn(); } //------------------------------------------------------------ void gameLCD(void) { //clear the display lcd_clear(); //display mode to user lcd_gotoxy(0,0); if (mode == Simon) lcd_putsf("Simon "); else lcd_putsf("FFA "); //display level to user if (level == easy) lcd_putsf("Easy"); else if (level == medium) lcd_putsf("Med"); else lcd_putsf("Hard"); //display rounds won lcd_gotoxy(0,1); lcd_putsf("Rounds: 0 "); } void updateLCD(void) { //display current rounds won lcd_gotoxy(0,1); sprintf(lcd_buffer, "Rounds: %-i", round); lcd_puts(lcd_buffer); } void endgameLCD(void) { //initialize the display lcd_init(LCDwidth); lcd_clear(); //display losing message and current round lcd_gotoxy(0,0); sprintf(lcd_buffer, "Loser! %-i rounds", round); lcd_puts(lcd_buffer); //display mode lcd_gotoxy(0,1); lcd_putsf("on "); if (mode == Simon) lcd_putsf("Simon "); else lcd_putsf("FFA "); //display level if (level == easy) lcd_putsf("Easy"); else if (level == medium) lcd_putsf("Med"); else lcd_putsf("Hard"); } void wingameLCD(void) { //clear display lcd_clear(); //display winning message and rounds won lcd_gotoxy(0,0); sprintf(lcd_buffer, "Winner %-i rounds", round); lcd_puts(lcd_buffer); //display mode lcd_gotoxy(0,1); lcd_putsf("on "); if (mode == Simon) lcd_putsf("Simon "); else lcd_putsf("FFA "); //display level if (level == easy) lcd_putsf("Easy"); else if (level == medium) lcd_putsf("Med"); else lcd_putsf("Hard"); } //------------------------------------------------------------ void randNote(void) { //variables used in randNote() unsigned char newColor; unsigned char randnum; //generate a random number randnum = num & mask; //create a new color by using random number if (randnum == 0x00) newColor = red; else if (randnum == 0x08) newColor = blue; else if (randnum == 0x10) newColor = yellow; else if (randnum == 0x18) newColor = green; //append new color to end of sequence noteCount++; noteArray[noteCount-1] = newColor; } void playback(void) { //load the current color's note value into OCR1A color = noteArray[index]; OCR1A = noteTable[color]; index++; //speed up in FFA-medium and FFA-hard levels only if (mode == FFA) { if (level == medium) { //speed up every 5 rounds if (round%5 == 0) timertemp = timertemp - speedup; } else if (level == hard) { //speed up every 3 rounds if (round%3 == 0) timertemp = timertemp - speedup; } } //note/LED is on for the amount of time in timertemp OnTimer = timertemp; soundOn(); //turn on sound ledsOn(); //turn on LED } void userPush(void) { //set flag low bttnpressFlag = 0; //load current color pressed into OCR1A OCR1A = noteTable[color]; //user's current note count incremented userNoteCount++; //hold sound/LED on for period of time userOnTimer = userOnT; soundOn(); //turn sound on ledsOn(); //turn LED on } //********************************************************** // TASK 1 - FSM for Simon game void task1(void) { time1 = t1; //turn off start/select "beep" if ((playbackFlag==0)&&(userplaybackFlag==0) ) { soundOff(); ledsOff(); } // Run FSM for Simon switch(gameState) { case ModeStart: if (startFlag == 1) { //init LCD to level levelLCD(); gameState = LevelStart; startFlag = 0; //play start/select "beep" OCR1A = noteTable[6]; soundOn(); } else gameState = ModeSelect; break; case ModeSelect: if (selectFlag == 1) { //toggle mode and update LCD toggleMode(); gameState = ModeSelect; selectFlag = 0; } else gameState = ModeStart; break; case LevelStart: if (startFlag == 1) { //play start/select "beep" OCR1A = noteTable[6]; soundOn(); //init length of game and speed up if (mode==FFA) { //game is practically infinite gameLength = 99; //easy has no speedup if ( (level == medium)||(level == hard) ) speedup = 2; } else // in Simon mode - no speed up at all { // speed up is initialized in init() to OnT if (level == easy) gameLength = 7; else if (level == medium) gameLength = 15; else gameLength = 31; //hard is 31 rounds } randNote(); //create new random note gameLCD(); //get LCD ready for game gameState = Playback; //go to Playback state startFlag = 0; delay_ms(100); soundOff(); //turn off sound delay_ms(700); //let user get ready for game } else gameState = LevelSelect; break; case LevelSelect: if (selectFlag == 1) { //toggle level and display toggleLevel(); gameState = LevelSelect; selectFlag = 0; } else gameState = LevelStart; break; case Playback: if (playbackFlag == 0) //ready to play notes { //cycle through sequence if (index < noteCount) { playbackFlag = 1; //we're going into playback mode now playback(); //play note in noteArray gameState = Playback; } else gameState = ButtonPress; //played all the notes, wait for user button press } //else do nothing - have to wait for end of playback mode break; case ButtonPress: if (userplaybackFlag ==0) //ready to check if user pressed anything { if (bttnpressFlag == 1) //user pressed a colored button { userPush(); //play note/color that user pressed userplaybackFlag =1; //go into userplayback mode gameState = ButtonPress; bttnpressFlag = 0; //this line is set after userOnTimer has run out in the "main" function //gameState = Check; //check if the button pressed is correct } } else gameState = ButtonPress; //wait for user button press break; case Check: if (color == noteArray[userNoteCount - 1]) gameState = GameCont; else { //game is over, user pressed wrong button wrong(); endgameLCD(); gameState = EndGame; } break; case EndGame: if (startFlag == 1) { init(); //reinitialize game vars for next game modeLCD(); //reinitialize LCD gameState = ModeStart; //begin new game startFlag = 0; } else gameState = EndGame; //wait for user to press start break; case RoundCheck: if (round < gameLength) { //user entered in the correct sequence gameState = Playback; randNote(); //create new note index = 0; //reinitialize for new round userNoteCount = 0; //reinitialize for new round updateLCD(); //update rounds won ledsOff(); soundOff(); delay_ms(800); //let user get ready for next round } else { //user won game //blink winning lights, play winning sounds, update winning msg on LCD wingame(); wingameLCD(); gameState = EndGame; } break; case GameCont: if (userNoteCount < noteCount) gameState = ButtonPress; //wait for user to enter in the next color else { round++; //user just won the round gameState = RoundCheck; } break; } // End FSM }// end task 1 //------------------------------------------------------------ // TASK 2 void task2(void) { time2 = t2; //get butnum from PIND butnum = PIND; switch(debounceState) { case Released: if (butnum == 0) debounceState = Released; else { maybe = butnum; debounceState = MaybePressed; } break; case MaybePressed: if (butnum == maybe) debounceState = ButtonPressed; else debounceState = Released; break; case ButtonPressed: if (butnum == 0x01) { color = red; bttnpressFlag =1; } else if (butnum == 0x02) { color = blue; bttnpressFlag =1; } else if (butnum == 0x04) { color = yellow; bttnpressFlag =1; } else if (butnum == 0x08) { color = green; bttnpressFlag =1; } else if (butnum == 0x80) startFlag = 1; else if (butnum == 0x40) selectFlag = 1; debounceState = Pressed; break; case Pressed: if (butnum == maybe) debounceState = Pressed; else debounceState = MaybeReleased; break; case MaybeReleased: if (butnum==maybe) debounceState = Pressed; else debounceState = Released; break; } //end debounce }// end task 2 //********************************************************** void main(void) { initialize(); init(); while(1) { if (time1==0) task1(); //FSM if (time2==0) task2(); //debounce button //check if we're still in playback mode if (playbackFlag == 1) { if (OnTimer ==1) //catch it right before it zeros out { soundOff(); //turn off sound ledsOff(); //turn off LED OffTimer = timertemp; //set "off time" } //check if out of playback mode if (OffTimer == 1) playbackFlag = 0; } else { //check if we're in user playback if (userplaybackFlag==1) { if (userOnTimer ==1) { ledsOff(); //turn off LED soundOff(); //turn off sound userplaybackFlag =0; //out of userplayback mode gameState = Check; //check if color entered is correct } } } } //end while } //end main //********************************************************** //Set it all up void initialize(void) { //set up the ports DDRD=0x00; // PORT D is an input for buttons // PORT C is an ouput for lcd DDRB=0xff; // PORT B is an output for leds DDRA=0xff; // PORT A is an output for speaker PORTA=0; PORTB=0x00; //all LEDs off //set up timer 0 //62.5 x (64x.25) microSec = 1.0 mSec, so prescale 64, and count 62 times. reload=256-125; //value for 1 Msec TCNT0=reload; //preload timer 1 so that is interrupts after 1 mSec. TCCR0=3; //prescalar to 64 TIMSK=2; //turn on timer 0 overflow ISR //set up timer 1 TIMSK=TIMSK | 0x40; //turn on timer 1 compare match interrupt TCCR1B = 0; //disable timer 1 TCNT1 = 0; //zero the timer //init the task timers time1=t1; time2=t2; //initialize and clear the display lcd_init(LCDwidth); lcd_clear(); //crank up the ISRs #asm sei #endasm }
|